async def setup_panel(mocker): mocker.patch.multiple( cfg, LOGGING_LEVEL_CONSOLE=logging.DEBUG, LOGGING_DUMP_PACKETS=True ) mocker.patch("paradox.lib.utils.main_thread_loop", asyncio.get_event_loop()) # cfg.LOGGING_LEVEL_CONSOLE = logging.DEBUG # cfg.LOGGING_DUMP_PACKETS = True logger.setLevel(logging.DEBUG) alarm = Paradox() # alarm.work_loop.set_debug(True) alarm.run_state = RunState.RUN start_communication_response = Container( fields=Container(value=Container(product_id="MAGELLAN_MG5050")) ) alarm.panel = create_panel(alarm, start_communication_response) await send_initial_status(alarm) con = MockConnection(alarm.on_connection_message) alarm._connection = con alarm._register_connection_handlers() return alarm, con
def _clean_session(self): logger.info("Clean Session") if self.connection.connected: if not self.panel: panel = create_panel(self) else: panel = self.panel logger.info("Cleaning previous session. Closing connection") # Write directly as this can be called from other contexts self.connection.write(panel.get_message('CloseConnection').build(dict()))
def _parse_serial_passthrough_response(self, parsed): parsed_payload = self.panel.parse_message(parsed.payload, direction="frompanel") if parsed_payload is not None: if parsed_payload is not None: print(parsed_payload) else: print( f"No parser for serial_passthrough_response payload: {binascii.hexlify(parsed.payload)}" ) if parsed_payload.fields.value.po.command == 0: # panel detection self.panel = create_panel(None, parsed_payload) if parsed_payload.fields.value.po.command == 5: # eeprom/ram read self._parse_serial_passthrough_eeprom_read(parsed_payload)
async def setup_panel(mocker): mocker.patch.object(cfg, "LOGGING_LEVEL_CONSOLE", logging.DEBUG) mocker.patch.object(cfg, "LOGGING_DUMP_PACKETS", True) mocker.patch("paradox.lib.utils.main_thread_loop", asyncio.get_event_loop()) # cfg.LOGGING_LEVEL_CONSOLE = logging.DEBUG # cfg.LOGGING_DUMP_PACKETS = True logger.setLevel(logging.DEBUG) alarm = Paradox() #alarm.work_loop.set_debug(True) alarm.run_state = RunState.RUN alarm.panel = create_panel(alarm, 'MAGELLAN_MG5050') await send_initial_status(alarm) con = MockConnection(alarm.on_connection_message) alarm._connection = con alarm._register_connection_handlers() return alarm, con
async def connect(self): if self._connection: self.disconnect() # socket needs to be also closed self.panel = None self.run_state = RunState.INIT logger.info("Connecting to interface") if not await self.connection.connect(): self.run_state = RunState.ERROR logger.error('Failed to connect to interface') return False logger.info("Connecting to panel") if not self.panel: self.panel = create_panel(self) self.connection.variable_message_length(self.panel.variable_message_length) try: logger.info("Initiating communication") initiate_reply = await self.send_wait( self.panel.get_message('InitiateCommunication'), None, reply_expected=0x07 ) if initiate_reply: model = initiate_reply.fields.value.label.strip(b'\0 ').decode(cfg.LABEL_ENCODING) firmware_version = "{}.{} build {}".format( initiate_reply.fields.value.application.version, initiate_reply.fields.value.application.revision, initiate_reply.fields.value.application.build ) serial_number = hexlify(initiate_reply.fields.value.serial_number).decode() logger.info("Found Panel {} version {}".format(model, firmware_version)) else: raise ConnectionError("Panel did not replied to InitiateCommunication") logger.info("Starting communication") reply = await self.send_wait(self.panel.get_message('StartCommunication'), args=dict(source_id=0x02), reply_expected=0x00) if reply is None: raise ConnectionError("Panel did not replied to StartCommunication") if reply.fields.value.product_id is not None: self.panel = create_panel(self, reply.fields.value.product_id) # Now we know what panel it is. Let's # recreate panel object. ps.sendMessage( 'panel_detected', panel=DetectedPanel( product_id=reply.fields.value.product_id, model=model, firmware_version=firmware_version, serial_number=serial_number ) ) else: raise PanelNotDetected('Failed to detect panel') result = await self.panel.initialize_communication(reply, cfg.PASSWORD) if not result: raise ConnectionError("Failed to initialize communication") if cfg.SYNC_TIME: await self.sync_time() if cfg.DEVELOPMENT_DUMP_MEMORY: if hasattr(self.panel, 'dump_memory') and callable(self.panel.dump_memory): logger.warning("Requested memory dump. Dumping...") await self.panel.dump_memory() logger.warning("Memory dump completed. Exiting pai.") raise SystemExit() else: logger.warning("Requested memory dump, but current panel type does not support it yet.") logger.info("Loading definitions") definitions = await self.panel.load_definitions() ps.sendMessage('definitions_loaded', data=definitions) logger.info("Loading labels") labels = await self.panel.load_labels() ps.sendMessage('labels_loaded', data=labels) logger.info("Connection OK") self.run_state = RunState.RUN self.request_status_refresh() # Trigger status update ps.sendMessage('connected') return True except asyncio.TimeoutError as e: logger.error("Timeout while connecting to panel: %s" % str(e)) except ConnectionError as e: logger.error("Failed to connect: %s" % str(e)) self.run_state = RunState.ERROR return False
async def connect_async(self): self.disconnect() # socket needs to be also closed logger.info("Connecting to interface") if not await self.connection.connect(): logger.error('Failed to connect to interface') self.run = STATE_STOP return False self.run = STATE_STOP self.connection.timeout(0.5) logger.info("Connecting to panel") # Reset all states self.reset() if not self.panel: self.panel = create_panel(self) self.connection.variable_message_length( self.panel.variable_message_length) try: logger.info("Initiating communication") reply = await self.send_wait( self.panel.get_message('InitiateCommunication'), None, reply_expected=0x07) if reply: logger.info("Found Panel {} version {}.{} build {}".format( (reply.fields.value.label.strip(b'\0 ').decode( cfg.LABEL_ENCODING)), reply.fields.value.application.version, reply.fields.value.application.revision, reply.fields.value.application.build)) else: raise ConnectionError( "Panel did not replied to InitiateCommunication") logger.info("Starting communication") reply = await self.send_wait( self.panel.get_message('StartCommunication'), args=dict(source_id=0x02), reply_expected=0x00) if reply is None: raise ConnectionError( "Panel did not replied to StartCommunication") if reply.fields.value.product_id is not None: self.panel = create_panel( self, reply.fields.value.product_id ) # Now we know what panel it is. Let's # recreate panel object. result = await self.panel.initialize_communication( reply, cfg.PASSWORD) if not result: raise ConnectionError("Failed to initialize communication") # Now we need to start async message reading worker self.run = STATE_RUN self.receive_worker_task = self.work_loop.create_task( self.receive_worker()) if cfg.SYNC_TIME: await self.sync_time() if cfg.DEVELOPMENT_DUMP_MEMORY: if hasattr(self.panel, 'dump_memory') and callable( self.panel.dump_memory): logger.warn("Requested memory dump. Dumping...") await self.panel.dump_memory() logger.warn("Memory dump completed. Exiting pai.") raise SystemExit() else: logger.warn( "Requested memory dump, but current panel type does not support it yet." ) await self.panel.update_labels() logger.info("Connection OK") self.loop_wait = False return True except ConnectionError as e: logger.error("Failed to connect: %s" % str(e)) except Exception: logger.exception("Connect error") self.run = STATE_STOP return False
def connect(self): logger.info("Connecting to interface") if not self.connection.connect(): logger.error('Failed to connect to interface') self.run = STATE_STOP return False self.connection.timeout(0.5) logger.info("Connecting to panel") # Reset all states self.reset() self.run = STATE_RUN if not self.panel: self.panel = create_panel(self) try: logger.info("Initiating communication") reply = self.send_wait( self.panel.get_message('InitiateCommunication'), None, reply_expected=0x07) if reply: logger.info("Found Panel {} version {}.{} build {}".format( (reply.fields.value.label.strip(b'\0 ').decode('utf-8')), reply.fields.value.application.version, reply.fields.value.application.revision, reply.fields.value.application.build)) else: logger.warn( "Unknown panel. Some features may not be supported") logger.info("Starting communication") reply = self.send_wait( self.panel.get_message('StartCommunication'), args=dict(source_id=0x02), reply_expected=0x00) if reply is None: self.run = STATE_STOP return False self.panel = create_panel(self, reply.fields.value.product_id ) # Now we know what panel it is. Let's # recreate panel object. result = self.panel.initialize_communication(reply, cfg.PASSWORD) if not result: self.run = STATE_STOP return False self.send_wait() # Read WinLoad in (connected) event if cfg.SYNC_TIME: self.sync_time() self.send_wait() # Read Clock loss restore event self.panel.update_labels() logger.info("Connection OK") self.loop_wait = False return True except Exception: logger.exception("Connect error") self.run = STATE_STOP return False
def connect(self): logger.info("Connecting to interface") if not self.connection.connect(): logger.error('Failed to connect to interface') self.run = STATE_STOP return False self.run = STATE_STOP self.connection.timeout(0.5) logger.info("Connecting to panel") # Reset all states self.reset() if not self.panel: self.panel = create_panel(self) try: logger.info("Initiating communication") reply = self.send_wait( self.panel.get_message('InitiateCommunication'), None, reply_expected=0x07) if reply: logger.info("Found Panel {} version {}.{} build {}".format( (reply.fields.value.label.strip(b'\0 ').decode('utf-8')), reply.fields.value.application.version, reply.fields.value.application.revision, reply.fields.value.application.build)) else: logger.warn( "Unknown panel. Some features may not be supported") logger.info("Starting communication") reply = self.send_wait( self.panel.get_message('StartCommunication'), args=dict(source_id=0x02), reply_expected=0x00) if reply is None: return False self.panel = create_panel(self, reply.fields.value.product_id ) # Now we know what panel it is. Let's # recreate panel object. result = self.panel.initialize_communication(reply, cfg.PASSWORD) if not result: return False self.send_wait() # Read WinLoad in (connected) event if cfg.SYNC_TIME: self.sync_time() self.send_wait() # Read Clock loss restore event if cfg.DEVELOPMENT_DUMP_MEMORY: if hasattr(self.panel, 'dump_memory') and callable( self.panel.dump_memory): logger.warn("Requested memory dump. Dumping...") self.panel.dump_memory() logger.warn("Memory dump completed. Exiting pai.") raise SystemExit() else: logger.warn( "Requested memory dump, but current panel type does not support it yet." ) self.panel.update_labels() self.run = STATE_RUN logger.info("Connection OK") self.loop_wait = False return True except Exception: logger.exception("Connect error") self.run = STATE_STOP return False
def create_evo192_panel(alarm=None): payload = b"\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05" data = StartCommunicationResponse.parse(payload) return create_panel(alarm, data)
def __init__(self): self.panel = create_panel(None)
async def connect(self) -> bool: if self._connection: await self.disconnect() # socket needs to be also closed self.panel = None self.run_state = RunState.INIT logger.info("Connecting to interface") if not await self.connection.connect(): self.run_state = RunState.ERROR logger.error("Failed to connect to interface") return False logger.info("Connecting to Panel") if not self.panel: self.panel = create_panel(self) self.connection.variable_message_length( self.panel.variable_message_length) try: initiate_reply = await self.send_wait( self.panel.get_message("InitiateCommunication"), None, reply_expected=0x07, ) if initiate_reply: model = initiate_reply.fields.value.label.strip(b"\0 ").decode( cfg.LABEL_ENCODING) firmware_version = "{}.{} build {}".format( initiate_reply.fields.value.application.version, initiate_reply.fields.value.application.revision, initiate_reply.fields.value.application.build, ) serial_number = hexlify( initiate_reply.fields.value.serial_number).decode() logger.info("Panel Identified {} version {}".format( model, firmware_version)) else: raise ConnectionError( "Panel did not replied to InitiateCommunication") logger.info("Initiating panel connection") reply = await self.send_wait( self.panel.get_message("StartCommunication"), args=dict(source_id=0x02), reply_expected=0x00, ) if reply is None: raise ConnectionError( "Panel did not replied to StartCommunication") if reply.fields.value.product_id is not None: self.panel = create_panel( self, reply) # Now we know what panel it is. Let's # recreate panel object. ps.sendMessage( "panel_detected", panel=DetectedPanel( product_id=reply.fields.value.product_id, model=model, firmware_version=firmware_version, serial_number=serial_number, ), ) else: raise PanelNotDetected("Failed to detect panel") result = await self.panel.initialize_communication(cfg.PASSWORD) if not result: raise ConnectionError("Failed to initialize communication") self.run_state = RunState.CONNECTED logger.info("Connection OK") return True except asyncio.TimeoutError: logger.error( "Timeout while connecting to panel. Is an other connection active?" ) except ConnectionError as e: logger.error("Failed to connect: %s" % str(e)) self.run_state = RunState.ERROR return False
async def test_hass(mocker): mocker.patch('paradox.lib.utils.main_thread_loop', asyncio.get_event_loop()) con = mocker.patch("paradox.interfaces.mqtt.core.MQTTConnection") con.get_instance.return_value.availability_topic = "paradox/interface/availability" con.get_instance.return_value.run_status_topic = "paradox/interface/run_status" alarm = mocker.MagicMock() alarm.panel = create_panel(alarm, 'DIGIPLEX_EVO_192') interface = HomeAssistantMQTTInterface(alarm) interface.start() interface.on_connect(None, None, None, None) assert interface.connected_future.done( ) and interface.connected_future.result() is True try: await asyncio.sleep(0.01) # TODO: Bad way to wait for a start sendMessage("panel_detected", panel=DetectedPanel(ProductIdEnum.parse(b'\x05'), 'EVO192', "6.80 build 5", "aabbccdd")) sendMessage( "labels_loaded", data=dict(partition={ 1: dict(id=1, label='Partition 1', key='Partition_1') })) sendMessage("status_update", status=dict(partition={1: dict(arm=False)})) await asyncio.sleep(0.01) interface.mqtt.publish.assert_any_call( 'homeassistant/sensor/aabbccdd/run_status/config', json.dumps({ "name": "Run status", "unique_id": "aabbccdd_partition_run_status", "state_topic": "paradox/interface/run_status", "device": { "manufacturer": "Paradox", "model": "EVO192", "identifiers": ["Paradox", "EVO192", "aabbccdd"], "name": "EVO192", "sw_version": "6.80 build 5" } }), 0, True) interface.mqtt.publish.assert_any_call( 'homeassistant/alarm_control_panel/aabbccdd/Partition_1/config', json.dumps({ "name": "Partition 1", "unique_id": "aabbccdd_partition_Partition_1", "command_topic": "paradox/control/partitions/Partition_1", "state_topic": "paradox/states/partitions/Partition_1/current_state", "availability_topic": "paradox/interface/availability", "device": { "manufacturer": "Paradox", "model": "EVO192", "identifiers": ["Paradox", "EVO192", "aabbccdd"], "name": "EVO192", "sw_version": "6.80 build 5" }, "payload_disarm": "disarm", "payload_arm_home": "arm_stay", "payload_arm_away": "arm", "payload_arm_night": "arm_sleep" }), 0, True) finally: interface.stop() interface.join() assert not interface.is_alive()