diff --git a/cbus/daemon/cmqttd.py b/cbus/daemon/cmqttd.py index c647207..81efb44 100644 --- a/cbus/daemon/cmqttd.py +++ b/cbus/daemon/cmqttd.py @@ -29,9 +29,10 @@ async def create_serial_connection(*_, **__): raise ImportError('Serial device support requires pyserial-asyncio') -from cbus.common import MIN_GROUP_ADDR, MAX_GROUP_ADDR, check_ga, Application +from cbus.common import MIN_GROUP_ADDR, MAX_GROUP_ADDR, check_ga, Application, GroupState from cbus.paho_asyncio import AsyncioHelper from cbus.protocol.pciprotocol import PCIProtocol +from cbus.protocol.cal.report import BinaryStatusReport from cbus.toolkit.cbz import CBZ @@ -111,7 +112,24 @@ def on_lighting_group_off(self, source_addr, group_addr): if not self.mqtt_api: return self.mqtt_api.lighting_group_off(source_addr, group_addr) - + + def on_extended_cal(self, source_addr, extended_cal): + if not self.mqtt_api: + return + logger.debug(f'Block start: {extended_cal.block_start!r}') + if isinstance(extended_cal.report, BinaryStatusReport): + group_addr = extended_cal.block_start + for s in extended_cal.report: + if s == GroupState.ON: + logger.debug(f'group_addr {group_addr!r} is ON') + self.mqtt_api.lighting_group_on(source_addr, group_addr) + elif s == GroupState.OFF: + logger.debug(f'group_addr {group_addr!r} is OFF') + self.mqtt_api.lighting_group_off(source_addr, group_addr) + group_addr += 1 + else: + logger.debug(f'unhandled report type {extended_cal.report!r}') + # TODO: on_lighting_group_terminate_ramp def on_clock_request(self, source_addr): diff --git a/cbus/protocol/pciprotocol.py b/cbus/protocol/pciprotocol.py index 08df01d..35a0a50 100644 --- a/cbus/protocol/pciprotocol.py +++ b/cbus/protocol/pciprotocol.py @@ -44,6 +44,7 @@ async def create_serial_connection(*_, **__): from cbus.protocol.base_packet import ( BasePacket, SpecialServerPacket, SpecialClientPacket) from cbus.protocol.cal.identify import IdentifyCAL +from cbus.protocol.cal.extended import ExtendedCAL from cbus.protocol.cbus_protocol import CBusProtocol from cbus.protocol.confirm_packet import ConfirmationPacket from cbus.protocol.dm_packet import DeviceManagementPacket @@ -88,11 +89,13 @@ def connection_made(self, transport: WriteTransport) -> None: """ self._transport = transport - self.pci_reset() + self.pci_reset() + create_task(self.req_status()) if self._timesync_frequency: create_task(self.timesync()) def connection_lost(self, exc: Optional[Exception]) -> None: + logger.debug("Connection lost") self._transport = None self._connection_lost_future.set_result(True) @@ -134,6 +137,12 @@ def handle_cbus_packet(self, p: BasePacket) -> None: self.on_clock_update(p.source_address, s.val) else: logger.debug(f'hcp: unhandled SAL type: {s!r}') + elif isinstance(p, PointToPointPacket): + for s in p: + if isinstance(s, ExtendedCAL): + self.on_extended_cal(p.source_address, s) + else: + logger.debug(f'hcp: unhandled P2P type: {s!r}') else: logger.debug(f'hcp: unhandled other packet: {p!r}') @@ -309,6 +318,18 @@ def on_clock_update(self, source_addr, val): """ logger.debug(f'recv: clock update from {source_addr} of {val!r}') + + def on_extended_cal(self, source_addr, extended_cal): + """ + Event called when a unit sends a binary status report to the PCI. + + :param source_addr: Source address of the unit requesting time. + :type source_addr: int + :param extended_cal: Extended CAL Object + :type extended_cal: ExtendedCAL + + """ + logger.debug(f'recv: extended CAL from {source_addr} of {extended_cal}') # other things. @@ -411,6 +432,7 @@ def pci_reset(self): self._send(DeviceManagementPacket( checksum=False, parameter=0x30, value=0x59), basic_mode=True) + def identify(self, unit_address, attribute): """ @@ -551,6 +573,16 @@ def clock_datetime(self, when: Optional[datetime] = None): p = PointToMultipointPacket(sals=clock_update_sal(when)) return self._send(p) + async def req_status(self): + + await sleep(5) + + self._send(PointToMultipointPacket(sals=StatusRequestSAL( + child_application=Application.LIGHTING, + level_request=False, + group_address=0, + ))) + async def timesync(self): frequency = self._timesync_frequency if frequency <= 0: