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 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
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 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
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 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 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 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
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 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 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 read_attributes(self, attributes): schema = foundation.COMMANDS[0x00][1] attributes = [t.uint16_t(a) for a in attributes] v = yield from self.request(True, 0x00, schema, attributes) for record in v[0]: if record.status == 0: self._attr_cache[record.attrid] = record.value.value return v
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)
async def config(ctx, config, all_): """Get/set configuration on the NCP""" click.secho( "NOTE: Configuration changes do not persist across resets", fg='red' ) if config and all_: raise click.BadOptionUsage("Specify a config or --all, not both") if not (config or all_): raise click.BadOptionUsage("One of config or --all must be specified") s = await util.setup(ctx.obj['device'], ctx.obj['baudrate'], util.print_cb) if all_: for config in t.EzspConfigId: v = await s.getConfigurationValue(config) if v[0] == t.EzspStatus.ERROR_INVALID_ID: continue click.echo("%s=%s" % (config.name, v[1])) s.close() return if '=' in config: config, value = config.split("=", 1) if config.isdigit(): try: config = t.EzspConfigId(int(config)) except ValueError: raise click.BadArgumentUsage("Invalid config ID: %s" % ( config, )) else: try: config = t.EzspConfigId[config] except KeyError: raise click.BadArgumentUsage("Invalid config name: %s" % ( config, )) try: value = t.uint16_t(value) if not (0 <= value <= 65535): raise ValueError("%s out of allowed range 0..65535" % ( value, )) except ValueError as e: raise click.BadArgumentUsage("Invalid value: %s" % (e, )) v = await s.setConfigurationValue(config, value) click.echo(v) s.close() return v = await s.getConfigurationValue(config) click.echo(v)
def test_frame_handler_zdo_annce(app, aps, ieee): aps.destinationEndpoint = 0 app.handle_join = mock.MagicMock() nwk = t.uint16_t(0xAA55) data = b"\x18" + nwk.serialize() + ieee.serialize() _frame_handler(app, aps, ieee, 0, cluster=0x0013, data=data) assert app.handle_message.call_count == 1 assert app.handle_message.call_args[0][5] is data assert app.handle_join.call_count == 1 assert app.handle_join.call_args[0][0] == nwk assert app.handle_join.call_args[0][1] == ieee
def write_attributes(self, attributes): args = [] for attrid, value in attributes.items(): a = foundation.Attribute() a.attrid = t.uint16_t(attrid) a.value = foundation.TypeValue() 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) schema = foundation.COMMANDS[0x02][1] return self.request(True, 0x02, schema, args)
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, 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 = self._tx_options 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")) with self._pending.new(message_tag) as req: async with self._in_flight_msg: delays = [0.5, 1.0, 1.5] while True: async with self._req_lock: 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) if self.use_source_routing and self._ezsp.ezsp_version < 8: (res, ) = await self._ezsp.set_source_route(device) if res == t.EmberStatus.SUCCESS: aps_frame.options ^= ( t.EmberApsOption. APS_OPTION_ENABLE_ROUTE_DISCOVERY) LOGGER.debug( "Set source route for %s to %s: %s", device.nwk, device.relays, res, ) else: LOGGER.debug( "using route discovery for %s device", device.nwk, ) status, _ = await self._ezsp.sendUnicast( self.direct, device.nwk, aps_frame, message_tag, data) if not (status == t.EmberStatus.MAX_MESSAGE_LIMIT_REACHED and delays): # retry only on MAX_MESSAGE_LIMIT_REACHED if tries are left break delay = delays.pop(0) LOGGER.debug("retrying request %s tag in %ss", message_tag, delay) await asyncio.sleep(delay) if status != t.EmberStatus.SUCCESS: return status, f"EZSP sendUnicast failure: {str(status)}" res = await asyncio.wait_for(req.result, APS_ACK_TIMEOUT) return res
def read_attributes_raw(self, attributes): schema = foundation.COMMANDS[0x00][1] attributes = [t.uint16_t(a) for a in attributes] v = yield from self.request(True, 0x00, schema, attributes) return v
def join(ctx, channels, pan_id, extended_pan_id): """Join an existing ZigBee network as an end device""" def cb(fut, frame_name, response): if frame_name == 'stackStatusHandler': fut.set_result(response) s = yield from util.setup(ctx.obj['device'], ctx.obj['baudrate']) channel = None if len(channels) != 1: if pan_id or extended_pan_id: raise click.BadOptionUsage( "Specify exactly one channel to join a specific network") else: channel = t.uint8_t(channels[0]) if not (pan_id or extended_pan_id): scan_type = t.EzspNetworkScanType.ACTIVE_SCAN channel_mask = util.channel_mask(channels) click.echo("PAN not provided, scanning channels %s..." % (' '.join(map(str, channels)), )) v = yield from s.startScan(scan_type, channel_mask, 3) networks = [n[0] for n in v if n[0].allowingJoin] if len(networks) == 0: click.echo("No joinable networks found") return 1 if len(networks) > 1: click.echo("Multiple joinable networks found. Refusing to pick.") return 1 network = networks[0] pan_id = network.panId extended_pan_id = network.extendedPanId channel = network.channel click.echo("Found network %s %s on channel %s" % ( pan_id, extended_pan_id, channel, )) if pan_id is None: pan_id = t.uint16_t(0) else: pan_id = t.uint16_t(pan_id) if isinstance(extended_pan_id, str): extended_pan_id = util.parse_epan(extended_pan_id) if extended_pan_id is None: extended_pan_id = t.fixed_list(8, t.uint8_t)([t.uint8_t(0)] * 8) v = yield from util.network_init(s) if v[0] == t.EmberStatus.SUCCESS: LOGGER.debug("Network was up, leaving...") v = yield from s.leaveNetwork() util.check(v[0], "Failure leaving network: %s" % (v[0], )) yield from asyncio.sleep(1) # TODO initial_security_state = zutil.zha_security() v = yield from s.setInitialSecurityState(initial_security_state) util.check(v[0], "Setting security state failed: %s" % (v[0], )) parameters = t.EmberNetworkParameters() parameters.extendedPanId = extended_pan_id parameters.panId = pan_id parameters.radioTxPower = t.uint8_t(8) parameters.radioChannel = t.uint8_t(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) click.echo(parameters) fut = asyncio.Future() cbid = s.add_callback(functools.partial(cb, fut)) v = yield from s.joinNetwork(t.EmberNodeType.END_DEVICE, parameters) util.check(v[0], "Joining network failed: %s" % (v[0], )) v = yield from fut click.echo(v) s.remove_callback(cbid) s.close()
def form(ctx, channel, pan_id, extended_pan_id): """Create a new ZigBee network""" s = yield from util.setup(ctx.obj['device'], util.print_cb) v = yield from util.networkInit(s) if v[0] == t.EmberStatus.SUCCESS: LOGGER.debug("Network was up, leaving...") v = yield from s.leaveNetwork() util.check(v[0], "Failure leaving network: %s" % (v[0], )) yield from asyncio.sleep(1) # TODO initial_security_state = util.zha_security(controller=True) v = yield from s.setInitialSecurityState(initial_security_state) util.check(v[0], "Setting security state failed: %s" % (v[0], )) yield from util.basic_tc_permits(s) if channel: channel = t.uint8_t(channel) else: channel = t.uint8_t(17) if extended_pan_id: extended_pan_id = util.parse_epan(extended_pan_id) else: extended_pan_id = t.fixed_list(8, t.uint8_t)([t.uint8_t(0)] * 8) if pan_id: pan_id = t.uint16_t(pan_id) else: pan_id = t.uint16_t.from_bytes(os.urandom(2), 'little') 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) click.echo(parameters) LOGGER.info("Forming network ...") fut = asyncio.Future() def cb(fut, frame_name, response): if frame_name == 'stackStatusHandler': fut.set_result(response) s.add_callback(functools.partial(cb, fut)) v = yield from s.formNetwork(parameters) util.check(v[0], "Failed to form network: %s" % (v[0], )) v = yield from fut util.check( v[0], "Network didn't come up after form", t.EmberStatus.NETWORK_UP, ) yield from s.setValue(t.EzspValueId.VALUE_STACK_TOKEN_WRITING, 1) yield from asyncio.sleep(0.1) s.close()
async def request(self, nwk, profile, cluster, src_ep, dst_ep, sequence, data, expect_reply=True, timeout=15): # LOGGER.debug("pending message queue length: %s", len(self._pending)) 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) LOGGER.debug( "sendUnicast to NWKID:0x%04x DST_EP:%s PROFIL_ID:%s CLUSTER:0x%04x TSN:%s, Timeout:%s", nwk, dst_ep, profile, cluster, sequence, timeout, ) try: v = await asyncio.wait_for(self._ezsp.sendUnicast(self.direct, nwk, aps_frame, sequence, data), timeout) except asyncio.TimeoutError: LOGGER.debug( "sendunicast uart timeout NWKID:0x%04x DST_EP:%s PROFIL_ID:%s CLUSTER:0x%04x TSN:%s, Timeout:%s", nwk, dst_ep, profile, cluster, sequence, timeout, ) self._pending.pop(sequence) send_fut.cancel() if expect_reply: reply_fut.cancel() raise DeliveryError("Message send failure uart timeout") if v[0] != t.EmberStatus.SUCCESS: self._pending.pop(sequence) send_fut.cancel() if expect_reply: reply_fut.cancel() LOGGER.debug("sendunicast send failure NWKID:0x%04x DST_EP:%s PROFIL_ID:%s CLUSTER:0x%04x TSN:%s, Timeout:%s", nwk, dst_ep, profile, cluster, sequence, timeout, ) raise DeliveryError("Message send failure _send_unicast_fail") try: v = await asyncio.wait_for(send_fut, timeout) except DeliveryError as e: LOGGER.debug("0x%04x:%s:0x%04x sendunicast send_ACK failure - Error:%s", nwk, dst_ep, cluster, e) raise except asyncio.TimeoutError: LOGGER.debug("sendunicast message send_ACK timeout NWKID:0x%04x DST_EP:%s PROFIL_ID:%s CLUSTER:0x%04x TSN:%s, Timeout:%s", nwk, dst_ep, profile, cluster, sequence, timeout, ) self._pending.pop(sequence) if expect_reply: reply_fut.cancel() raise DeliveryError("ACK_TIMEOUT") # if v != t.EmberStatus.SUCCESS: # self._pending.pop(sequence) # if expect_reply: # reply_fut.cancel() # LOGGER.debug("sendunicast send_ACK failure 0x%04x:%s:0x%04x = %s", nwk, dst_ep, cluster, v) # raise DeliveryError("sendunicast send_ACK failure") if expect_reply: try: v = await asyncio.wait_for(reply_fut, timeout) except asyncio.TimeoutError: LOGGER.debug( "[0x%04x:%s:0x%04x] sendunicast reply(TSN:%s) timeout failure", nwk, dst_ep, cluster, sequence) self._pending.pop(sequence) raise DeliveryError("sendunicast reply timeout error") return v