def test_join(app): payload = { "nwkaddr": 27441, "extaddr": "0x07a3c302008d1500", "parentaddr": 0 } obj = ZpiObject(2, 5, "tcDeviceInd", 202, payload, []) app.handle_znp(obj) print(app.devices) payload = { "groupid": 0, "clusterid": 6, "srcaddr": 27441, "srcendpoint": 1, "dstendpoint": 1, "wasbroadcast": 0, "linkquality": 136, "securityuse": 0, "timestamp": 15458350, "transseqnumber": 0, "len": 7, "data": bytearray(b"\x18\x0c\n\x00\x00\x10\x00"), } obj = ZpiObject(2, 4, "incomingMsg", 129, payload, []) app.handle_znp(obj)
def test_join(app): payload = {'nwkaddr': 27441, 'extaddr': '0x07a3c302008d1500', 'parentaddr': 0} obj = ZpiObject(2, 5, 'tcDeviceInd', 202, payload, []) app.handle_znp(obj) print(app.devices) payload = {'groupid': 0, 'clusterid': 6, 'srcaddr': 27441, 'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 136, 'securityuse': 0, 'timestamp': 15458350, 'transseqnumber': 0, 'len': 7, 'data': bytearray(b'\x18\x0c\n\x00\x00\x10\x00')} obj = ZpiObject(2, 4, 'incomingMsg', 129, payload, []) app.handle_znp(obj)
def test_from_cluster_id_ZCL(): profile = 260 obj = ZpiObject.from_cluster(t.NWK(53322), profile, 0, 1, 1, 1, b'\x00\x0b\x00\x04\x00\x05\x00', 123) assert "SREQ AF dataRequest tsn: 1 {'dstaddr': 53322, 'destendpoint': 1, 'srcendpoint': 1, " \ "'clusterid': 0, 'transid': 123, 'options': 0, 'radius': 30, 'len': 7, " \ "'data': b'\\x00\\x0b\\x00\\x04\\x00\\x05\\x00'}" == str(obj)
def data_received(self, frame): try: obj = ZpiObject.from_unpi_frame(frame) except Exception as e: LOGGER.error("Error while parsing frame: %s", frame) raise e for waiter_id in list(self._waiters): waiter = self._waiters.get(waiter_id) if waiter.match(obj): self._waiters.pop(waiter_id) waiter.set_result(obj) if waiter.sequence: obj.sequence = waiter.sequence break LOGGER.debug("<-- %s", obj) if self._app is not None: self._app.handle_znp(obj) try: getattr(self, "_handle_%s" % (obj.command, ))(obj) except AttributeError: pass
def test_data_received(api, monkeypatch): monkeypatch.setattr( t, "deserialize", mock.MagicMock(return_value=(mock.sentinel.deserialize_data, b"")), ) my_handler = mock.MagicMock() data = UnpiFrame(3, 1, 2, b"\x02\x00\x02\x06\x03\x90\x154\x01\x02\x01\x00\x00\x00") setattr(api, "_handle_version", 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 assert my_handler.call_count == 1 assert str(my_handler.call_args[0][0]) == str( ZpiObject( 3, 1, "version", 2, { 'transportrev': 2, 'product': 0, 'majorrel': 2, 'minorrel': 6, 'maintrel': 3, 'revision': 20190608 }, []))
def test_ieee_addr(): # 3 - 7 - 0 - 18 - [bytearray(b'\x00\x0c%\xed\x18\x00K\x12\x00\x00\x00\x07\t\x02J\xd0]\x97')] - 172 frame = uart.UnpiFrame(3, 7, 0, b'\x00\x0c%\xed\x18\x00K\x12\x00\x00\x00\x07\t\x02J\xd0]\x97') obj = ZpiObject.from_unpi_frame(frame) out = obj.to_unpi_frame() assert out.data == b'\x00\x00\x12K\x00\x18\xed%\x0c\x00\x00\x07\t\x02J\xd0]\x97'
def test_from_unpi_frame3(): payload = { "groupid":0, "clusterid":0, "srcaddr":44052, "srcendpoint":1, "dstendpoint":1, "wasbroadcast":0, "linkquality":78, "securityuse":0, "timestamp":2206697, "transseqnumber":0, "len":55, "data":bytes([24,2,1,5,0,0,66,23,84,82,65,68,70,82,73,32,119,105,114,101,108,101,115,115,32,100,105,109,109,101,114,4,0,0,66,14,73,75,69,65,32,111,102,32,83,119,101,100,101,110,7,0,0,48,3]) } obj = ZpiObject.from_command( t.CommandType.AREQ, t.Subsystem.AF, 'incomingMsg', payload ) assert "AREQ AF incomingMsg tsn: None {'groupid': 0, 'clusterid': 0, 'srcaddr': 44052, " \ "'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 78, " \ "'securityuse': 0, 'timestamp': 2206697, 'transseqnumber': 0, 'len': 55, " \ "'data': b'\\x18\\x02\\x01\\x05\\x00\\x00B\\x17TRADFRI wireless dimmer\\x04\\x00\\x00B\\x0eIKEA of Sweden\\x07\\x00\\x000\\x03'}" == str(obj)
async def test_get_node_descriptor(app: application.ControllerApplication): await device_annce(app) device = app.get_device(nwk=53322) fut = asyncio.Future() fut.set_result([0, "message send success"]) app._api.request_raw = mock.MagicMock(return_value=fut) payload = { "srcaddr": 53322, "status": 0, "nwkaddr": 0, "logicaltype_cmplxdescavai_userdescavai": 0, "apsflags_freqband": 0, "maccapflags": 0, "manufacturercode": 1234, "maxbuffersize": 0, "maxintransfersize": 0, "servermask": 0, "maxouttransfersize": 0, "descriptorcap": 0, } obj = ZpiObject.from_command(5, "nodeDescRsp", payload) frame = obj.to_unpi_frame() async def nested(): await asyncio.sleep(0) app._api.data_received(frame) await asyncio.wait([device.get_node_descriptor(), nested()], timeout=0.2) assert isinstance(device.node_desc, zdo_t.NodeDescriptor) assert 1234 == device.node_desc.manufacturer_code
def test_ieee_addr(): frame = uart.UnpiFrame( 3, 7, 0, b"\x00\x0c%\xed\x18\x00K\x12\x00\x00\x00\x07\t\x02J\xd0]\x97") obj = ZpiObject.from_unpi_frame(frame) out = obj.to_unpi_frame() assert out.data == b"\x00\x00\x12K\x00\x18\xed%\x0c\x00\x00\x07\t\x02J\xd0]\x97"
def test_mgmt_lqi_rsp(): frame = uart.UnpiFrame( 2, 5, 177, b"\x00\x00\x00\x14\x00\x03\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\x1d$&\xfe\xffW\xb4\x14\xef>\x15\x02\x01\x00\xdd" b"\xdd\xdd\xdd\xdd\xdd\xdd\xdd\x9atk\x03\x00\x8d\x15\x00}0\x12\x02\x01`\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\x8d(," b"\x03\x00\x8d\x15\x00}\xcc\x12\x02\x017", 72, 34, ) obj = ZpiObject.from_unpi_frame(frame) assert ( "AREQ ZDO mgmtLqiRsp tsn: None {" "'srcaddr': 0x0000, " "'status': 0, " "'neighbortableentries': 20, " "'startindex': 0, " "'neighborlqilistcount': 3, " "'neighborlqilist': [" "{'extPanId': dd:dd:dd:dd:dd:dd:dd:dd, 'extAddr': 14:b4:57:ff:fe:26:24:1d, 'nwkAddr': 0x3EEF, " "'deviceType': 1, 'rxOnWhenIdle': 1, 'relationship': 1, 'permitJoin': 2, 'depth': 1, 'lqi': 0}, " "{'extPanId': dd:dd:dd:dd:dd:dd:dd:dd, 'extAddr': 00:15:8d:00:03:6b:74:9a, 'nwkAddr': 0x307D, " "'deviceType': 2, 'rxOnWhenIdle': 0, 'relationship': 1, 'permitJoin': 2, 'depth': 1, 'lqi': 96}, " "{'extPanId': dd:dd:dd:dd:dd:dd:dd:dd, 'extAddr': 00:15:8d:00:03:2c:28:8d, 'nwkAddr': 0xCC7D, " "'deviceType': 2, 'rxOnWhenIdle': 0, 'relationship': 1, 'permitJoin': 2, 'depth': 1, 'lqi': 55}" "]}" == str(obj) )
def test_bind_req(): ''' zigpy_cc.zigbee.application DEBUG request ( 0xbd8b, 0, <ZDOCmd.Bind_req: 0x0021>, 0, 0, 1, b"\x01<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01", True, False) zigpy_cc.api DEBUG waiting for 1 bindReq zigpy_cc.api DEBUG --> SREQ ZDO bindReq tsn: 1 { 'dstaddr': 0xbd8b, 'srcaddr': 00:0b:57:ff:fe:27:78:3c, 'srcendpoint': 1, 'clusterid': 8, 'dstaddrmode': 3, 'dstaddress': 00:12:4b:00:18:ed:25:0c, 'dstendpoint': 1} zigpy_cc.uart DEBUG Send: b"\xfe\x17%!\x8b\xbd<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01\x95" ''' data = b"\x02<x'\xfe\xffW\x0b\x00\x01\x08\x00\x03\x0c%\xed\x18\x00K\x12\x00\x01" obj = ZpiObject.from_cluster( NWK(0x6292), 0, 0x0021, 0, 0, 2, data, 123 ) assert ( "SREQ ZDO bindReq tsn: 2 {" "'dstaddr': 0x6292, " "'srcaddr': 00:0b:57:ff:fe:27:78:3c, " "'srcendpoint': 1, " "'clusterid': 8, " "'dstaddrmode': 3, " "'dstaddress': 00:12:4b:00:18:ed:25:0c, " "'dstendpoint': 1}" == str(obj) ) assert ( bytes( [254, 23, 37, 33, 146, 98, 60, 120, 39, 254, 255, 87, 11, 0, 1, 8, 0, 3, 12, 37, 237, 24, 0, 75, 18, 0, 1, 83]) == obj.to_unpi_frame().to_buffer() )
def test_bind_req_serialize(): payload = {"dstaddr": NWK(25234), "srcaddr": EUI64(reversed(b'\x00\x0b\x57\xff\xfe\x27\x78\x3c')), "srcendpoint": 1, "clusterid": 8, "dstaddrmode": 3, "dstaddress": EUI64(reversed(b'\x00\x12\x4b\x00\x18\xed\x25\x0c')), "dstendpoint": 1} obj = ZpiObject.from_command(t.Subsystem.ZDO, 'bindReq', payload) assert ( "SREQ ZDO bindReq tsn: None {" "'dstaddr': 0x6292, " "'srcaddr': 00:0b:57:ff:fe:27:78:3c, " "'srcendpoint': 1, " "'clusterid': 8, " "'dstaddrmode': 3, " "'dstaddress': 00:12:4b:00:18:ed:25:0c, " "'dstendpoint': 1}" == str(obj) ) assert ( bytes( [254, 23, 37, 33, 146, 98, 60, 120, 39, 254, 255, 87, 11, 0, 1, 8, 0, 3, 12, 37, 237, 24, 0, 75, 18, 0, 1, 83]) == obj.to_unpi_frame().to_buffer() )
async def test_get_node_descriptor(app: application.ControllerApplication): await device_annce(app) device = app.get_device(nwk=53322) fut = asyncio.Future() fut.set_result([0, 'message send success']) app._api.request_raw = mock.MagicMock(return_value=fut) payload = {'srcaddr': 53322, 'status': 0, 'nwkaddr': 0, 'logicaltype_cmplxdescavai_userdescavai': 0, 'apsflags_freqband': 0, 'maccapflags': 0, 'manufacturercode': 1234, 'maxbuffersize': 0, 'maxintransfersize': 0, 'servermask': 0, 'maxouttransfersize': 0, 'descriptorcap': 0} obj = ZpiObject.from_command(2, 5, 'nodeDescRsp', payload) frame = obj.to_unpi_frame() async def nested(): await asyncio.sleep(0) app._api.data_received(frame) await asyncio.wait([ device.get_node_descriptor(), nested(), ], timeout=0.2) assert isinstance(device.node_desc, zdo_t.NodeDescriptor) assert device.node_desc.manufacturer_code == 1234
def test_from_cluster_id(): profile = 0 obj = ZpiObject.from_cluster(NWK(53322), profile, ZDOCmd.Node_Desc_req, 0, 0, 0, b"\x03\x4a\xd0", 32) assert ( "SREQ ZDO nodeDescReq tsn: 0 {'dstaddr': 0xd04a, 'nwkaddrofinterest': 0xd04a}" == str(obj))
async def request(self, subsystem, command, payload, waiter_id=None, expected_status=None): obj = ZpiObject.from_command(subsystem, command, payload) return await self.request_raw(obj, waiter_id, expected_status)
async def device_annce(app: application.ControllerApplication): # payload = {'nwkaddr': 27441, 'extaddr': '0x07a3c302008d1500', 'parentaddr': 0} # obj = ZpiObject(2, 5, 'tcDeviceInd', 202, payload, []) payload = {'srcaddr': 53322, 'nwkaddr': 53322, 'ieeeaddr': 0x41e54b02008d1500.to_bytes(8, 'little'), 'capabilities': 132} obj = ZpiObject(2, 5, 'endDeviceAnnceInd', 193, payload, []) app.handle_znp(obj)
async def broadcast( self, profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address=zigpy.types.BroadcastAddress.RX_ON_WHEN_IDLE, ): LOGGER.debug( "broadcast %s", ( profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address, ), ) try: obj = ZpiObject.from_cluster( broadcast_address, profile, cluster, src_ep, dst_ep, sequence, data, radius=radius, addr_mode=AddressMode.ADDR_16BIT, ) async with self._semaphore: await self._api.request_raw(obj) """ As a broadcast command is not confirmed and thus immediately returns (contrary to network address requests) we will give the command some time to 'settle' in the network. """ await asyncio.sleep(0.2) except CommandError as ex: return ( ex.status, "Couldn't enqueue send data request for broadcast: {}".format( ex), ) return 0, "broadcast send success"
async def _request_raw(self, obj: ZpiObject, waiter_id=None, expected_status=None): if expected_status is None: expected_status = [0] LOGGER.debug("--> %s", obj) frame = obj.to_unpi_frame() if obj.command_type == CommandType.SREQ: timeout = (20000 if obj.command == "bdbStartCommissioning" or obj.command == "startupFromApp" else Timeouts.SREQ) waiter = self.wait_for(CommandType.SRSP, obj.subsystem, obj.command, {}, timeout) self._uart.send(frame) result = await waiter.wait() if (result and "status" in result.payload and result.payload["status"] not in expected_status): if waiter_id is not None: self._waiters.pop(waiter_id).set_result(result) raise CommandError( result.payload["status"], "SREQ '{}' failed with status '{}' (expected '{}')".format( obj.command, result.payload["status"], expected_status), ) else: return result elif obj.command_type == CommandType.AREQ and obj.is_reset_command(): waiter = self.wait_for(CommandType.AREQ, Subsystem.SYS, "resetInd", {}, Timeouts.reset) # TODO clear queue, requests waiting for lock self._uart.send(frame) return await waiter.wait() else: if obj.command_type == CommandType.AREQ: self._uart.send(frame) return None else: LOGGER.warning("Unknown type '%s'", obj.command_type) raise Exception("Unknown type '{}'".format(obj.command_type))
def test_from_unpi_frame2(): frame = uart.UnpiFrame( 2, 4, 129, b'\x00\x00\x01\x00\xbbm\x01\x01\x00s\x00YC3\x00\x00\t\x18\x01\x01\x04\x00\x86\x05\x00\x86\xbbm\x1d' ) obj = ZpiObject.from_unpi_frame(frame) assert "AREQ AF incomingMsg tsn: None {'groupid': 0, 'clusterid': 1, 'srcaddr': 0x6dbb, " \ "'srcendpoint': 1, 'dstendpoint': 1, 'wasbroadcast': 0, 'linkquality': 115, " \ "'securityuse': 0, 'timestamp': 3359577, 'transseqnumber': 0, 'len': 9, " \ "'data': b'\\x18\\x01\\x01\\x04\\x00\\x86\\x05\\x00\\x86'}" == str(obj)
async def device_annce(app: application.ControllerApplication): # payload = {'nwkaddr': 27441, 'extaddr': '0x07a3c302008d1500', 'parentaddr': 0} # obj = ZpiObject(2, 5, 'tcDeviceInd', 202, payload, []) payload = { "srcaddr": 53322, "nwkaddr": 53322, "ieeeaddr": 0x41E54B02008D1500.to_bytes(8, "little"), "capabilities": 132, } obj = ZpiObject(2, 5, "endDeviceAnnceInd", 193, payload, []) app.handle_znp(obj)
async def mrequest(self, group_id, profile, cluster, src_ep, sequence, data, *, hops=0, non_member_radius=3): """Submit and send data out as a multicast transmission. :param group_id: destination multicast address :param profile: Zigbee Profile ID to use for outgoing message :param cluster: cluster id where the message is being sent :param src_ep: source endpoint id :param sequence: transaction sequence number of the message :param data: Zigbee message payload :param hops: the message will be delivered to all nodes within this number of hops of the sender. A value of zero is converted to MAX_HOPS :param non_member_radius: the number of hops that the message will be forwarded by devices that are not members of the group. A value of 7 or greater is treated as infinite :returns: return a tuple of a status and an error_message. Original requestor has more context to provide a more meaningful error message """ req_id = self.get_sequence() LOGGER.debug( "multicast %s", ( group_id, profile, cluster, src_ep, sequence, data, hops, non_member_radius, ), ) try: obj = ZpiObject.from_cluster(group_id, profile, cluster, src_ep, src_ep, sequence, data, req_id) await self._api.request_raw(obj) except CommandError as ex: return ex.status, "Couldn't enqueue send data multicast: {}".format( ex) return 0, "message send success"
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( "broadcast %s", ( profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address, ), ) try: obj = ZpiObject.from_cluster( broadcast_address, profile, cluster, src_ep, dst_ep, sequence, data, req_id, radius=radius, ) await self._api.request_raw(obj) except CommandError as ex: return ( ex.status, "Couldn't enqueue send data request for broadcast: {}".format( ex), ) return 0, "broadcast send success"
def test_from_unpi_frame(): frame = uart.UnpiFrame(3, 1, 2, b"\x02\x00\x02\x06\x03\x90\x154\x01") extra = { "maintrel": 3, "majorrel": 2, "minorrel": 6, "product": 0, "revision": 20190608, "transportrev": 2, } obj = ZpiObject.from_unpi_frame(frame) assert obj.command == "version" assert obj.payload == extra assert str(obj.to_unpi_frame()) == str(frame)
def test_mgmt_nwk_update_notify(): frame = uart.UnpiFrame( 2, 5, 184, b"\xe9\xc0\x00\x00\xf8\xff\x07\x14\x00\x0f\x00\x10\xd6\xac" b"\xcc\xb0\xb5\xa2\xb2\xa5\xb3\xa5\xa2\xa9\xa1\xa1\xa5\xae", 28, 211, ) obj = ZpiObject.from_unpi_frame(frame) assert ( "AREQ ZDO mgmtNwkUpdateNotify tsn: None {'srcaddr': 0xc0e9, 'status': 0, 'scanchannels': 134215680, " "'totaltransmissions': 20, 'transmissionfailures': 15, 'channelcount': 16, " "'energyvalues': [214, 172, 204, 176, 181, 162, 178, 165, 179, 165, 162, 169, 161, 161, 165, 174]" "}" == str(obj))
def test_from_unpi_frame(): frame = uart.UnpiFrame(3, 1, 2, b"\x02\x00\x02\x06\x03\x90\x154\x01") extra = { 'maintrel': 3, 'majorrel': 2, 'minorrel': 6, 'product': 0, 'revision': 20190608, 'transportrev': 2, } obj = ZpiObject.from_unpi_frame(frame) assert obj.command == 'version' assert obj.payload == extra assert str(obj.to_unpi_frame()) == str(frame)
async def request( self, device, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, use_ieee=False, ): LOGGER.debug( "request %s", ( device.nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply, use_ieee, ), ) try: obj = ZpiObject.from_cluster(device.nwk, profile, cluster, src_ep, dst_ep, sequence, data) waiter_id = None if expect_reply: waiter = self._api.create_response_waiter(obj, sequence) if waiter: waiter_id = waiter.id async with self._semaphore: await self._api.request_raw(obj, waiter_id) except CommandError as ex: return ex.status, "Couldn't enqueue send data request: {}".format( ex) return 0, "message send success"
def handle_znp(self, obj: ZpiObject): if obj.type != t.CommandType.AREQ: return # if obj.subsystem == t.Subsystem.ZDO and obj.command == 'tcDeviceInd': # nwk = obj.payload['nwkaddr'] # rest = obj.payload['extaddr'][2:].encode("ascii") # ieee, _ = zigpy.types.EUI64.deserialize(rest) # LOGGER.info("New device joined: 0x%04x, %s", nwk, ieee) # self.handle_join(nwk, ieee, obj.payload['parentaddr']) frame = obj.to_unpi_frame() nwk = obj.payload["srcaddr"] if "srcaddr" in obj.payload else None ieee = obj.payload["ieeeaddr"] if "ieeeaddr" in obj.payload else None profile_id = zha.PROFILE_ID src_ep = 0 dst_ep = 0 lqi = 0 rssi = 0 if obj.subsystem == t.Subsystem.ZDO and obj.command == "endDeviceAnnceInd": nwk = obj.payload["nwkaddr"] LOGGER.info("New device joined: 0x%04x, %s", nwk, ieee) self.handle_join(nwk, ieee, 0) # TODO TEST obj.sequence = 0 # TODO bindRsp if obj.command in IGNORED: LOGGER.debug("message ignored: %s", obj.command) return if obj.subsystem == t.Subsystem.ZDO and obj.command == "permitJoinInd": # if obj.payload["duration"] == 0: # loop = asyncio.get_event_loop() # loop.create_task(self.permit_ncp()) return if obj.subsystem == t.Subsystem.ZDO and obj.command in REQUESTS: if obj.sequence is None: LOGGER.warning("missing tsn from %s, maybe not a reply", obj.command) return LOGGER.info("REPLY for %d %s", obj.sequence, obj.command) cluster_id, prefix_length = REQUESTS[obj.command] tsn = bytes([obj.sequence]) data = tsn + frame.data[prefix_length:] elif obj.subsystem == t.Subsystem.AF and (obj.command == "incomingMsg" or obj.command == "incomingMsgExt"): # ZCL commands cluster_id = obj.payload["clusterid"] src_ep = obj.payload["srcendpoint"] dst_ep = obj.payload["dstendpoint"] data = obj.payload["data"] lqi = obj.payload["linkquality"] else: LOGGER.warning("Unhandled message: %s %s", t.Subsystem(obj.subsystem), obj.command) return try: if ieee: device = self.get_device(ieee=ieee) else: device = self.get_device(nwk=nwk) except KeyError: LOGGER.warning("Received frame from unknown device: %s", ieee if ieee else nwk) return device.radio_details(lqi, rssi) # if obj.subsystem == t.Subsystem.ZDO: # pass LOGGER.info("handle_message %s", obj.command) self.handle_message(device, profile_id, cluster_id, src_ep, dst_ep, data)
async def mrequest(self, group_id, profile, cluster, src_ep, sequence, data, *, hops=0, non_member_radius=3): """Submit and send data out as a multicast transmission. :param group_id: destination multicast address :param profile: Zigbee Profile ID to use for outgoing message :param cluster: cluster id where the message is being sent :param src_ep: source endpoint id :param sequence: transaction sequence number of the message :param data: Zigbee message payload :param hops: the message will be delivered to all nodes within this number of hops of the sender. A value of zero is converted to MAX_HOPS :param non_member_radius: the number of hops that the message will be forwarded by devices that are not members of the group. A value of 7 or greater is treated as infinite :returns: return a tuple of a status and an error_message. Original requestor has more context to provide a more meaningful error message """ LOGGER.debug( "multicast %s", ( group_id, profile, cluster, src_ep, sequence, data, hops, non_member_radius, ), ) try: obj = ZpiObject.from_cluster( group_id, profile, cluster, src_ep or 1, 0xFF, sequence, data, addr_mode=AddressMode.ADDR_GROUP, ) waiter_id = None waiter = self._api.create_response_waiter(obj, sequence) if waiter: waiter_id = waiter.id async with self._semaphore: await self._api.request_raw(obj, waiter_id) """ As a group command is not confirmed and thus immediately returns (contrary to network address requests) we will give the command some time to 'settle' in the network. """ await asyncio.sleep(0.2) except CommandError as ex: return ex.status, "Couldn't enqueue send data multicast: {}".format( ex) return 0, "message send success"
def handle_znp(self, obj: ZpiObject): if obj.type != t.CommandType.AREQ: return # if obj.subsystem == t.Subsystem.ZDO and obj.command == 'tcDeviceInd': # nwk = obj.payload['nwkaddr'] # rest = obj.payload['extaddr'][2:].encode("ascii") # ieee, _ = zigpy.types.EUI64.deserialize(rest) # LOGGER.info("New device joined: 0x%04x, %s", nwk, ieee) # self.handle_join(nwk, ieee, obj.payload['parentaddr']) frame = obj.to_unpi_frame() nwk = obj.payload['srcaddr'] if 'srcaddr' in obj.payload else None ieee = obj.payload['ieeeaddr'] if 'ieeeaddr' in obj.payload else None profile_id = zha.PROFILE_ID src_ep = 0 dst_ep = 0 lqi = 0 rssi = 0 if obj.subsystem == t.Subsystem.ZDO and obj.command == 'endDeviceAnnceInd': nwk = obj.payload['nwkaddr'] LOGGER.info("New device joined: 0x%04x, %s", nwk, ieee) self.handle_join(nwk, ieee, 0) # TODO TEST obj.sequence = 0 if obj.subsystem == t.Subsystem.ZDO and obj.command in REQUESTS: if obj.sequence is None: LOGGER.warning("missing tsn from %s, maybe not a reply", obj.command) return cluster_id, prefix_length = REQUESTS[obj.command] LOGGER.info("REPLY for %d %s", obj.sequence, obj.command) tsn = bytes([obj.sequence]) data = tsn + frame.data[prefix_length:] elif obj.subsystem == t.Subsystem.AF and (obj.command == 'incomingMsg' or obj.command == 'incomingMsgExt'): # ZCL commands cluster_id = obj.payload['clusterid'] src_ep = obj.payload['srcendpoint'] dst_ep = obj.payload['dstendpoint'] data = obj.payload['data'] lqi = obj.payload['linkquality'] elif obj.command == 'stateChangeInd': LOGGER.info("State changed to: %s", obj.payload['state']) return else: LOGGER.warning("Unhandled message: %s %s", obj.subsystem, obj.command) return try: if ieee: device = self.get_device(ieee=ieee) else: device = self.get_device(nwk=nwk) except KeyError: LOGGER.debug("Received frame from unknown device: %s", ieee if ieee else nwk) return device.radio_details(lqi, rssi) if obj.subsystem == t.Subsystem.ZDO: pass LOGGER.info('handle_message %s', obj.command) self.handle_message(device, profile_id, cluster_id, src_ep, dst_ep, data)
def handle_znp(self, obj: ZpiObject): if obj.command_type != t.CommandType.AREQ: return frame = obj.to_unpi_frame() nwk = obj.payload["srcaddr"] if "srcaddr" in obj.payload else None ieee = obj.payload["ieeeaddr"] if "ieeeaddr" in obj.payload else None profile_id = zha.PROFILE_ID src_ep = 0 dst_ep = 0 lqi = 0 rssi = 0 if obj.subsystem == t.Subsystem.ZDO and obj.command == "endDeviceAnnceInd": nwk = obj.payload["nwkaddr"] LOGGER.info("New device joined: 0x%04x, %s", nwk, ieee) self.handle_join(nwk, ieee, 0) obj.sequence = 0 if obj.command in IGNORED: return if obj.subsystem == t.Subsystem.ZDO and obj.command == "mgmtPermitJoinRsp": self.set_led(LedMode.On) if obj.subsystem == t.Subsystem.ZDO and obj.command == "permitJoinInd": self.set_led(LedMode.Off if obj.payload["duration"] == 0 else LedMode.On) return if obj.subsystem == t.Subsystem.ZDO and obj.command in REQUESTS: if obj.sequence is None: return LOGGER.debug("REPLY for %d %s", obj.sequence, obj.command) cluster_id, prefix_length = REQUESTS[obj.command] tsn = bytes([obj.sequence]) data = tsn + frame.data[prefix_length:] elif obj.subsystem == t.Subsystem.AF and (obj.command == "incomingMsg" or obj.command == "incomingMsgExt"): # ZCL commands cluster_id = obj.payload["clusterid"] src_ep = obj.payload["srcendpoint"] dst_ep = obj.payload["dstendpoint"] data = obj.payload["data"] lqi = obj.payload["linkquality"] else: LOGGER.warning( "Unhandled message: %s %s %s", t.CommandType(obj.command_type), t.Subsystem(obj.subsystem), obj.command, ) return try: if ieee: device = self.get_device(ieee=ieee) else: device = self.get_device(nwk=nwk) except KeyError: LOGGER.warning("Received frame from unknown device: %s", ieee if ieee else nwk) return device.radio_details(lqi, rssi) LOGGER.info("handle_message %s", obj.command) self.handle_message(device, profile_id, cluster_id, src_ep, dst_ep, data)