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
Beispiel #2
0
    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)
Beispiel #4
0
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 
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
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)
Beispiel #11
0
    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
Beispiel #12
0
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()