async def subscribe(self, group_id) -> t.EmberStatus: if group_id in self._multicast: LOGGER.debug("%s is already subscribed", t.EmberMulticastId(group_id)) return t.EmberStatus.SUCCESS try: idx = self._available.pop() except KeyError: LOGGER.error("No more available slots MulticastId subscription") return t.EmberStatus.INDEX_OUT_OF_RANGE entry = t.EmberMulticastTableEntry() entry.endpoint = t.uint8_t(1) entry.multicastId = t.EmberMulticastId(group_id) entry.networkIndex = t.uint8_t(0) status = await self._ezsp.setMulticastTableEntry(idx, entry) if status[0] != t.EmberStatus.SUCCESS: LOGGER.warning( "Set MulticastTableEntry #%s for %s multicast id: %s", idx, entry.multicastId, status) self._available.add(idx) return status[0] self._multicast[entry.multicastId] = (entry, idx) LOGGER.debug("Set MulticastTableEntry #%s for %s multicast id: %s", idx, entry.multicastId, status) return status[0]
async def form_network(self): nwk = self.config[zigpy.config.CONF_NWK] pan_id = nwk[zigpy.config.CONF_NWK_PAN_ID] if pan_id is None: pan_id = int.from_bytes(os.urandom(2), byteorder="little") extended_pan_id = nwk[zigpy.config.CONF_NWK_EXTENDED_PAN_ID] if extended_pan_id is None: extended_pan_id = t.EmberEUI64([t.uint8_t(0)] * 8) hashed_tclk = self._ezsp.ezsp_version > 4 initial_security_state = bellows.zigbee.util.zha_security( nwk, controller=True, hashed_tclk=hashed_tclk) v = await self._ezsp.setInitialSecurityState(initial_security_state) assert v[0] == t.EmberStatus.SUCCESS # TODO: Better check parameters = t.EmberNetworkParameters() parameters.panId = t.EmberPanId(pan_id) parameters.extendedPanId = extended_pan_id parameters.radioTxPower = t.uint8_t(8) parameters.radioChannel = t.uint8_t(nwk[zigpy.config.CONF_NWK_CHANNEL]) parameters.joinMethod = t.EmberJoinMethod.USE_MAC_ASSOCIATION parameters.nwkManagerId = t.EmberNodeId(0) parameters.nwkUpdateId = t.uint8_t( nwk[zigpy.config.CONF_NWK_UPDATE_ID]) parameters.channels = nwk[zigpy.config.CONF_NWK_CHANNELS] await self._ezsp.formNetwork(parameters) await self._ezsp.setValue( self._ezsp.types.EzspValueId.VALUE_STACK_TOKEN_WRITING, 1)
async def broadcast(self, profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address=BroadcastAddress.RX_ON_WHEN_IDLE): if not self.is_controller_running: raise ControllerError("ApplicationController is not running") aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_NONE ) aps_frame.groupId = t.uint16_t(grpid) aps_frame.sequence = t.uint8_t(sequence) with self._pending.new(sequence) as req: async with self._in_flight_msg: res = await self._ezsp.sendBroadcast(broadcast_address, aps_frame, radius, sequence, data) if res[0] != t.EmberStatus.SUCCESS: hdr, hdr_args = self._dst_pp(broadcast_address, aps_frame) msg = hdr + "Broadcast failure: %s" msg_args = (hdr_args + (res[0], )) raise DeliveryError(msg % msg_args) # Wait for messageSentHandler message res = await asyncio.wait_for(req.send, timeout=APS_ACK_TIMEOUT) return res
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=APS_REPLY_TIMEOUT): if not self.is_controller_running: raise ControllerError("ApplicationController is not running") aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY ) aps_frame.groupId = t.uint16_t(0) aps_frame.sequence = t.uint8_t(sequence) with self._pending.new(sequence, expect_reply) as req: async with self._in_flight_msg: res = await self._ezsp.sendUnicast(self.direct, nwk, aps_frame, sequence, data) if res[0] != t.EmberStatus.SUCCESS: hdr, hdr_args = self._dst_pp(nwk, aps_frame) msg = hdr + "message send failure: %s" msg_args = (hdr_args + (res[0], )) raise DeliveryError(msg % msg_args) res = await asyncio.wait_for(req.send, timeout=APS_ACK_TIMEOUT) if expect_reply: res = await asyncio.wait_for(req.reply, timeout) return res
def zha_security(controller=False): empty_key_data = t.EmberKeyData() empty_key_data.contents = t.fixed_list(16, t.uint8_t)([t.uint8_t(0)] * 16) zha_key = t.EmberKeyData() zha_key.contents = t.fixed_list( 16, t.uint8_t)([t.uint8_t(c) for c in b"ZigBeeAlliance09"]) isc = t.EmberInitialSecurityState() isc.bitmask = t.uint16_t( t.EmberInitialSecurityBitmask.HAVE_PRECONFIGURED_KEY | t.EmberInitialSecurityBitmask.REQUIRE_ENCRYPTED_KEY) isc.preconfiguredKey = zha_key isc.networkKey = empty_key_data isc.networkKeySequenceNumber = t.uint8_t(0) isc.preconfiguredTrustCenterEui64 = t.EmberEUI64([t.uint8_t(0)] * 8) if controller: isc.bitmask |= ( t.EmberInitialSecurityBitmask.TRUST_CENTER_GLOBAL_LINK_KEY | t.EmberInitialSecurityBitmask.HAVE_NETWORK_KEY) isc.bitmask = t.uint16_t(isc.bitmask) random_key = t.fixed_list( 16, t.uint8_t)([t.uint8_t(x) for x in os.urandom(16)]) isc.networkKey = random_key return isc
async def form_network(self, channel=15, pan_id=None, extended_pan_id=None): channel = t.uint8_t(channel) if pan_id is None: pan_id = t.uint16_t.from_bytes(os.urandom(2), 'little') pan_id = t.uint16_t(pan_id) if extended_pan_id is None: extended_pan_id = t.fixed_list(8, t.uint8_t)([t.uint8_t(0)] * 8) initial_security_state = bellows.zigbee.util.zha_security( controller=True) v = await self._ezsp.setInitialSecurityState(initial_security_state) assert v[0] == t.EmberStatus.SUCCESS # TODO: Better check parameters = t.EmberNetworkParameters() parameters.panId = pan_id parameters.extendedPanId = extended_pan_id parameters.radioTxPower = t.uint8_t(8) parameters.radioChannel = channel parameters.joinMethod = t.EmberJoinMethod.USE_MAC_ASSOCIATION parameters.nwkManagerId = t.EmberNodeId(0) parameters.nwkUpdateId = t.uint8_t(0) parameters.channels = t.uint32_t(0) await self._ezsp.formNetwork(parameters) await self._ezsp.setValue(t.EzspValueId.VALUE_STACK_TOKEN_WRITING, 1)
async def mock_get(*args): nonlocal group_id entry = t.EmberMulticastTableEntry() entry.endpoint = t.uint8_t(group_id % 3 + 1) entry.multicastId = t.EmberMulticastId(group_id) entry.networkIndex = t.uint8_t(0) group_id += 1 return [t.EmberStatus.ERR_FATAL, entry]
async def request( self, device, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, use_ieee=False, ): """Submit and send data out as an unicast transmission. :param device: destination device :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 dst_ep: destination endpoint id :param sequence: transaction sequence number of the message :param data: Zigbee message payload :param expect_reply: True if this is essentially a request :param use_ieee: use EUI64 for destination addressing :returns: return a tuple of a status and an error_message. Original requestor has more context to provide a more meaningful error message """ if not self.is_controller_running: raise ControllerError("ApplicationController is not running") aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY) aps_frame.groupId = t.uint16_t(0) aps_frame.sequence = t.uint8_t(sequence) message_tag = self.get_sequence() if use_ieee: LOGGER.warning(("EUI64 addressing is not currently supported, " "reverting to NWK")) if expect_reply and device.node_desc.is_end_device in (True, None): LOGGER.debug("Extending timeout for %s/0x%04x", device.ieee, device.nwk) await self._ezsp.setExtendedTimeout(device.ieee, True) with self._pending.new(message_tag) as req: async with self._in_flight_msg: res = await self._ezsp.sendUnicast(self.direct, device.nwk, aps_frame, message_tag, data) if res[0] != t.EmberStatus.SUCCESS: return res[0], "EZSP sendUnicast failure: %s" % (res[0], ) res = await asyncio.wait_for(req.result, APS_ACK_TIMEOUT) return res
def get_aps(self, profile, cluster, endpoint): f = t.EmberApsFrame() f.profileId = t.uint16_t(profile) f.clusterId = t.uint16_t(cluster) f.sourceEndpoint = t.uint8_t(endpoint) f.destinationEndpoint = t.uint8_t(endpoint) f.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY) f.groupId = t.uint16_t(0) f.sequence = t.uint8_t(self._application.get_sequence()) return f
async def broadcast( self, profile, cluster, src_ep, dst_ep, grpid, radius, sequence, data, broadcast_address=BroadcastAddress.RX_ON_WHEN_IDLE, ): """Submit and send data out as an unicast transmission. :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 dst_ep: destination endpoint id :param: grpid: group id to address the broadcast to :param radius: max radius of the broadcast :param sequence: transaction sequence number of the message :param data: zigbee message payload :param timeout: how long to wait for transmission ACK :param broadcast_address: broadcast address. :returns: return a tuple of a status and an error_message. Original requestor has more context to provide a more meaningful error message """ if not self.is_controller_running: raise ControllerError("ApplicationController is not running") aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption.APS_OPTION_NONE aps_frame.groupId = t.uint16_t(grpid) aps_frame.sequence = t.uint8_t(sequence) message_tag = self.get_sequence() with self._pending.new(message_tag) as req: async with self._in_flight_msg: async with self._req_lock: res = await self._ezsp.sendBroadcast( broadcast_address, aps_frame, radius, message_tag, data) if res[0] != t.EmberStatus.SUCCESS: return res[0], "broadcast send failure" # Wait for messageSentHandler message res = await asyncio.wait_for(req.result, timeout=APS_ACK_TIMEOUT) return res
async def mrequest( self, group_id, profile, cluster, src_ep, sequence, data, *, hops=EZSP_DEFAULT_RADIUS, non_member_radius=EZSP_MULTICAST_NON_MEMBER_RADIUS ): """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 """ if not self.is_controller_running: raise ControllerError("ApplicationController is not running") aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(src_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY ) aps_frame.groupId = t.uint16_t(group_id) aps_frame.sequence = t.uint8_t(sequence) message_tag = self.get_sequence() with self._pending.new(message_tag) as req: async with self._in_flight_msg: res = await self._ezsp.sendMulticast( aps_frame, hops, non_member_radius, message_tag, data ) if res[0] != t.EmberStatus.SUCCESS: return res[0], "EZSP sendMulticast failure: %s" % (res[0],) res = await asyncio.wait_for(req.result, APS_ACK_TIMEOUT) return res
async def mock_get(*args): nonlocal group_id, mct entry = t.EmberMulticastTableEntry() if mct > 0: entry.endpoint = t.uint8_t(group_id % 3 + 1) else: entry.endpoint = t.uint8_t(0) entry.multicastId = t.EmberMulticastId(group_id) entry.networkIndex = t.uint8_t(0) group_id += 1 mct -= 1 return [t.EmberStatus.SUCCESS, entry]
def test_size_prefixed_simple_descriptor(): sd = types.SizePrefixedSimpleDescriptor() sd.endpoint = t.uint8_t(1) sd.profile = t.uint16_t(2) sd.device_type = t.uint16_t(3) sd.device_version = t.uint8_t(4) sd.input_clusters = t.LVList(t.uint16_t)([t.uint16_t(5), t.uint16_t(6)]) sd.output_clusters = t.LVList(t.uint16_t)([t.uint16_t(7), t.uint16_t(8)]) ser = sd.serialize() assert ser[0] == len(ser) - 1 sd2, data = types.SizePrefixedSimpleDescriptor.deserialize(ser) assert sd.input_clusters == sd2.input_clusters assert sd.output_clusters == sd2.output_clusters
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=10): 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) aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY) aps_frame.groupId = t.uint16_t(0) aps_frame.sequence = t.uint8_t(sequence) v = await self._ezsp.sendUnicast(self.direct, nwk, aps_frame, sequence, data) if v[0] != t.EmberStatus.SUCCESS: self._pending.pop(sequence) send_fut.cancel() if expect_reply: reply_fut.cancel() raise DeliveryError("Message send failure %s" % (v[0], )) # Wait for messageSentHandler message v = await send_fut if expect_reply: # Wait for reply try: v = await asyncio.wait_for(reply_fut, timeout) except: # noqa: E722 # If we timeout (or fail for any reason), clear the future self._pending.pop(sequence) raise return v
async def remove(service): """Remove a node from the network.""" from bellows.types import EmberEUI64, uint8_t ieee = service.data.get(ATTR_IEEE_ADDRESS) ieee = EmberEUI64([uint8_t(p, base=16) for p in ieee.split(':')]) _LOGGER.info("Removing node %s", ieee) await application_controller.remove(ieee)
def zha_security(config: Dict[str, Any], controller: bool = False) -> None: isc = t.EmberInitialSecurityState() isc.bitmask = t.uint16_t( t.EmberInitialSecurityBitmask.HAVE_PRECONFIGURED_KEY | t.EmberInitialSecurityBitmask.REQUIRE_ENCRYPTED_KEY) isc.preconfiguredKey = t.EmberKeyData( config[zigpy.config.CONF_NWK_TC_LINK_KEY]) nwk_key = config[zigpy.config.CONF_NWK_KEY] if nwk_key is None: nwk_key = os.urandom(16) isc.networkKey = t.EmberKeyData(nwk_key) isc.networkKeySequenceNumber = t.uint8_t( config[zigpy.config.CONF_NWK_KEY_SEQ]) tc_addr = config[zigpy.config.CONF_NWK_TC_ADDRESS] if tc_addr is None: tc_addr = [0x00] * 8 isc.preconfiguredTrustCenterEui64 = t.EmberEUI64(tc_addr) if controller: isc.bitmask |= ( t.EmberInitialSecurityBitmask.TRUST_CENTER_GLOBAL_LINK_KEY | t.EmberInitialSecurityBitmask.HAVE_NETWORK_KEY) isc.bitmask = t.uint16_t(isc.bitmask) return isc
async def permit_with_key(self, node, code, time_s=60): if type(node) is not t.EmberEUI64: node = t.EmberEUI64([t.uint8_t(p) for p in node]) key = zigpy.util.convert_install_code(code) if key is None: raise Exception("Invalid install code") link_key = t.EmberKeyData() link_key.contents = key v = await self._ezsp.addTransientLinkKey(node, link_key) if v[0] != t.EmberStatus.SUCCESS: raise Exception("Failed to set link key") v = await self._ezsp.setPolicy( t.EzspPolicyId.TC_KEY_REQUEST_POLICY, t.EzspDecisionId.GENERATE_NEW_TC_LINK_KEY, ) if v[0] != t.EmberStatus.SUCCESS: raise Exception( "Failed to change policy to allow generation of new trust center keys" ) return await self.permit(time_s)
def serialize(self): r = t.uint16_t(self.attrid).serialize() r += t.uint8_t(self.status).serialize() if self.status == 0: r += self.value.serialize() return r
def write_attributes(self, attributes, is_report=False): args = [] for attrid, value in attributes.items(): if isinstance(attrid, str): attrid = self._attridx[attrid] if attrid not in self.attributes: self.error("%d is not a valid attribute id", attrid) continue if is_report: a = foundation.ReadAttributeRecord() a.status = 0 else: a = foundation.Attribute() a.attrid = t.uint16_t(attrid) a.value = foundation.TypeValue() try: python_type = self.attributes[attrid][1] a.value.type = t.uint8_t(foundation.DATA_TYPE_IDX[python_type]) a.value.value = python_type(value) args.append(a) except ValueError as e: self.error(str(e)) if is_report: schema = foundation.COMMANDS[0x01][1] return self.reply(0x01, schema, args) else: schema = foundation.COMMANDS[0x02][1] return self.request(True, 0x02, schema, args)
async def _update_nwk_id(ezsp, nwk_update_id): """Update NWK id by sending a ZDO broadcast.""" aps_frame = t.EmberApsFrame( profileId=0x0000, clusterId=zigpy.zdo.types.ZDOCmd.Mgmt_NWK_Update_req, sourceEndpoint=0x00, destinationEndpoint=0x00, options=t.EmberApsOption.APS_OPTION_NONE, groupId=0x0000, sequence=0xDE, ) nwk_update_id = t.uint8_t(nwk_update_id).serialize() payload = b"\xDE" + zigpy.types.Channels.ALL_CHANNELS.serialize() + b"\xFF" payload += nwk_update_id + b"\x00\x00" status, _ = await ezsp.sendBroadcast( zigpy.types.BroadcastAddress.ALL_DEVICES, aps_frame, 0x00, 0x01, payload, ) assert status == t.EmberStatus.SUCCESS await asyncio.sleep(1)
async def remove(service): """Remove a node from the network.""" from bellows.types import EmberEUI64, uint8_t ieee = service.data.get(ATTR_IEEE) ieee = EmberEUI64([uint8_t(p, base=16) for p in ieee.split(':')]) _LOGGER.info("Removing node %s", ieee) await APPLICATION_CONTROLLER.remove(ieee)
async def unsubscribe(self, group_id) -> t.EmberStatus: try: entry, idx = self._multicast[group_id] except KeyError: LOGGER.error( "Couldn't find MulticastTableEntry for %s multicast_id", group_id) return t.EmberStatus.INDEX_OUT_OF_RANGE entry.endpoint = t.uint8_t(0) status = await self._ezsp.setMulticastTableEntry(idx, entry) if status[0] != t.EmberStatus.SUCCESS: LOGGER.warning( "Set MulticastTableEntry #%s for %s multicast id: %s", idx, entry.multicastId, status, ) return status[0] self._multicast.pop(group_id) self._available.add(idx) LOGGER.debug( "Set MulticastTableEntry #%s for %s multicast id: %s", idx, entry.multicastId, status, ) return status[0]
def remove(service): """Remove a node from the network.""" from bellows.types import EmberEUI64, uint8_t ieee = service.data.get(ATTR_IEEE) ieee = EmberEUI64([uint8_t(p, base=16) for p in ieee.split(':')]) _LOGGER.info("Removing node %s", ieee) yield from APPLICATION_CONTROLLER.remove(ieee)
def handle_match_desc(self, addr, profile, in_clusters, out_clusters): if profile == 260: response = (0x8006, 0, addr, [t.uint8_t(1)]) else: response = (0x8006, 0, addr, []) self.reply(*response)
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=10): 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) aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(profile) aps_frame.clusterId = t.uint16_t(cluster) aps_frame.sourceEndpoint = t.uint8_t(src_ep) aps_frame.destinationEndpoint = t.uint8_t(dst_ep) aps_frame.options = t.EmberApsOption( t.EmberApsOption.APS_OPTION_RETRY | t.EmberApsOption.APS_OPTION_ENABLE_ROUTE_DISCOVERY) aps_frame.groupId = t.uint16_t(0) aps_frame.sequence = t.uint8_t(sequence) v = await self._ezsp.sendUnicast(self.direct, nwk, aps_frame, sequence, data) if v[0] != t.EmberStatus.SUCCESS: self._pending.pop(sequence) send_fut.cancel() if expect_reply: reply_fut.cancel() raise DeliveryError("Message send failure _send_unicast_fail %s" % (v[0], )) try: v = await send_fut except DeliveryError as e: LOGGER.debug("DeliveryError: %s", e) raise except Exception as e: LOGGER.debug("other Exception: %s", e) if expect_reply: v = await asyncio.wait_for(reply_fut, timeout) return v
def _frame_handler(app, aps, ieee, endpoint, cluster=0, sender=3): app.add_device(ieee, 3) app._ieee = [t.uint8_t(0)] * 8 app._nwk = 0 aps.destinationEndpoint = endpoint aps.clusterId = cluster app.ezsp_callback_handler('incomingMessageHandler', [None, aps, 1, 2, sender, 4, 5, b'\x01\x00\x00'])
def test_struct(): class TestStruct(t.EzspStruct): _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"
async def send_zdo_broadcast(self, command, grpid, radius, args): """ create aps_frame for zdo broadcast""" aps_frame = t.EmberApsFrame() aps_frame.profileId = t.uint16_t(0x0000) # 0 for zdo aps_frame.clusterId = t.uint16_t(command) aps_frame.sourceEndpoint = t.uint8_t(0) # endpoint 0x00 for zdo aps_frame.destinationEndpoint = t.uint8_t(0) # endpoint 0x00 for zdo aps_frame.options = t.EmberApsOption(t.EmberApsOption.APS_OPTION_NONE) aps_frame.groupId = t.uint16_t(grpid) aps_frame.sequence = t.uint8_t(self.get_sequence()) radius = t.uint8_t(radius) data = aps_frame.sequence.to_bytes(1, 'little') schema = zigpy.zdo.types.CLUSTERS[command][2] data += t.serialize(args, schema) LOGGER.debug("zdo-broadcast: %s - %s", aps_frame, data) await self._ezsp.sendBroadcast(0xfffd, aps_frame, radius, len(data), data)
def test_struct(): class TestStruct(t.EzspStruct): _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'
def handle_match_desc(self, addr, profile, in_clusters, out_clusters): local_addr = self._device.application.nwk if profile == 260: response = (0x8006, 0, local_addr, [t.uint8_t(1)]) else: response = (0x8006, 0, local_addr, []) self.reply(*response)
async def subscribe_group(self, group_id): # check if already subscribed, if not find a free entry and subscribe group_id e = self._ezsp index = None for entry_id in self._multicast_table.keys(): if self._multicast_table[entry_id].multicastId == group_id: LOGGER.debug("multicast group %s already subscribed", group_id) return if self._multicast_table[entry_id].endpoint == 0: index = entry_id if index is None: LOGGER.critical("multicast table full, can not add %s", group_id) return self._multicast_table[index].endpoint = t.uint8_t(1) self._multicast_table[index].multicastId = t.EmberMulticastId(group_id) result = await e.setMulticastTableEntry(t.uint8_t(index), self._multicast_table[index]) return result