示例#1
0
async def test_force_remove(application, mocker):
    app, znp_server = application

    await app.startup(auto_form=False)

    mocker.patch("zigpy_znp.zigbee.application.ZDO_REQUEST_TIMEOUT", new=0.3)

    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xAABB)
    device.status = zigpy.device.Status.ENDPOINTS_INIT
    device.initializing = False

    # Reply to zigpy's leave request
    bad_mgmt_leave_req = znp_server.reply_once_to(
        request=c.ZDO.MgmtLeaveReq.Req(DstAddr=device.nwk, partial=True),
        responses=[c.ZDO.MgmtLeaveReq.Rsp(Status=t.Status.FAILURE)],
    )

    # Reply to our own leave request
    good_mgmt_leave_req = znp_server.reply_once_to(
        request=c.ZDO.MgmtLeaveReq.Req(DstAddr=0x0000, partial=True),
        responses=[
            c.ZDO.MgmtLeaveReq.Rsp(Status=t.Status.SUCCESS),
            c.ZDO.MgmtLeaveRsp.Callback(Src=0x000, Status=t.ZDOStatus.SUCCESS),
        ],
    )

    # Make sure the device exists
    assert app.get_device(nwk=device.nwk) is device

    await app.remove(device.ieee)
    await asyncio.gather(bad_mgmt_leave_req, good_mgmt_leave_req)

    # Make sure the device is gone once we remove it
    with pytest.raises(KeyError):
        app.get_device(nwk=device.nwk)
示例#2
0
async def test_zigpy_request(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    TSN = 1

    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xAABB)
    device.status = zigpy.device.Status.ENDPOINTS_INIT
    device.initializing = False

    device.add_endpoint(1).add_input_cluster(6)

    # Respond to a light turn on request
    data_req = znp_server.reply_once_to(
        request=c.AF.DataRequestExt.Req(
            DstAddrModeAddress=t.AddrModeAddress(mode=t.AddrMode.NWK,
                                                 address=device.nwk),
            DstEndpoint=1,
            SrcEndpoint=1,
            ClusterId=6,
            TSN=TSN,
            Data=bytes([0x01, TSN, 0x01]),
            partial=True,
        ),
        responses=[
            c.AF.DataRequestExt.Rsp(Status=t.Status.SUCCESS),
            c.AF.DataConfirm.Callback(
                Status=t.Status.SUCCESS,
                Endpoint=1,
                TSN=TSN,
            ),
            c.ZDO.SrcRtgInd.Callback(DstAddr=device.nwk, Relays=[]),
            c.AF.IncomingMsg.Callback(
                GroupId=0x0000,
                ClusterId=6,
                SrcAddr=device.nwk,
                SrcEndpoint=1,
                DstEndpoint=1,
                WasBroadcast=False,
                LQI=63,
                SecurityUse=False,
                TimeStamp=1198515,
                TSN=0,
                Data=bytes([0x08, TSN, 0x0B, 0x00, 0x00]),
                MacSrcAddr=device.nwk,
                MsgResultRadius=29,
            ),
        ],
    )

    # Turn on the light
    await device.endpoints[1].on_off.on()
    await data_req
