From 924769890737366a1337e1f32558f12b2c70b7d8 Mon Sep 17 00:00:00 2001 From: Felix Kaechele Date: Sat, 11 Mar 2023 22:39:12 -0500 Subject: [PATCH] feat: correct parsers and tests based on new info Further studying the ProFlame 2 controller I was able to identify what some of these other bits do. Adding that to the functions and tests. Signed-off-by: Felix Kaechele --- src/bonaparte/device.py | 4 ++-- src/bonaparte/fireplace.py | 23 +++++++++++++++-------- src/bonaparte/parser.py | 13 +++++++------ tests/mock_messages.py | 5 +++-- tests/test_misc.py | 2 ++ tests/test_parsers.py | 23 +++++++++++++++++------ 6 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/bonaparte/device.py b/src/bonaparte/device.py index 35af23a..7d2b91e 100644 --- a/src/bonaparte/device.py +++ b/src/bonaparte/device.py @@ -271,7 +271,7 @@ async def _notification_handler( _LOGGER.debug( "%s: Receiving response via notify: %s (expected=%s)", self.name, - message.hex(), + message.hex(" "), bool(self._notify_future), ) @@ -336,7 +336,7 @@ async def _execute( _LOGGER.debug( "%s: Sending message %s", self.name, - message.hex(), + message.hex(" "), ) if self._write_lock.locked(): _LOGGER.debug( diff --git a/src/bonaparte/fireplace.py b/src/bonaparte/fireplace.py index 40310c4..4b114c1 100644 --- a/src/bonaparte/fireplace.py +++ b/src/bonaparte/fireplace.py @@ -98,6 +98,7 @@ class FireplaceState: power: bool = False remote_in_use: bool = False split_flow: bool = False + thermostat: bool = False time_left: tuple[int, int, int] = (0, 0, 0) timer: bool = False mcu_version: str = "" @@ -187,9 +188,10 @@ async def _ifc_cmd1(self) -> bool: payload = bytearray( [ 0x0, - self._state.main_mode << 1 + self._state.power + | (self._state.thermostat << 1) | (self._state.night_light_brightness << 4) - | self._state.pilot << 7, + | (self._state.pilot << 7), ] ) result = await self._simple_command(EfireCommand.SET_IFC_CMD1, payload) @@ -234,9 +236,13 @@ async def power(self, *, on: bool) -> bool: ) self._state.power = result - if not on: + if on: + await self._ifc_cmd1() + else: self._state.blower_speed = 0 self._state.flame_height = 0 + await self._ifc_cmd1() + await self._ifc_cmd2() return result @needs_auth @@ -436,9 +442,10 @@ async def update_ifc_cmd1_state(self) -> None: msg = f"Command failed with return code {result.hex()}" raise CommandFailedException(msg) ( - self._state.pilot, + _, # power state is handled separately for eFIRE + self._state.thermostat, # thermostat is not used with eFIRE self._state.night_light_brightness, - self._state.main_mode, + self._state.pilot, ) = parse_ifc_cmd1_state(result) # E4 @@ -447,10 +454,10 @@ async def update_ifc_cmd2_state(self) -> None: """Update the state of the IFC CMD1 functions.""" result = await self.execute_command(EfireCommand.GET_IFC_CMD2_STATE) ( - self._state.split_flow, - self._state.aux, - self._state.blower_speed, self._state.flame_height, + self._state.blower_speed, + self._state.aux, + self._state.split_flow, ) = parse_ifc_cmd2_state(result) # E6 diff --git a/src/bonaparte/parser.py b/src/bonaparte/parser.py index dfac14d..7c20b0e 100644 --- a/src/bonaparte/parser.py +++ b/src/bonaparte/parser.py @@ -14,21 +14,22 @@ def parse_mcu_version(payload: bytes | bytearray) -> str: return f"{payload[0]}.{payload[1]}{payload[2]}" -def parse_ifc_cmd1_state(payload: bytes | bytearray) -> tuple[bool, int, int]: +def parse_ifc_cmd1_state(payload: bytes | bytearray) -> tuple[bool, bool, int, bool]: """Parse the fireplace state from an IFC CMD1 response.""" pilot = bool((payload[1] >> 7) & 1) night_light = (payload[1] >> 4) & 7 - main_mode = payload[1] & 2 - return pilot, night_light, main_mode + thermostat = bool((payload[1] >> 1) & 2) + power = bool(payload[1] & 1) + return power, thermostat, night_light, pilot -def parse_ifc_cmd2_state(payload: bytes | bytearray) -> tuple[bool, bool, int, int]: +def parse_ifc_cmd2_state(payload: bytes | bytearray) -> tuple[int, int, bool, bool]: """Parse the fireplace state from an IFC CMD2 response.""" split_flow = bool((payload[1] >> 7) & 1) - aux = bool((payload[1] >> 3) & 1) blower_speed = (payload[1] >> 4) & 7 + aux = bool((payload[1] >> 3) & 1) flame_height = payload[1] & 7 - return split_flow, aux, blower_speed, flame_height + return flame_height, blower_speed, aux, split_flow def parse_timer(payload: bytes | bytearray) -> tuple[tuple[int, int, int], bool]: diff --git a/tests/mock_messages.py b/tests/mock_messages.py index 3854bd3..d6e6cff 100644 --- a/tests/mock_messages.py +++ b/tests/mock_messages.py @@ -11,8 +11,9 @@ "mcu_version": bytes.fromhex("ab bb 06 f3 01 01 04 f1 55"), "timer_off": bytes.fromhex("ab bb 07 e6 00 00 00 00 e1 55"), "timer_201455_on": bytes.fromhex("ab bb 07 e6 14 0e 01 37 cd 55"), - "on_state_all_off": bytes.fromhex("ab bb 05 e4 00 00 e1 55"), - "off_state_all_off": bytes.fromhex("ab bb 05 e3 00 01 e7 55"), + "cmd1_state_power_on": bytes.fromhex("ab bb 05 e3 00 01 e7 55"), + "cmd1_state_all_off": bytes.fromhex("ab bb 05 e3 00 00 e7 55"), + "cmd2_state_all_off": bytes.fromhex("ab bb 05 e4 00 00 e1 55"), "led_color_0000ff": bytes.fromhex("ab bb 06 e1 00 02 ff 1a 55"), "led_controller_state": bytes.fromhex("ab bb 08 ee ff 00 00 ff 02 e4 55"), } diff --git a/tests/test_misc.py b/tests/test_misc.py index caa5176..ffea825 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -30,6 +30,7 @@ def test_full_valid_featureset() -> None: fireplace_features.led_lights = True fireplace_features.night_light = True fireplace_features.split_flow = True + fireplace_features.timer = True assert fp.set_features(full_valid_set) == fireplace_features @@ -41,6 +42,7 @@ def test_partial_valid_featureset() -> None: fireplace_features.led_lights = False fireplace_features.night_light = True fireplace_features.split_flow = False + fireplace_features.timer = False assert fp.set_features(partial_valid_set) == fireplace_features diff --git a/tests/test_parsers.py b/tests/test_parsers.py index 463bd97..1d9e816 100644 --- a/tests/test_parsers.py +++ b/tests/test_parsers.py @@ -38,18 +38,29 @@ def test_mcu_version_parser() -> None: assert parse_mcu_version(response["mcu_version"][4:-2]) == "1.14" -def test_off_state_parser() -> None: +def test_cmd1_state_parser() -> None: """Test parsing the power off state from a known message.""" - assert parse_ifc_cmd1_state(response["off_state_all_off"][4:-2]) == (False, 0, 0) + assert parse_ifc_cmd1_state(response["cmd1_state_all_off"][4:-2]) == ( + False, + False, + 0, + 0, + ) + assert parse_ifc_cmd1_state(response["cmd1_state_power_on"][4:-2]) == ( + True, + False, + 0, + 0, + ) -def test_on_state_parser() -> None: +def test_cmd2_state_parser() -> None: """Test parsing the on state from a known message.""" - assert parse_ifc_cmd2_state(response["on_state_all_off"][4:-2]) == ( - False, - False, + assert parse_ifc_cmd2_state(response["cmd2_state_all_off"][4:-2]) == ( 0, 0, + False, + False, )