Skip to content

Commit

Permalink
feat: correct parsers and tests based on new info
Browse files Browse the repository at this point in the history
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 <felix@kaechele.ca>
  • Loading branch information
kaechele committed Mar 12, 2023
1 parent 4d0eedd commit 9247698
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 24 deletions.
4 changes: 2 additions & 2 deletions src/bonaparte/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)

Expand Down Expand Up @@ -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(
Expand Down
23 changes: 15 additions & 8 deletions src/bonaparte/fireplace.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
13 changes: 7 additions & 6 deletions src/bonaparte/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]:
Expand Down
5 changes: 3 additions & 2 deletions tests/mock_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
}
2 changes: 2 additions & 0 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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


Expand Down
23 changes: 17 additions & 6 deletions tests/test_parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)


Expand Down

0 comments on commit 9247698

Please # to comment.