示例#3
0
async def test_on_zdo_device_join(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    mocker.patch.object(app, "handle_join")

    nwk = 0x1234
    ieee = t.EUI64(range(8))

    znp_server.send(
        c.ZDO.TCDevInd.Callback(SrcNwk=nwk, SrcIEEE=ieee, ParentNwk=0x0001))
    app.handle_join.assert_called_once_with(nwk=nwk,
                                            ieee=ieee,
                                            parent_nwk=0x0001)
示例#4
0
async def test_on_zdo_device_leave_callback(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    mocker.patch.object(app, "handle_leave")

    nwk = 0x1234
    ieee = t.EUI64(range(8))

    znp_server.send(
        c.ZDO.LeaveInd.Callback(NWK=nwk,
                                IEEE=ieee,
                                Request=False,
                                Remove=False,
                                Rejoin=False))
    app.handle_leave.assert_called_once_with(nwk=nwk, ieee=ieee)
示例#5
0
async def test_on_zdo_device_announce(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    mocker.patch.object(app, "handle_join")

    nwk = 0x1234
    ieee = t.EUI64(range(8))

    znp_server.send(
        c.ZDOCommands.EndDeviceAnnceInd.Callback(
            Src=0x0001,
            NWK=nwk,
            IEEE=ieee,
            Capabilities=c.zdo.MACCapabilities.Router))
    app.handle_join.assert_called_once_with(nwk=nwk, ieee=ieee, parent_nwk=0)
示例#6
0
async def test_on_zdo_device_announce(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    mocker.patch.object(app, "handle_message")

    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xFA9E)

    znp_server.send(
        c.ZDO.EndDeviceAnnceInd.Callback(
            Src=0x0001,
            NWK=device.nwk,
            IEEE=device.ieee,
            Capabilities=c.zdo.MACCapabilities.Router,
        ))

    app.handle_message.called_once_with(cluster=ZDOCmd.Device_annce)
示例#7
0
async def test_request_use_ieee(application, mocker, use_ieee, dev_addr):
    app, znp_server = application
    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xAABB)

    send_req = mocker.patch.object(app, "_send_request", new=CoroutineMock())

    await app.request(
        device,
        use_ieee=use_ieee,
        profile=None,
        cluster=None,
        src_ep=None,
        dst_ep=None,
        sequence=None,
        data=None,
    )

    assert send_req.call_count == 1
    assert send_req.mock_calls[0][2]["dst_addr"] == dev_addr
示例#8
0
async def test_zigpy_request_failure(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    TSN = 1

    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xAABB)
    device.status = zigpy.device.Status.ENDPOINTS_INIT
    device.initializing = False

    device.add_endpoint(1).add_input_cluster(6)

    # Fail to respond to a light turn on request
    znp_server.reply_to(
        request=c.AF.DataRequestExt.Req(
            DstAddrModeAddress=t.AddrModeAddress(mode=t.AddrMode.NWK,
                                                 address=device.nwk),
            DstEndpoint=1,
            SrcEndpoint=1,
            ClusterId=6,
            TSN=TSN,
            Data=bytes([0x01, TSN, 0x01]),
            partial=True,
        ),
        responses=[
            c.AF.DataRequestExt.Rsp(Status=t.Status.SUCCESS),
            c.AF.DataConfirm.Callback(
                Status=t.Status.FAILURE,
                Endpoint=1,
                TSN=TSN,
            ),
        ],
    )

    mocker.patch.object(app,
                        "_send_request",
                        new=CoroutineMock(wraps=app._send_request))

    # Fail to turn on the light
    with pytest.raises(zigpy.exceptions.DeliveryError):
        await device.endpoints[1].on_off.on()

    assert app._send_request.call_count == 1
示例#9
0
async def test_zdo_request_interception(application, mocker):
    app, znp_server = application
    await app.startup(auto_form=False)

    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xFA9E)

    # Send back a request response
    active_ep_req = znp_server.reply_once_to(
        request=c.ZDO.SimpleDescReq.Req(DstAddr=device.nwk,
                                        NWKAddrOfInterest=device.nwk,
                                        Endpoint=1),
        responses=[
            c.ZDO.SimpleDescReq.Rsp(Status=t.Status.SUCCESS),
            c.ZDO.SimpleDescRsp.Callback(
                Src=device.nwk,
                Status=t.ZDOStatus.SUCCESS,
                NWK=device.nwk,
                SimpleDescriptor=SizePrefixedSimpleDescriptor(*dict(
                    endpoint=1,
                    profile=49246,
                    device_type=256,
                    device_version=2,
                    input_clusters=[0, 3, 4, 5, 6, 8, 2821, 4096],
                    output_clusters=[5, 25, 32, 4096],
                ).values()),
            ),
        ],
    )

    status, message = await app.request(
        device=device,
        profile=260,
        cluster=ZDOCmd.Simple_Desc_req,
        src_ep=0,
        dst_ep=0,
        sequence=1,
        data=b"\x01\x9e\xfa\x01",
        use_ieee=False,
    )

    await active_ep_req

    assert status == t.Status.SUCCESS
示例#10
0
async def test_update_network(mocker, caplog, application):
    app, znp_server = application

    await app.startup(auto_form=False)
    mocker.patch.object(app, "_reset", new=CoroutineMock())

    channel = t.uint8_t(15)
    pan_id = t.PanId(0x1234)
    extended_pan_id = t.ExtendedPanId(range(8))
    channels = t.Channels.from_channel_list([11, 15, 20])
    network_key = t.KeyData(range(16))

    channels_updated = znp_server.reply_once_to(
        request=c.Util.SetChannels.Req(Channels=channels),
        responses=[c.Util.SetChannels.Rsp(Status=t.Status.SUCCESS)],
    )

    bdb_set_primary_channel = znp_server.reply_once_to(
        request=c.AppConfig.BDBSetChannel.Req(IsPrimary=True,
                                              Channel=channels),
        responses=[c.AppConfig.BDBSetChannel.Rsp(Status=t.Status.SUCCESS)],
    )

    bdb_set_secondary_channel = znp_server.reply_once_to(
        request=c.AppConfig.BDBSetChannel.Req(IsPrimary=False,
                                              Channel=t.Channels.NO_CHANNELS),
        responses=[c.AppConfig.BDBSetChannel.Rsp(Status=t.Status.SUCCESS)],
    )

    set_pan_id = znp_server.reply_once_to(
        request=c.Util.SetPanId.Req(PanId=pan_id),
        responses=[c.Util.SetPanId.Rsp(Status=t.Status.SUCCESS)],
    )

    set_extended_pan_id = znp_server.reply_once_to(
        request=c.SYS.OSALNVWrite.Req(Id=NwkNvIds.EXTENDED_PAN_ID,
                                      Offset=0,
                                      Value=extended_pan_id.serialize()),
        responses=[c.SYS.OSALNVWrite.Rsp(Status=t.Status.SUCCESS)],
    )

    set_network_key_util = znp_server.reply_once_to(
        request=c.Util.SetPreConfigKey.Req(PreConfigKey=network_key),
        responses=[c.Util.SetPreConfigKey.Rsp(Status=t.Status.SUCCESS)],
    )

    set_network_key_nvram = znp_server.reply_once_to(
        request=c.SYS.OSALNVWrite.Req(Id=NwkNvIds.PRECFGKEYS_ENABLE,
                                      Offset=0,
                                      Value=t.Bool(True).serialize()),
        responses=[c.SYS.OSALNVWrite.Rsp(Status=t.Status.SUCCESS)],
    )

    set_nib_nvram = znp_server.reply_once_to(
        request=c.SYS.OSALNVWrite.Req(Id=NwkNvIds.NIB, Offset=0, partial=True),
        responses=[c.SYS.OSALNVWrite.Rsp(Status=t.Status.SUCCESS)],
    )

    # But it does succeed with a warning if you explicitly allow it
    with caplog.at_level(logging.WARNING):
        await app.update_network(
            channel=channel,
            channels=channels,
            extended_pan_id=extended_pan_id,
            network_key=network_key,
            pan_id=pan_id,
            tc_address=t.EUI64(range(8)),
            tc_link_key=t.KeyData(range(8)),
            update_id=0,
            reset=True,
        )

    # We should receive a few warnings for `tc_` stuff
    assert len(caplog.records) >= 2

    await channels_updated
    await bdb_set_primary_channel
    await bdb_set_secondary_channel
    await set_pan_id
    await set_extended_pan_id
    await set_network_key_util
    await set_network_key_nvram
    await set_nib_nvram

    app._reset.assert_called_once_with()

    # Ensure we set everything we could
    assert app.nwk_update_id is None  # We can't use it
    assert app.channel == channel
    assert app.channels == channels
    assert app.pan_id == pan_id
    assert app.extended_pan_id == extended_pan_id
示例#11
0
def application(znp_server):
    app = ControllerApplication(config_for_port_path("/dev/ttyFAKE0"))

    # Handle the entire startup sequence
    znp_server.reply_to(
        request=c.SYS.ResetReq.Req(Type=t.ResetType.Soft),
        responses=[
            c.SYS.ResetInd.Callback(
                Reason=t.ResetReason.PowerUp,
                TransportRev=2,
                ProductId=1,
                MajorRel=2,
                MinorRel=7,
                MaintRel=1,
            )
        ],
    )

    active_eps = [100, 13, 12, 11, 8, 1]

    znp_server.reply_to(
        request=c.ZDO.ActiveEpReq.Req(DstAddr=0x0000,
                                      NWKAddrOfInterest=0x0000),
        responses=[
            c.ZDO.ActiveEpReq.Rsp(Status=t.Status.SUCCESS),
            c.ZDO.ActiveEpRsp.Callback(
                Src=0x0000,
                Status=t.ZDOStatus.SUCCESS,
                NWK=0x0000,
                ActiveEndpoints=active_eps,
            ),
        ],
    )

    znp_server.reply_to(
        request=c.ZDO.ActiveEpReq.Req(DstAddr=0x0000,
                                      NWKAddrOfInterest=0x0000),
        responses=[
            c.ZDO.ActiveEpReq.Rsp(Status=t.Status.SUCCESS),
            c.ZDO.ActiveEpRsp.Callback(
                Src=0x0000,
                Status=t.ZDOStatus.SUCCESS,
                NWK=0x0000,
                ActiveEndpoints=active_eps,
            ),
        ],
    )

    def on_endpoint_registration(req):
        assert req.Endpoint not in active_eps

        active_eps.append(req.Endpoint)
        active_eps.sort(reverse=True)

        return c.AF.Register.Rsp(Status=t.Status.SUCCESS)

    znp_server.reply_to(
        request=c.AF.Register.Req(partial=True),
        responses=[on_endpoint_registration],
    )

    def on_endpoint_deletion(req):
        assert req.Endpoint in active_eps

        active_eps.remove(req.Endpoint)

        return c.AF.Delete.Rsp(Status=t.Status.SUCCESS)

    znp_server.reply_to(
        request=c.AF.Delete.Req(partial=True),
        responses=[on_endpoint_deletion],
    )

    znp_server.reply_to(
        request=c.AppConfig.BDBStartCommissioning.Req(
            Mode=c.app_config.BDBCommissioningMode.NwkFormation),
        responses=[
            c.AppConfig.BDBStartCommissioning.Rsp(Status=t.Status.SUCCESS),
            c.AppConfig.BDBCommissioningNotification.Callback(
                Status=c.app_config.BDBCommissioningStatus.Success,
                Mode=c.app_config.BDBCommissioningMode.NwkSteering,
                RemainingModes=c.app_config.BDBCommissioningMode.NONE,
            ),
        ],
    )

    # Reply to the initialization NVID writes
    for nvid in [
            NwkNvIds.CONCENTRATOR_ENABLE,
            NwkNvIds.CONCENTRATOR_DISCOVERY,
            NwkNvIds.CONCENTRATOR_RC,
            NwkNvIds.SRC_RTG_EXPIRY_TIME,
            NwkNvIds.NWK_CHILD_AGE_ENABLE,
            NwkNvIds.LOGICAL_TYPE,
    ]:
        znp_server.reply_to(
            request=c.SYS.OSALNVWrite.Req(Id=nvid, Offset=0, partial=True),
            responses=[c.SYS.OSALNVWrite.Rsp(Status=t.Status.SUCCESS)],
        )

    znp_server.reply_to(
        request=c.SYS.OSALNVRead.Req(Id=NwkNvIds.HAS_CONFIGURED_ZSTACK3,
                                     Offset=0),
        responses=[
            c.SYS.OSALNVRead.Rsp(Status=t.Status.SUCCESS, Value=b"\x55")
        ],
    )

    znp_server.reply_to(
        request=c.Util.GetDeviceInfo.Req(),
        responses=[
            c.Util.GetDeviceInfo.Rsp(
                Status=t.Status.SUCCESS,
                IEEE=t.EUI64([0x00, 0x12, 0x4B, 0x00, 0x1C, 0xAA, 0xAC, 0x5C]),
                NWK=t.NWK(0xFFFE),
                DeviceType=t.DeviceTypeCapabilities(7),
                DeviceState=t.DeviceState.InitializedNotStarted,
                AssociatedDevices=[],
            )
        ],
    )

    znp_server.reply_to(
        request=c.ZDO.StartupFromApp.Req(partial=True),
        responses=[
            c.ZDO.StartupFromApp.Rsp(
                State=c.zdo.StartupState.RestoredNetworkState),
            c.ZDO.StateChangeInd.Callback(
                State=t.DeviceState.StartedAsCoordinator),
        ],
    )

    # The NIB matches the above device info
    NIB = bytes.fromhex("""
        790502331433001e0000000105018f00070002051e000000190000000000000000000000FFFE0800
        008010020f0f040001000000010000000000124b001caaac5c010000000000000000000000000000
        000000000000000000000000000000000000000000000f030001780a0100000020470000
        """)

    znp_server.reply_to(
        request=c.SYS.OSALNVRead.Req(Id=NwkNvIds.NIB, Offset=0),
        responses=[c.SYS.OSALNVRead.Rsp(Status=t.Status.SUCCESS, Value=NIB)],
    )

    return app, znp_server
示例#12
0
                        "_send_request",
                        new=CoroutineMock(wraps=app._send_request))

    # Fail to turn on the light
    with pytest.raises(zigpy.exceptions.DeliveryError):
        await device.endpoints[1].on_off.on()

    assert app._send_request.call_count == 1


