def leave(): global seq tx( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_DATA, seq=seq, dst=0x0000, dst_pan=pan, src=nwk_addr, payload=ZigbeeNetwork.ZigbeeNetwork( aes=Parser.aes, frame_type=ZigbeeNetwork.FRAME_TYPE_CMD, version=2, radius=1, seq=12, dst=0xfffd, src=nwk_addr, ext_src=mac_addr, discover_route=0, security=1, sec_seq=bytearray(b'\x00\x00\x00\x00'), sec_key=1, sec_key_seq=0, payload=bytearray(b'\x04\x00')), )) seq += 1
def beacon(self): self.tx_ieee( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_CMD, command=IEEE802154.COMMAND_BEACON_REQUEST, seq=self.seq, src=None, src_pan=None, dst=0xFFFF, # everyone dst_pan=0xFFFF, # every PAN payload=b'', ))
def loop(): pan_set = False incoming = '' machine.zrepl(False) while True: pkt = Radio.rx() if pkt is not None: # throw away the extra b' and ' on the string # representation x = repr(hexlify(pkt))[2:-1] print(x) ieee = IEEE802154.IEEE802154(data=pkt) if ieee.frame_type == IEEE802154.FRAME_TYPE_CMD \ and ieee.command == IEEE802154.COMMAND_JOIN_RESPONSE: # reponse to our join request; update our short address (new_nwk, status) = unpack("<HB", ieee.payload) if status == 0: print("NIC: NEW NWK %04x" % (new_nwk)) Radio.address(new_nwk) else: print("NIC: NEW NWK failed") elif ieee.frame_type == IEEE802154.FRAME_TYPE_BEACON \ and not pan_set \ and ieee.payload[1] & 0x80 \ and ieee.src != 0x0000: print("NIC: NEW PAN %04x" % (ieee.src_pan)) Radio.pan(ieee.src_pan) pan_set = True x = None gc.collect() if machine.stdio_poll(): y = sys.stdin.read(1) if y == '\r': continue if y != '\n': incoming += y continue #print("SEND:", incoming) try: x = unhexlify(incoming) Radio.tx(x) except: print("TX FAIL") incoming = '' x = None gc.collect()
def join(self, payload=b'\x80'): self.tx_ieee( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_CMD, command=IEEE802154.COMMAND_JOIN_REQUEST, ack_req=1, seq=self.seq, src=self.radio.mac(), src_pan=0xFFFF, # not yet part of the PAN dst=self.router, dst_pan=self.radio.pan(), payload= payload, # b'\x80' = Battery powered, please allocate address )) self.pending_data = True self.join_failed = False
def tx(self, payload, dst=None, ack_req=False, long_addr=False): pan = self.radio.pan() src = self.radio.address() if src is None: src = self.radio.mac() self.tx_ieee( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_DATA, dst=dst, dst_pan=pan, src=src, src_pan=pan, ack_req=ack_req, payload=payload, ))
def data_request(self): pan = self.radio.pan() src = self.radio.address() if src is None: src = self.radio.mac() self.tx_ieee( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_CMD, command=IEEE802154.COMMAND_DATA_REQUEST, dst=self.router, dst_pan=pan, src=src, src_pan=pan, ack_req=True, ))
def data_request(src=None): global seq this_seq = seq seq += 1 if src is None: src = nwk_addr return tx( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_CMD, command=IEEE802154.COMMAND_DATA_REQUEST, ack_req=True, seq=this_seq, src=src, dst=0x0000, dst_pan=pan, payload=b'', ))
def wait_packet(wait_type): spins = 0 ieee = IEEE802154.IEEE802154() while spins < max_spins: if reset_pin() == 0: break spins += 1 b = Radio.rx() if b is None: continue # fast discard #print("b=", b[0]) frame_type = b[0] & 0x7 if frame_type != wait_type: continue ieee.deserialize(memoryview(b)) print("<--", ieee) return ieee return None
def rx(self, data): if data is None or len( data) < 2: # or len(data) < 2 or len(data) & 1 != 0: self.tick() return try: ieee = IEEE802154.IEEE802154(data=data) # check for duplicates, using the short address # long address duplicates will be processed if type(ieee.src) is int: if ieee.src in self.seqs \ and self.seqs[ieee.src] == ieee.seq: return self.seqs[ieee.src] = ieee.seq if self.verbose: print("RX: " + str(Parser.parse(data)[0])) except Exception as e: print("IEEE error: " + str(hexlify(data))) raise return if ieee.frame_type == IEEE802154.FRAME_TYPE_CMD: return self.handle_command(ieee) elif ieee.frame_type == IEEE802154.FRAME_TYPE_ACK: return self.handle_ack(ieee) elif ieee.frame_type == IEEE802154.FRAME_TYPE_BEACON: return self.handle_beacon(ieee) elif ieee.frame_type == IEEE802154.FRAME_TYPE_DATA: # for the next layer up, pass it to the handler return self.handler(ieee.payload) else: # should signal a wtf? print("RX: " + str(Parser.parse(data)[0])) pass
from ZbPy import ZigbeeApplication from ZbPy import ZigbeeCluster from ZbPy import ZCL import gc gc.collect() # This is the "well known" zigbee2mqtt key. # The Ikea gateway uses a different key that has to be learned # by joining the network (not yet implemented) nwk_key = unhexlify(b"01030507090b0d0f00020406080a0c0d") aes = AES.AES(nwk_key) # Pre-allocate message types for the parser # Only one message can be parsed at a time ieee = IEEE802154.IEEE802154() nwk = ZigbeeNetwork.ZigbeeNetwork(aes=aes) aps = ZigbeeApplication.ZigbeeApplication() zcl = ZigbeeCluster.ZigbeeCluster() cmd = ZCL.ZCL() # For filtering dupes seqs = {} def parse(data, verbose=False, filter_dupes=False): global seqs #print("------") #print(data) ieee.deserialize(data)
def ack(self, ack_seq): self.radio.tx( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_ACK, seq=ack_seq, ).serialize())
def join(): global seq global nwk_addr global pan gc.collect() Radio.promiscuous(1) pan = discover_pan() if pan is None: print("No PAN received?") return False print("PAN=0x%04x" % (pan)) # Send the join request if not tx( IEEE802154.IEEE802154( frame_type=IEEE802154.FRAME_TYPE_CMD, command=IEEE802154.COMMAND_JOIN_REQUEST, seq=seq, src=mac_addr, src_pan=0xFFFF, dst=0x0000, dst_pan=pan, ack_req=True, payload=b'\x80', # Battery powered, please allocate address )): print("JOIN_REQUEST: no ack") return False seq += 1 if not data_request(src=mac_addr): print("DATA_REQUEST: long no ack") return False assoc = wait_packet(IEEE802154.FRAME_TYPE_CMD) if assoc is None: print("ASSOCIATE RESPONSE not received?") return False ack(assoc.seq) if assoc.command != IEEE802154.COMMAND_JOIN_RESPONSE: print("Not an associate response?") return False nwk_addr = (assoc.payload[0] << 0) | (assoc.payload[1] << 8) status = assoc.payload[2] if status == 2: print("JOIN DENIED!") return print("------------") print("New network address 0x%04x status %d" % (nwk_addr, status)) gc.collect() return nwk_addr #Radio.promiscuous(0) #Radio.address(nwk_addr, pan) #if not data_request(): #print("DATA_REQUEST: short no ack") # try to get the network key #for i in range(10): print("---- Sending request ----") if not data_request(): print("DATA_REQUEST: short no ack") process_one() #print("Running loop") #loop(0) return True
def ack(ack_seq): tx(IEEE802154.IEEE802154(frame_type=IEEE802154.FRAME_TYPE_ACK, seq=ack_seq))
Radio.promiscuous(True) while True: if reset_pin() == 0: break bytes = Radio.rx() if bytes is None: continue # throw away the extra two bytes of wtf x = hexlify(bytes) print(x) beacon_packet = IEEE802154.IEEE802154(frame_type=3, seq=99, command=7, dst=0xffff, dst_pan=0xffff) def beacon(): tx(beacon_packet) def wait_packet(wait_type): spins = 0 ieee = IEEE802154.IEEE802154() while spins < max_spins: if reset_pin() == 0: break