Exemplo n.º 1
0
    def __init__(self, config: conf.ConfigType):
        super().__init__(config=conf.CONFIG_SCHEMA(config))

        self._znp = None

        # It's easier to deal with this if it's never None
        self._reconnect_task = asyncio.Future()
        self._reconnect_task.cancel()
Exemplo n.º 2
0
    async def probe(cls, device_config: conf.ConfigType) -> bool:
        znp = ZNP(conf.CONFIG_SCHEMA({conf.CONF_DEVICE: device_config}))
        LOGGER.debug("Probing %s", znp._port_path)

        try:
            await znp.connect()
            return True
        except Exception as e:
            LOGGER.warning("Failed to probe ZNP radio with config %s",
                           device_config,
                           exc_info=e)
            return False
        finally:
            znp.close()
Exemplo n.º 3
0
    async def probe(cls, device_config: conf.ConfigType) -> bool:
        new_schema = conf.CONFIG_SCHEMA({
            conf.CONF_DEVICE: device_config,
            conf.CONF_ZNP_CONFIG: {
                conf.CONF_AUTO_RECONNECT: False
            },
        })

        znp = ZNP(new_schema)
        LOGGER.debug("Probing %s", znp._port_path)

        try:
            await znp.connect()
            return True
        except Exception:
            return False
        finally:
            znp.close()
Exemplo n.º 4
0
def config_for_port_path(path):
    return conf.CONFIG_SCHEMA(
        {conf.CONF_DEVICE: {
            conf.CONF_DEVICE_PATH: path
        }})
Exemplo n.º 5
0
async def test_api_reconnect(event_loop, mocker):
    SREQ_TIMEOUT = 0.2
    port_path = "/dev/ttyUSB1"

    config = conf.CONFIG_SCHEMA(
        {
            conf.CONF_DEVICE: {conf.CONF_DEVICE_PATH: port_path},
            conf.CONF_ZNP_CONFIG: {
                conf.CONF_SREQ_TIMEOUT: SREQ_TIMEOUT,
                conf.CONF_AUTO_RECONNECT_RETRY_DELAY: 0.01,
            },
        }
    )

    transport = mocker.Mock()

    def dummy_serial_conn(loop, protocol_factory, url, *args, **kwargs):
        fut = loop.create_future()
        assert url == port_path

        protocol = protocol_factory()
        protocol.connection_made(transport)

        fut.set_result((transport, protocol))

        return fut

    mocker.patch("serial_asyncio.create_serial_connection", new=dummy_serial_conn)
    mocker.patch("zigpy_znp.uart.connect", wraps=zigpy_znp.uart.connect)

    app = mocker.Mock()
    app.startup = Mock(return_value=asyncio.sleep(0))

    api = ZNP(config)
    api.set_application(app)

    connect_fut = event_loop.create_future()
    connect_task = asyncio.create_task(api.connect())
    connect_task.add_done_callback(lambda _: connect_fut.set_result(None))

    while transport.write.call_count < 1:
        await asyncio.sleep(0.01)  # XXX: not ideal

    # We should have receiving a ping
    transport.write.assert_called_once_with(bytes.fromhex("FE  00  21 01  20"))

    # Send a ping response
    api._uart.data_received(bytes.fromhex("FE  02  61 01  00 01  63"))

    # Wait to connect
    await connect_fut

    assert api._port_path == port_path

    transport.reset_mock()

    # Now that we're connected, close the connection due to an error
    assert transport.write.call_count == 0
    api.connection_lost(RuntimeError("Uh oh"))

    # We should get another ping request soon
    while transport.write.call_count != 1:
        await asyncio.sleep(0.01)  # XXX: not ideal

    transport.write.assert_called_once_with(bytes.fromhex("FE  00  21 01  20"))

    # Reply incorrectly to the ping request
    api._uart.data_received(b"bad response")

    # We should still have the old connection info
    assert api._port_path == port_path

    # Wait for the SREQ_TIMEOUT to pass, we should fail to reconnect
    await asyncio.sleep(SREQ_TIMEOUT + 0.1)

    transport.reset_mock()

    # We wait a bit again for another ping
    while transport.write.call_count != 1:
        await asyncio.sleep(0.01)  # XXX: not ideal

    transport.write.assert_called_once_with(bytes.fromhex("FE  00  21 01  20"))

    # Our reconnect task should complete after we send the ping reply
    reconnect_fut = event_loop.create_future()
    api._reconnect_task.add_done_callback(lambda _: reconnect_fut.set_result(None))

    # App re-startup should not have happened, we've never reconnected before
    assert api._app.startup.call_count == 0
    api._uart.data_received(bytes.fromhex("FE  02  61 01  00 01  63"))

    # We should be reconnected soon and the app should have been restarted
    await reconnect_fut
    assert api._app.startup.call_count == 1
Exemplo n.º 6
0
    def __init__(self, config: conf.ConfigType):
        super().__init__(config=conf.CONFIG_SCHEMA(config))

        self._znp = None