def test_rx_device_annce(app, addr_ieee, addr_nwk): dst_ep = 0 cluster_id = zdo_t.ZDOCmd.Device_annce device = MagicMock() device.status = zigpy.device.Status.NEW app.get_device = MagicMock(return_value=device) app.handle_join = MagicMock() app._handle_reply = MagicMock() app.handle_message = MagicMock() data = t.uint8_t(0xAA).serialize() data += addr_nwk.address.serialize() data += addr_ieee.address.serialize() data += t.uint8_t(0x8E).serialize() app.handle_rx( addr_nwk, sentinel.src_ep, dst_ep, sentinel.profile_id, cluster_id, data, sentinel.lqi, sentinel.rssi, ) assert app.handle_message.call_count == 1 assert app.handle_join.call_count == 1 assert app.handle_join.call_args[0][0] == addr_nwk.address assert app.handle_join.call_args[0][1] == addr_ieee.address assert app.handle_join.call_args[0][2] == 0
def _api_frame(self, cmd, *args): schema = TX_COMMANDS[cmd] d = t.serialize(args, schema) data = t.uint8_t(cmd).serialize() self._seq = (self._seq % 255) + 1 data += t.uint8_t(self._seq).serialize() data += t.uint8_t(0).serialize() data += t.uint16_t(len(d) + 5).serialize() data += d return data, self._seq
def _fake_args(arg_type): if isinstance(arg_type(), t.DeconzAddressEndpoint): addr = t.DeconzAddressEndpoint() addr.address_mode = t.ADDRESS_MODE.NWK addr.address = t.uint8_t(0) addr.endpoint = t.uint8_t(0) return addr if isinstance(arg_type(), t.EUI64): return t.EUI64([0x01] * 8) return arg_type()
async def request( self, device, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, use_ieee=False, ): req_id = self.get_sequence() LOGGER.debug( "Sending Zigbee request with tsn %s under %s request id, data: %s", sequence, req_id, binascii.hexlify(data), ) dst_addr_ep = t.DeconzAddressEndpoint() dst_addr_ep.endpoint = t.uint8_t(dst_ep) if use_ieee: dst_addr_ep.address_mode = t.uint8_t(t.ADDRESS_MODE.IEEE) dst_addr_ep.address = device.ieee else: dst_addr_ep.address_mode = t.uint8_t(t.ADDRESS_MODE.NWK) dst_addr_ep.address = device.nwk tx_options = t.DeconzTransmitOptions.USE_NWK_KEY_SECURITY async with self._limit_concurrency(): with self._pending.new(req_id) as req: try: await self._api.aps_data_request( req_id, dst_addr_ep, profile, cluster, min(1, src_ep), data, tx_options=tx_options, ) except zigpy_deconz.exception.CommandError as ex: return ex.status, f"Couldn't enqueue send data request: {ex!r}" r = await asyncio.wait_for(req.result, SEND_CONFIRM_TIMEOUT) if r: LOGGER.debug("Error while sending %s req id frame: %s", req_id, r) return r, "message send failure" return r, "message send success"
def _fake_args(arg_type): if issubclass(arg_type, enum.Enum): return list(arg_type)[0] # Pick the first enum value elif issubclass(arg_type, t.DeconzAddressEndpoint): addr = t.DeconzAddressEndpoint() addr.address_mode = t.ADDRESS_MODE.NWK addr.address = t.uint8_t(0) addr.endpoint = t.uint8_t(0) return addr elif issubclass(arg_type, t.EUI64): return t.EUI64([0x01] * 8) return arg_type()
def test_api_frame(api): addr = t.DeconzAddressEndpoint() addr.address_mode = t.ADDRESS_MODE.NWK addr.address = t.uint8_t(0) addr.endpoint = t.uint8_t(0) for cmd, schema in deconz_api.TX_COMMANDS.items(): if schema: args = [ addr if isinstance(a(), t.DeconzAddressEndpoint) else a() for a in schema ] api._api_frame(cmd, *args) else: api._api_frame(cmd)
async def broadcast( self, profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address=zigpy.types.BroadcastAddress.RX_ON_WHEN_IDLE): req_id = self.get_sequence() LOGGER.debug( "Sending Zigbee broadcast with tsn %s under %s request id, data: %s", sequence, req_id, binascii.hexlify(data)) dst_addr_ep = t.DeconzAddressEndpoint() dst_addr_ep.address_mode = t.uint8_t(t.ADDRESS_MODE.GROUP.value) dst_addr_ep.address = t.uint16_t(broadcast_address) with self._pending.new(req_id) as req: try: await self._api.aps_data_request(req_id, dst_addr_ep, profile, cluster, min(1, src_ep), data) except zigpy_deconz.exception.CommandError as ex: return ex.status, "Couldn't enqueue send data request for broadcast: {}".format( ex) r = await asyncio.wait_for(req.result, SEND_CONFIRM_TIMEOUT) if r: LOGGER.warning( "Error while sending %s req id broadcast: 0x%02x", req_id, r) return r, "broadcast send failure" return r, "broadcast send success"
def test_device_state_network_state(data, network_state): """Test device state flag.""" extra = b"the rest of the data\xaa\x55" for other_fields in (0x04, 0x08, 0x0C, 0x10, 0x24, 0x28, 0x30, 0x2C): new_data = t.uint8_t(data | other_fields).serialize() state, rest = deconz_api.DeviceState.deserialize(new_data + extra) assert rest == extra assert state.network_state == deconz_api.NetworkState[network_state] assert state.serialize() == new_data
def test_struct(): class TestStruct(t.Struct): _fields = [("a", t.uint8_t), ("b", t.uint8_t)] ts = TestStruct() ts.a = t.uint8_t(0xAA) ts.b = t.uint8_t(0xBB) ts2 = TestStruct(ts) assert ts2.a == ts.a assert ts2.b == ts.b r = repr(ts) assert "TestStruct" in r assert r.startswith("<") and r.endswith(">") s = ts2.serialize() assert s == b"\xaa\xbb" extra = b"\x00extra data\xff" d, rest = TestStruct.deserialize(s + extra) assert rest == extra assert d.a == ts.a assert d.b == ts.b
def test_api_frame(api): addr = t.DeconzAddress() addr.address_mode = t.ADDRESS_MODE.NWK addr.address = t.uint8_t(0) for cmd_name, cmd_opts in deconz_api.TX_COMMANDS.items(): _, schema, _ = cmd_opts if schema: args = [ addr if isinstance(a(), t.DeconzAddress) else a() for a in schema ] api._api_frame(cmd_name, *args) else: api._api_frame(cmd_name)
def test_data_received_unk_cmd(api, monkeypatch): monkeypatch.setattr( t, 'deserialize', mock.MagicMock(return_value=(mock.sentinel.deserialize_data, b''))) for cmd_id in range(253, 255): payload = b'\x01\x02\x03\x04' status = t.uint8_t(0x00).serialize() data = cmd_id.to_bytes(1, 'big') + b'\x00' + \ status + b'\x00\x00' + payload api._awaiting[0] = (mock.MagicMock(), ) api.data_received(data) assert t.deserialize.call_count == 0 t.deserialize.reset_mock()
def test_tx_status(value, name): """Test tx status undefined values.""" i = deconz_api.TXStatus(value) assert i == value assert i.value == value assert i.name == name extra = b"\xaa\55" data = t.uint8_t(value).serialize() status, rest = deconz_api.TXStatus.deserialize(data + extra) assert rest == extra assert isinstance(status, deconz_api.TXStatus) assert status == value assert status.value == value assert status.name == name
def test_data_received_unk_cmd(api, monkeypatch): monkeypatch.setattr( t, "deserialize", MagicMock(return_value=(sentinel.deserialize_data, b"")), ) for cmd_id in range(253, 255): payload = b"\x01\x02\x03\x04" status = t.uint8_t(0x00).serialize() data = cmd_id.to_bytes( 1, "big") + b"\x00" + status + b"\x00\x00" + payload api._awaiting[0] = (MagicMock(), ) api.data_received(data) assert t.deserialize.call_count == 0 t.deserialize.reset_mock()
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=10): LOGGER.debug("Zigbee request with id %s, data: %s", sequence, binascii.hexlify(data)) assert sequence not in self._pending send_fut = asyncio.Future() reply_fut = None if expect_reply: reply_fut = asyncio.Future() self._pending[sequence] = (send_fut, reply_fut) dst_addr = t.DeconzAddress() dst_addr.address_mode = t.uint8_t(t.ADDRESS_MODE.NWK.value) dst_addr.address = t.uint16_t(nwk) await self._api.aps_data_request(sequence, dst_addr, dst_ep, profile, cluster, min(1, src_ep), data) try: r = await asyncio.wait_for(send_fut, SEND_CONFIRM_TIMEOUT) except asyncio.TimeoutError: self._pending.pop(sequence, None) LOGGER.warning( "Failed to receive transmit confirm for request id: %s", sequence) raise if r: LOGGER.warning("Error while sending frame: 0x%02x", r) if not expect_reply: self._pending.pop(sequence, None) return try: return await asyncio.wait_for(reply_fut, timeout) except asyncio.TimeoutError: self._pending.pop(sequence, None) raise
def test_data_received_unk_status(api, monkeypatch): monkeypatch.setattr( t, 'deserialize', mock.MagicMock(return_value=(mock.sentinel.deserialize_data, b''))) my_handler = mock.MagicMock() for cmd, cmd_opts in deconz_api.RX_COMMANDS.items(): _, unsolicited = cmd_opts payload = b'\x01\x02\x03\x04' status = t.uint8_t(0xfe).serialize() data = cmd.serialize() + b'\x00' + status + b'\x00\x00' + payload setattr(api, '_handle_{}'.format(cmd.name), my_handler) api._awaiting[0] = mock.MagicMock() api.data_received(data) assert t.deserialize.call_count == 1 assert t.deserialize.call_args[0][0] == payload if unsolicited: assert my_handler.call_count == 0 else: assert my_handler.call_count == 1 t.deserialize.reset_mock() my_handler.reset_mock()
def test_data_received_unk_status(api, monkeypatch): monkeypatch.setattr( t, "deserialize", MagicMock(return_value=(sentinel.deserialize_data, b"")), ) my_handler = MagicMock() for cmd, cmd_opts in deconz_api.RX_COMMANDS.items(): _, solicited = cmd_opts payload = b"\x01\x02\x03\x04" status = t.uint8_t(0xFE).serialize() data = cmd.serialize() + b"\x00" + status + b"\x00\x00" + payload setattr(api, "_handle_{}".format(cmd.name), my_handler) api._awaiting[0] = MagicMock() api.data_received(data) if solicited: assert my_handler.call_count == 0 assert t.deserialize.call_count == 0 else: assert t.deserialize.call_count == 1 assert my_handler.call_count == 1 t.deserialize.reset_mock() my_handler.reset_mock()
def serialize(self) -> bytes: """Serialize data.""" return t.uint8_t(self).serialize()