From 7feaaacf144d652c557224c0b84a82c703277577 Mon Sep 17 00:00:00 2001 From: nathan wagner Date: Fri, 31 Dec 2021 16:35:49 -0500 Subject: [PATCH] updating for general cluster 0 responses --- main.py | 98 ++++++----- spec.py | 499 +++++++++++++++++++++++++++++++------------------------- 2 files changed, 336 insertions(+), 261 deletions(-) diff --git a/main.py b/main.py index 53df80b..6ceb085 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,7 @@ # xbee hardware pdf: https://www.digi.com/resources/documentation/digidocs/pdfs/90001543.pdf import time import xbee +import spec import ubinascii from machine import I2C from machine import Pin @@ -14,6 +15,10 @@ import struct # default to everything off and 0 at power on. # in the future, we can try to reclaim previous state. # Hopefully this lamp won't turn off very often +ad0 = Pin("D0", Pin.IN, Pin.PULL_UP) +ad1 = Pin("D1", Pin.IN, Pin.PULL_UP) +ad2 = Pin("D2", Pin.IN, Pin.PULL_UP) +ad4 = Pin("D4", Pin.OUT) def status_cb(status): print("received status: {:02x}".format(status)) @@ -55,53 +60,75 @@ lame = 0 # send=1 send=0 time.sleep(1) -while send==0: - try: - if xbee.transmit(xbee.ADDR_COORDINATOR, initial_payload, source_ep=0, dest_ep=0, cluster=19, profile=0, tx_options=0) is None: - send = 1 - print("joining") - except OSError as e: - print("joining transmit error") + +def fancy_transmit(payload, source_ep, dest_ep, cluster,profile): + send = 0 + while send==0: + try: + if xbee.transmit(xbee.ADDR_COORDINATOR, payload, source_ep=source_ep, dest_ep=dest_ep, cluster=cluster, profile=profile, + tx_options=0) is None: + send = 1 + time.sleep(1) + except OSError as e: + time.sleep(1) + print(payload) + print(e) + + +fancy_transmit( payload=initial_payload, source_ep=0, dest_ep=0, cluster=19,profile=0 ) print("receiving") while 1 != 0: blorp = xbee.receive() if blorp is not None: + print(blorp) + if blorp['cluster'] == 6: #genOnOffCluster in HA Profile + if blorp['profile'] == 260: #HA profile + cluster_name, seq, CommandType, command_name, disable_default_response, kwargs = spec.decode_zcl(blorp['cluster'], blorp['payload']) + if 'command' in kwargs: + if kwargs['commands'][0] == 0: + ad4.value(1) + time.sleep(1) + ad4.value(0) + if kwargs['commands'][1] == 0: + ad4.value(1) + time.sleep(1) + ad4.value(0) + if kwargs['commands'][2] == 0: + ad4.value(1) + time.sleep(1) + ad4.value(0) if blorp['cluster']==5: #active endpoint request print(bytes(blorp['payload'])) b = bytearray(blorp['payload']) print(b[0]) payload=bytes([b[0], 00, b[1], b[2], 1, 8]) - try: - if xbee.transmit(xbee.ADDR_COORDINATOR,payload,source_ep=0,dest_ep=0,cluster=32773, profile=0, tx_options=0) is None: - send = 1 - print("sent-endpoint-response") - except OSError as e: - print("joining transmit error") - + fancy_transmit(payload=payload,source_ep=0,dest_ep=0,cluster=32773, profile=0) + print("sent-endpoint-response") if blorp['cluster']==4: #simple descriptor request print(bytes(blorp['payload'])) b = bytearray(blorp['payload']) print(b[0]) payload = bytes([b[0], 00, b[1], b[2], 14, 8, 4, 1, 2, 0, 6, 3, 0, 0, 3, 0, 6, 0, 0]) - try: - if xbee.transmit(xbee.ADDR_COORDINATOR, payload, source_ep=0,dest_ep=0,cluster=32772, profile=0, tx_options=0) is None: - send = 1 - print("simple descriptor response") - except OSError as e: - print("joining transmit error") + fancy_transmit(payload=payload, source_ep=0, dest_ep=0, cluster=32772, profile=0) + print("simple descriptor response") if blorp['cluster'] == 0: #network address request if blorp['profile'] == 260: - resp = bytearray(blorp['payload']) - payload = bytes([b[0], 0, b[1], b[2]]) - try: - if xbee.transmit(xbee.ADDR_COORDINATOR, payload, source_ep=blorp['dest_ep'], dest_ep=blorp['source_ep'], cluster=blorp['cluster'], profile=blorp['profile'], - tx_options=0) is None: - send = 1 - print("joining") - except OSError as e: - print("joining transmit error") - + #resp = bytearray(blorp['payload']) + cluster_name, seq, CommandType, command_name, disable_default_response, kwargs = spec.decode_zcl(blorp['cluster'], blorp['payload']) + print(command_name) + print(kwargs) + if 'attributes' in kwargs: + attr_bytes=spec.attribute_result(kwargs) + #payload: control byte, code bytes(2), seq copy, command identifier(read_attributes_response, + #payload = bytes([4, 30, 16, seq, 1, attr_bytes, 0, 8, 0]) + payload = bytes([12, 30, 16, seq, 1]) + payload = payload+attr_bytes + #payload= attr_bytes + print(payload) + fancy_transmit(payload=payload, source_ep=blorp['dest_ep'], dest_ep=blorp['source_ep'], cluster=blorp['cluster'], profile=blorp['profile']) + print("attribute_read_response") + #spec.decode_zcl(blorp['cluster'], blorp['payload']) print(bytes(blorp['payload'])) b = bytearray(blorp['payload']) for x in b: @@ -111,19 +138,12 @@ while 1 != 0: b = bytearray(blorp['payload']) print(b[0]) payload = bytes([b[0], 00, b[1], b[2], 4, 143, 120, 8, 80, 160, 0, 1, 44, 160, 0, 0]) - try: - if xbee.transmit(xbee.ADDR_COORDINATOR, payload, source_ep=0, dest_ep=0, cluster=32772, profile=blorp['profile'], - tx_options=0) is None: - send = 1 - print("joining") - except OSError as e: - print("joining transmit error") - + fancy_transmit(payload=payload, source_ep=0, dest_ep=0, cluster=32772, profile=blorp['profile']) + print("node descriptor response") if blorp['cluster'] == 32770: #node descriptor response print(bytes(blorp['payload'])) b = bytearray(blorp['payload']) print("Node descriptor response integer payload discard") - print(blorp) #for key, value in blorp.items(): #1 print (key, ' : ', value) diff --git a/spec.py b/spec.py index 642c8e9..263864c 100644 --- a/spec.py +++ b/spec.py @@ -60,11 +60,11 @@ # t_int = 0 -import enum +#import enum import struct -class DataType(enum.IntEnum): +class DataType(): # ZCL Spec -- "2.5.2 Data Types" NULL = 0x00 BOOLEAN = 0x10 @@ -82,12 +82,12 @@ class DataType(enum.IntEnum): CHARACTER_STRING = 0x42 -ANALOG_DATATYPES = set([ +ANALOG_DATATYPES = [ DataType.UINT8, DataType.UINT16, DataType.UINT64, DataType.INT8, DataType.INT16, DataType.INT64 -]) +] -class Profile(enum.IntEnum): +class Profile(): ZIGBEE = 0x0000 HOME_AUTOMATION = 0x0104 ZIGBEE_LIGHT_LINK = 0xc05e @@ -97,16 +97,16 @@ def get_profile_by_name(n): return getattr(Profile, n.upper(), None) -class Endpoint(enum.IntEnum): +class Endpoint(): ZDO = 0x00 -class ZclCommandType(enum.IntEnum): +class ZclCommandType(): PROFILE = 0 CLUSTER = 1 -class Status(enum.IntEnum): +class Status(): SUCCESS = 0x00 FAILURE = 0x01 NOT_AUTHORIZED = 0x7E @@ -143,37 +143,37 @@ class Status(enum.IntEnum): UNSUPPORTED_CLUSTER = 0xC3 -ZDO_BY_NAME = { - # Zigbee Spec -- "2.4.3.1.5 Simple_Desc_req" - 'simple_desc': (0x0004, ('addr16:uint16', 'endpoint:uint8',),), - # Zigbee Spec -- "2.4.4.1.5 Simple_Desc_resp" - 'simple_desc_resp': (0x8004, ('status:enum8:success,invalid_ep,not_active,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'b_simple_descriptors:uint8', 'simple_descriptors:#simple_descriptor',),), - # Zigbee Spec -- "2.4.3.1.6 Active_EP_req" - 'active_ep': (0x0005, ('addr16:uint16',),), - # Zigbee Spec -- "2.4.4.1.6 Active_EP_resp" - 'active_ep_resp': (0x8005, ('status:enum8:success,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'n_active_eps:uint8', 'active_eps:*uint8',),), - # Zigbee Spec -- "2.4.3.1.7 Match_Desc_req" - 'match_desc': (0x0006, ('addr16:uint16', 'profile:uint16', 'n_in_clusters:uint8', 'in_clusters:*uint16', 'n_out_clusters:uint8', 'out_clusters:*uint16',),), - # Zigbee Spec -- "2.4.4.1.7 Match_Desc_resp" - 'match_desc_resp': (0x8006, ('status:enum8:success,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'n_match_list:uint8', 'match_list:*uint8',),), - # Zigbee Spec -- "2.4.3.2.2 Bind_req" - 'bind': (0x0021, ('src_addr:uint64', 'src_ep:uint8', 'cluster:uint16', 'dst_addr_mode:enum8:_,addr16,_,addr64', 'dst_addr:uint64', 'dst_ep:uint8',),), - # Zigbee Spec -- "2.4.3.2.3 Unbind_req" - 'unbind': (0x0022, ('src_addr:uint64', 'src_ep:uint8', 'cluster:uint16', 'dst_addr_mode:enum8:_,addr16,_,addr64', 'dst_addr:uint64', 'dst_ep:uint8',),), - # Zigbee Spec -- "2.4.4.2.2 Bind_resp" - 'bind_resp': (0x8021, ('status:enum8:success,not_supported,invalid_ep,table_full,not_authorized',),), - # Zigbee Spec -- "2.4.4.2.3 Unbind_resp" - 'unbind_resp': (0x8022, ('status:enum8:success,not_supported,invalid_ep,table_full,not_authorized',),), - # Spec -- "2.4.3.1.11 Device_annce" - 'device_annce': (0x0013, ('addr16:uint16', 'addr64:uint64', 'capability:uint8'),), # See Figure 2.17 - # Zigbee Spec -- "2.4.4.3.9 Mgmt_NWK_Update_notify" - 'mgmt_nwk_update_notify': (0x8038, ('status:uint8', 'scanned_channels:uint32', 'total_transmissions:uint16', 'transmisson_failures:uint16', 'n_energy_values:uint8', 'energy_values:*uint8',),), -} - - -ZDO_BY_ID = { - cluster: (name, args) for name, (cluster, args) in ZDO_BY_NAME.items() -} +#ZDO_BY_NAME = { +# # Zigbee Spec -- "2.4.3.1.5 Simple_Desc_req" +# 'simple_desc': (0x0004, ('addr16:uint16', 'endpoint:uint8',),), +# # Zigbee Spec -- "2.4.4.1.5 Simple_Desc_resp" +# 'simple_desc_resp': (0x8004, ('status:enum8:success,invalid_ep,not_active,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'b_simple_descriptors:uint8', 'simple_descriptors:#simple_descriptor',),), +# # Zigbee Spec -- "2.4.3.1.6 Active_EP_req" +# 'active_ep': (0x0005, ('addr16:uint16',),), +# # Zigbee Spec -- "2.4.4.1.6 Active_EP_resp" +# 'active_ep_resp': (0x8005, ('status:enum8:success,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'n_active_eps:uint8', 'active_eps:*uint8',),), +# # Zigbee Spec -- "2.4.3.1.7 Match_Desc_req" +# 'match_desc': (0x0006, ('addr16:uint16', 'profile:uint16', 'n_in_clusters:uint8', 'in_clusters:*uint16', 'n_out_clusters:uint8', 'out_clusters:*uint16',),), +# # Zigbee Spec -- "2.4.4.1.7 Match_Desc_resp" +# 'match_desc_resp': (0x8006, ('status:enum8:success,device_not_found,inv_requesttype,no_descriptor', 'addr16:uint16', 'n_match_list:uint8', 'match_list:*uint8',),), +# # Zigbee Spec -- "2.4.3.2.2 Bind_req" +# 'bind': (0x0021, ('src_addr:uint64', 'src_ep:uint8', 'cluster:uint16', 'dst_addr_mode:enum8:_,addr16,_,addr64', 'dst_addr:uint64', 'dst_ep:uint8',),), +# # Zigbee Spec -- "2.4.3.2.3 Unbind_req" +# 'unbind': (0x0022, ('src_addr:uint64', 'src_ep:uint8', 'cluster:uint16', 'dst_addr_mode:enum8:_,addr16,_,addr64', 'dst_addr:uint64', 'dst_ep:uint8',),), +# # Zigbee Spec -- "2.4.4.2.2 Bind_resp" +# 'bind_resp': (0x8021, ('status:enum8:success,not_supported,invalid_ep,table_full,not_authorized',),), +# # Zigbee Spec -- "2.4.4.2.3 Unbind_resp" +# 'unbind_resp': (0x8022, ('status:enum8:success,not_supported,invalid_ep,table_full,not_authorized',),), +# # Spec -- "2.4.3.1.11 Device_annce" +# 'device_annce': (0x0013, ('addr16:uint16', 'addr64:uint64', 'capability:uint8'),), # See Figure 2.17 +# # Zigbee Spec -- "2.4.4.3.9 Mgmt_NWK_Update_notify" +# 'mgmt_nwk_update_notify': (0x8038, ('status:uint8', 'scanned_channels:uint32', 'total_transmissions:uint16', 'transmisson_failures:uint16', 'n_energy_values:uint8', 'energy_values:*uint8',),), +#} + + +#ZDO_BY_ID = { +# cluster: (name, args) for name, (cluster, args) in ZDO_BY_NAME.items() +#} def _decode_helper(args, data, i=0): @@ -240,15 +240,15 @@ def _decode_helper(args, data, i=0): def _decode_simple_descriptor(data, i, obj): return _decode_helper(('endpoint:uint8', 'profile:uint16', 'device_identifier:uint16', 'device_version:uint8', 'n_in_clusters:uint8', 'in_clusters:*uint16', 'n_out_clusters:uint8', 'out_clusters:*uint16',), data, i) -def _encode_simple_descriptor(): - pass +#def _encode_simple_descriptor(): +# pass def _decode_read_attr_status(data, i, obj): return _decode_helper(('attribute:uint16', 's_status:status8', 'datatype:uint8', 'value:datatype',), data, i) -def _encode_read_attr_status(): - pass +#def _encode_read_attr_status(): +# pass def _decode_datatype(data, i, obj): @@ -269,23 +269,23 @@ def _decode_datatype(data, i, obj): return decode(data, i, obj) -def _encode_datatype(): - pass +#def _encode_datatype(): +# pass def _decode_attr_reporting_config(): pass -def _encode_attr_reporting_config(obj): - data = bytes() - datatype = DATATYPES_BY_NAME[obj['datatype']] - # min=1s, max=60s - data += struct.pack('