@pytest_mark_asyncio_timeout(seconds=3)
@pytest.mark.parametrize(
    "use_ieee,dev_addr",
    [
        (True,
         t.AddrModeAddress(mode=t.AddrMode.IEEE, address=t.EUI64(range(8)))),
        (False, t.AddrModeAddress(mode=t.AddrMode.NWK, address=t.NWK(0xAABB))),
    ],
)
async def test_request_use_ieee(application, mocker, use_ieee, dev_addr):
    app, znp_server = application
    device = app.add_device(ieee=t.EUI64(range(8)), nwk=0xAABB)

    send_req = mocker.patch.object(app, "_send_request", new=CoroutineMock())

    await app.request(
        device,
        use_ieee=use_ieee,
        profile=None,
        cluster=None,
        src_ep=None,
示例#13
0
def test_addr_mode_address():
    """Test Addr mode address."""

    data = b"\x03\x00\x01\x02\x03\x04\x05\x06\x07"
    extra = b"The rest of the data\x55\xaa"

    # IEEE
    r, rest = t.AddrModeAddress.deserialize(data + extra)
    assert rest == extra
    assert r.mode == t.AddrMode.IEEE
    assert r.address == t.EUI64(range(8))
    assert r.serialize() == data

    # NWK
    data = b"\x02\xaa\x55\x02\x03\x04\x05\x06\x07"
    r, rest = t.AddrModeAddress.deserialize(data + extra)
    assert rest == extra
    assert r.mode == t.AddrMode.NWK
    assert r.address == t.NWK(0x55AA)
    assert r.serialize()[:3] == data[:3]
    assert len(r.serialize()) == 9

    # Group
    data = b"\x01\xcd\xab\x02\x03\x04\x05\x06\x07"
    r, rest = t.AddrModeAddress.deserialize(data + extra)
    assert rest == extra
    assert r.mode == t.AddrMode.Group
    assert r.address == t.NWK(0xABCD)
    assert r.serialize()[:3] == data[:3]
    assert len(r.serialize()) == 9

    # Broadcast
    data = b"\x0f\xfe\xff\x02\x03\x04\x05\x06\x07"
    r, rest = t.AddrModeAddress.deserialize(data + extra)
    assert rest == extra
    assert r.mode == t.AddrMode.Broadcast
    assert r.address == t.NWK(0xFFFE)
    assert r.serialize()[:3] == data[:3]
    assert len(r.serialize()) == 9

    with pytest.raises(ValueError):
        # 0xab is not a valid mode
        data = b"\xAB\xaa\x55\x02\x03\x04\x05\x06\x07"
        t.AddrModeAddress.deserialize(data)

    with pytest.raises(ValueError):
        # NOT_PRESENT is a valid AddrMode member but it is not a valid AddrModeAddress
        data = b"\x00\xaa\x55\x02\x03\x04\x05\x06\x07"
        t.AddrModeAddress.deserialize(data)

    # Bytes at the end for NWK address mode are ignored
    data1 = b"\x02\x0E\xAD" + b"\xC0\x8C\x97\x83\xB0\x20\x33"
    data2 = b"\x02\x0E\xAD" + b"\x3F\xB9\x5B\x64\x20\x86\xD6"

    r1, _ = t.AddrModeAddress.deserialize(data1)
    r2, _ = t.AddrModeAddress.deserialize(data2)

    assert r1 == r2

    # All of the bytes are used for IEEE address mode
    data1 = b"\x02\x0E\xAD\xC0\x8C\x97\x83\xB0\x20\x33"
    data2 = b"\x02\x0E\xAD\x3F\xB9\x5B\x64\x20\x86\xD6"

    r3, _ = t.AddrModeAddress.deserialize(b"\x03" + data1[1:])
    r4, _ = t.AddrModeAddress.deserialize(b"\x03" + data2[1:])

    assert r3 != r4