+# -----------------------------------------------------------------------------
+# ZigBee Gateway Driver for Vigilia v.1.0
+# Created by Ali Younis
+# Modified by Rahmadi Trimananda, Lee Changwoo, Jiawei
+# (c) 2016-2018 University of California, Irvine
+# -----------------------------------------------------------------------------
+
from xbee import ZigBee
import serial
import time
UDP_RECEIVE_PORT = 5005 # port used for incoming UDP data
UDP_RECEIVE_BUFFER_SIZE = 4096 # max buffer size of an incoming UDP packet
SYSTEM_MASTER_ADDRESS = ("192.168.1.198", 12345) # ip address and portof the system master node
-#SYSTEM_MASTER_ADDRESS = ("192.168.2.108", 22222) # ip address and portof the system master node
-#SYSTEM_MASTER_ADDRESS2 = ("192.168.2.108", 11111)
-#SYSTEM_MASTER_ADDRESS3 = ("192.168.2.108", 11222)
+LOCAL_ADDRESS = "192.168.1.192" # local IP address
# time for messages to wait for a response before the system clears away that
# sequence identifier
ZIGBEE_SERIAL_BAUD = 115200 # Baud rate for above port
# address of our local zigbee radio
-#ZIGBEE_DEVICE_ADDRESS = "0013a20040d99cb4"
ZIGBEE_DEVICE_ADDRESS = "xxxxxxxxxxxxxxxx"
# -----------------------------------------------------------------------------
zigbeeConnection = None
zigbeeConnectionMutex = Lock()
-#singleton mabe by changwoo
+#singleton mabe by Changwoo
matchDescriptorReqSingleton = True
deviceAnnouncementSingleton = True
ManagementPermitJoiningReqSuccess = False
zigbeeSeqNumberToClient = dict()
zigbeeSeqNumberToClientMutex = Lock()
-zigeeBindRequest = dict()
-zigeeBindRequestMutex = Lock()
+zigbeeBindRequest = dict()
+zigbeeBindRequestMutex = Lock()
# Keeps record of where to send callbacks to when an HA message is received
zibeeHACallback = dict()
-zibeeHACallbackMutex = Lock()
+zigbeeHACallbackMutex = Lock()
# Keeps a record of device addresses whose short addresses have not been
# 2 sockets, one for sending (not bound to a port manually)
# and one for receiving, known port binding by application
# both UDP sockets
-sendSoceket = socket(AF_INET, SOCK_DGRAM)
-receiveSoceket = socket(AF_INET, SOCK_DGRAM)
+sendSocket = socket(AF_INET, SOCK_DGRAM)
+receiveSocket = socket(AF_INET, SOCK_DGRAM)
# zigbee address authority list
zigbeeAddressAuthorityDict = dict()
-# made by changwoo
+# Added by Changwoo
seqNumberForNotification = dict()
# -----------------------------------------------------------------------------
zigbeeConnection.send('at', command="SL")
# sleep for a bit to give the radio time to respond before we check again
- #time.sleep(2)
time.sleep(0.5)
def addressUpdateWorkerMethod():
)
zigbeeConnectionMutex.release()
- #time.sleep(8)
time.sleep(1)
'''
- global sendSoceket
+ global sendSocket
# construct the message
message = "type: " + packetTypeStr.strip() + "\n"
message += "reason: " + reason + "\n"
# send message in a UDP packet
- sendSoceket.sendto(message,addr)
+ sendSocket.sendto(message,addr)
def processUdpZdoBindReqMessage(parsedData, addr):
return
else:
return
-
+
# get the short address for this device long address if possible
zigbeeLongShortAddrMutex.acquire()
if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
# if there is not one then we cannot since we need both the short and
# the long address
if(shortAddr != None):
+ print "> Short address exists", shortAddr
# get a request number
seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
# a bind request was made so must store and wait for response
# before we setup callbacks, so keep just the data we need to create the callback
- zigeeBindRequestMutex.acquire()
- zigeeBindRequest[seqNumber] = (parsedData['device_address_long'],
+ zigbeeBindRequestMutex.acquire()
+ zigbeeBindRequest[seqNumber] = (parsedData['device_address_long'],
parsedData['cluster_id'],
parsedData['packet_id'],
addr)
- zigeeBindRequestMutex.release()
+ zigbeeBindRequestMutex.release()
# construct the short and long addresses of the message for sending
# make sure they are in the correct format
pass
def processUdpZdoUnBindReqMessage(parsedData, addr):
- zibeeHACallbackMutex.acquire();
+ zigbeeHACallbackMutex.acquire();
if(zibeeHACallback.has_key(parsedData['device_address_long'], parsedData['cluster_id'])):
zibeeHACallback(parsedData['device_address_long'], parsedData['cluster_id']).remove(addr)
- zibeeHACallbackMutex.release()
+ zigbeeHACallbackMutex.release()
sendUdpSuccessFail(addr, 'zdo_unbind_request', parsedData['packet_id'], True)
global zigbeeLongShortAddrMutex
global zigbeeUnregisteredAddresses
global zigbeeUnregisteredAddressesMutex
- global sendSoceket
+ global sendSocket
print "process send address"
message += "response: success\n"
# tell client that we got their request
- sendSoceket.sendto(message,addr)
+ sendSocket.sendto(message,addr)
print "responding", message
# construct
-#made by changwoo
+# Added by Changwoo
def processUdpEnrollmentResponse(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
-#made by changwoo
+# Added by Changwoo
def processUdpZclWriteAttributesMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
payloadData += '\x02'
payloadData += '\x10\x00'
payloadData += '\xF0'
-# payloadData += '\xDA\x9A\xD9\x40\x00\xA2\x13\x00'
payloadData += hexStringToZigbeeHexString(changeEndian(ZIGBEE_DEVICE_ADDRESS))
zigbeeConnectionMutex.acquire()
sendUdpSuccessFail(addr, 'zcl_write_attributes', parsedData['packet_id'], False, 'short_address_unknown')
pass
-#made by changwoo
+# Added by Changwoo
def processUdpZclChangeSwitchReqMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
pass
-#made by Jiawei
+# Added by Jiawei
def processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
sendUdpSuccessFail(addr, 'lock_or_unlock_door_request', parsedData['packet_id'], False, 'short_address_unknown')
-#made by Jiawei
+# Added by Jiawei
def processUdpZclReadDoorStatusReqMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
- # framecontrol = hexStringToZigbeeHexString(parsedData['framecontrol'])
- # commandframe = hexStringToZigbeeHexString(parsedData['commandframe'])
- # attribute_id = hexStringToZigbeeHexString(parsedData['attribute_id'])
# create and send binding command
zigbeeConnectionMutex.acquire()
sendUdpSuccessFail(addr, 'read_door_status_request', parsedData['packet_id'], False, 'short_address_unknown')
-# made by changwoo
+# Added by Changwoo
def processUdpBroadcastingRouteRecordReqMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
shortAddr = None
pass
-#made by changwoo
+# Added by Changwoo
def processUdpManagementPermitJoiningReqMessage(parsedData, addr):
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
global matchDescriptorReqSingleton
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
global zigbeeLongShortAddr
global zigbeeLongShortAddrMutex
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
# do nothing if wrong source
- #if addr == SYSTEM_MASTER_ADDRESS or addr == SYSTEM_MASTER_ADDRESS2 or addr == SYSTEM_MASTER_ADDRESS3 :
if addr == SYSTEM_MASTER_ADDRESS :
key = (parsedData['ip_address'], int(parsedData['port']))
if (zigbeeAddressAuthorityDict.has_key(key)):
parsedData -- Pre-parsed (into a dict) data from message.
'''
- global zigeeBindRequestMutex
- global zigeeBindRequest
+ global zigbeeBindRequestMutex
+ global zigbeeBindRequest
global zigbeeConnectionMutex
global zigbeeConnection
global ManagementPermitJoiningReqSuccess
global deviceAnnouncementSingleton
global seqNumberForNotification
- #made by Jiawei
+ # Added by Jiawei
#doorlock response
if (parsedData['cluster'] == '\x01\x01' and parsedData['profile'] == '\x01\x04'):
zclSeqNumber = parsedData['rf_data'][1]
if(tup == None):
# cant really do anything here
return
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
elif command == '\x07':
status = rfdata[3]
print ''
if(tup == None):
# cant really do anything here
return
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
else:
print "Configure report unsuccessfully, status =", zigbeeHexStringToHexString(status)
elif(command == '\x0A'):
# get callback clients to respond to
callbackIndex = (zigbeeHexStringToHexString(parsedData['source_addr_long']), zigbeeHexStringToHexString(parsedData['cluster']))
retAddr = None
- zibeeHACallbackMutex.acquire()
+ zigbeeHACallbackMutex.acquire()
if(zibeeHACallback.has_key(callbackIndex)):
retAddr = zibeeHACallback[callbackIndex]
- zibeeHACallbackMutex.release()
+ zigbeeHACallbackMutex.release()
# no one to respond to so do nothing here
if(retAddr == None):
return
for ra in retAddr:
- sendSoceket.sendto(message,ra)
+ sendSocket.sendto(message,ra)
return
# if this is a ZDO message/response
- #print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
- #print parsedData
- #print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
if(parsedData['profile'] == '\x00\x00'):
- # made by changwoo
+ # Added by Changwoo
# if this is a Match Descriptor Request so we need to answer.
if(parsedData['cluster'] == '\x00\x06' and matchDescriptorReqSingleton):
zigbeeConnectionMutex.acquire()
# if this is a device announcement so we can get some useful data from it
elif(parsedData['cluster'] == '\x00\x13' and deviceAnnouncementSingleton):
- #print parsedData
# pick out the correct parts of the payload
longAddr = zigbeeHexStringToHexString(parsedData['rf_data'][3:11])
shortAddr = zigbeeHexStringToHexString(parsedData['rf_data'][1:3])
zigbeeUnregisteredAddresses.remove(longAddr)
zigbeeUnregisteredAddressesMutex.release()
-
- # made by changwoo
+ # Added by Changwoo
zigbeeConnectionMutex.acquire()
zigbeeConnection.send('tx_explicit',
frame_id='\x08',
# get the status and sequence number from the message
seqNumber = parsedData['rf_data'][0]
statusCode = parsedData['rf_data'][1]
- print ">response to a zdo bind_req message parsedData>"
+ print "> response to a zdo bind_req message parsedData"
# get the bind tuple information
# for this specific bind request
tup = None
- zigeeBindRequestMutex.acquire()
- if(zigeeBindRequest.has_key(ord(seqNumber))):
- tup = zigeeBindRequest[ord(seqNumber)]
- zigeeBindRequestMutex.release()
+ zigbeeBindRequestMutex.acquire()
+ if(zigbeeBindRequest.has_key(ord(seqNumber))):
+ tup = zigbeeBindRequest[ord(seqNumber)]
+ zigbeeBindRequestMutex.release()
if(tup == None):
# cant really do anything in this case...
# add a callback for this specific device and cluster
# to the HA callback dict
- zibeeHACallbackMutex.acquire();
+ zigbeeHACallbackMutex.acquire();
if(zibeeHACallback.has_key((tup[0], tup[1]))):
if(tup[3] not in zibeeHACallback[(tup[0], tup[1])]):
zibeeHACallback[(tup[0], tup[1])].append(tup[3])
else:
zibeeHACallback[(tup[0], tup[1])] = [tup[3]]
- zibeeHACallbackMutex.release()
-
+ zigbeeHACallbackMutex.release()
+
# send success message
sendUdpSuccessFail(tup[3], 'zdo_bind_request', tup[2], True)
+
+ print "> Success message sent!"
# Not Supported
elif (ord(statusCode) == 170):
# if this is a response to a short address query
elif(parsedData['cluster'] == '\x80\x00'):
- print ">response to a short address query 0x8000"
+ #print ">response to a short address query 0x8000"
# get a status code
statusCode = parsedData['rf_data'][0]
zigbeeLongShortAddr[longAddr] = shortAddr
zigbeeLongShortAddrMutex.release()
- #made by changwoo
+ # Added by Changwoo
elif(parsedData['cluster'] == '\x80\x06'):
print ''
print '[ 0x8006 ] get Match Descriptor Response'
print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
- #made by changwoo
+ # Added by Changwoo
elif(parsedData['cluster'] == '\x80\x36'):
print ''
print '[ 0x8036 ] get Management Permit Joining Response'
ManagementPermitJoiningReqSuccess = True
- #made by changwoo
+ # Added by Changwoo
else :
print ''
print '[ '+zigbeeHexStringToHexString(parsedData['cluster'])+' ] ...'
zclCommand = parsedData['rf_data'][2]
zclStatus = parsedData['rf_data'][3]
- #made by changwoo
+ # Added by Changwoo
if(zclCommand == '\x00'):
print ''
print '> ('+zigbeeHexStringToHexString(zclStatus)+') notification! : '+ zigbeeHexStringToHexString( parsedData['rf_data'] )
message += "attributes: success"
message += "\n"
# send the socket
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
print(">port : ", tup[0][1])
message = message[0:len(message) - 1]
message += "\n"
# send the socket
- sendSoceket.sendto(message,tup[0])
-
+ sendSocket.sendto(message,tup[0])
-
-
- # made by changwoo
- # this is a zcl write attribute response
+ # Added by Changwoo
+ # this is a zcl write attribute response
elif(zclCommand == '\x04'):
# get the zcl payload
message += "attributes: success"
message += "\n"
# send the socket
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
print ''
print '[ 0x0500 ] get Write Attribute Response success'
print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
# if all the configurations are a success then only send back a success
# based on zigbee specs
message += "all_success \n";
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
else:
attibuteResponseList = []
message = message[0:len(message) - 1]
message += "\n"
- sendSoceket.sendto(message,tup[0])
+ sendSocket.sendto(message,tup[0])
# this is a zcl report attribute message
elif(zclCommand == '\x0a'):
# get callback clients to respond to
callbackIndex = (zigbeeHexStringToHexString(parsedData['source_addr_long']), zigbeeHexStringToHexString(parsedData['cluster']))
retAddr = None
- zibeeHACallbackMutex.acquire()
+ zigbeeHACallbackMutex.acquire()
if(zibeeHACallback.has_key(callbackIndex)):
retAddr = zibeeHACallback[callbackIndex]
- zibeeHACallbackMutex.release()
+ zigbeeHACallbackMutex.release()
# no one to respond to so do nothing here
if(retAddr == None):
# send to all client that want this callback
for ra in retAddr:
- sendSoceket.sendto(message,ra)
+ sendSocket.sendto(message,ra)
# -----------------------------------------------------------------------------
# Communication Callback/Parse Methods
'''
#print "=================================================================="
#print ''
- print "New Zigbee Message"
+ #print "New Zigbee Message"
#printMessageData(parsedData)
# dispatch to the correct zigbee handler
if (parsedData['id'] == 'at_response'):
- print "parsedDataID : at_response"
+ #print "parsedDataID : at_response"
processZigbeeATCommandMessage(parsedData)
elif (parsedData['id'] == 'rx_explicit'):
- print "parsedDataID : rx_explicit"
+ #print "parsedDataID : rx_explicit"
processZigbeeRxExplicitCommandMessage(parsedData)
- else:
- print "Unknown API format"
+ #else:
+ #print "Unknown API format"
#print "=================================================================="
elif(parsedData["type"] == "zcl_read_attributes"):
processUdpZclReadAttributesMessage(parsedData, addr)
elif(parsedData["type"] == "zcl_configure_reporting"):
- print "> zcl_configure_reporting call"
+ print "> processUdpZclConfigureReportingMessage call"
processUdpZclConfigureReportingMessage(parsedData, addr)
elif(parsedData["type"] == "policy_set"):
processUdpPolicySet(parsedData, addr)
elif(parsedData["type"] == "policy_clear"):
processUdpPolicyClear(parsedData, addr)
- elif(parsedData["type"] == "management_permit_joining_request"): #made by changwoo
- processUdpManagementPermitJoiningReqMessage(parsedData, addr)
- elif(parsedData["type"] == "zcl_write_attributes" and ManagementPermitJoiningReqSuccess): #made by changwoo
+ elif(parsedData["type"] == "management_permit_joining_request"): # Added by Changwoo
+ processUdpManagementPermitJoiningReqMessage(parsedData, addr)
+ elif(parsedData["type"] == "zcl_write_attributes" and ManagementPermitJoiningReqSuccess): # Added by Changwoo
processUdpZclWriteAttributesMessage(parsedData, addr)
- elif(parsedData["type"] == "zcl_enrollment_response"): #made by changwoo
- processUdpEnrollmentResponse(parsedData, addr)
- elif(parsedData["type"] == "zdo_broadcast_route_record_request"): #made by changwoo
- processUdpBroadcastingRouteRecordReqMessage(parsedData, addr)
- elif(parsedData["type"] == "zcl_change_switch_request"): #made by changwoo
- processUdpZclChangeSwitchReqMessage(parsedData, addr)
- elif(parsedData["type"] == "zcl_lock_or_unlock_door_request"): #made by Jiawei
+ elif(parsedData["type"] == "zcl_enrollment_response"): # Added by Changwoo
+ processUdpEnrollmentResponse(parsedData, addr)
+ elif(parsedData["type"] == "zdo_broadcast_route_record_request"): # Added by Changwoo
+ processUdpBroadcastingRouteRecordReqMessage(parsedData, addr)
+ elif(parsedData["type"] == "zcl_change_switch_request"): # Added by Changwoo
+ processUdpZclChangeSwitchReqMessage(parsedData, addr)
+ elif(parsedData["type"] == "zcl_lock_or_unlock_door_request"): # Added by Jiawei
processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr)
- elif(parsedData["type"] == "zcl_read_door_status_request"): #made by Jiawei
+ elif(parsedData["type"] == "zcl_read_door_status_request"): # Added by Jiawei
processUdpZclReadDoorStatusReqMessage(parsedData, addr)
else:
#print "unknown Packet: " + parsedData["type"]
# setup incoming UDP socket and bind it to self and specified UDP port
# sending socket does not need to be bound to anything
- #receiveSoceket.bind(('192.168.2.227', UDP_RECEIVE_PORT))
- receiveSoceket.bind(('192.168.1.192', UDP_RECEIVE_PORT))
+ receiveSocket.bind((LOCAL_ADDRESS, UDP_RECEIVE_PORT))
# create the thread that does short address lookups
addressUpdateWorkerThread = threading.Thread(target=addressUpdateWorkerMethod)
while(True):
print "=================================================================="
print ''
- print "Waiting..."
+ print "Waiting..."
print "=================================================================="
# wait for an incoming UDP packet
# this is a blocking call
- data, addr = receiveSoceket.recvfrom(4096)
+ data, addr = receiveSocket.recvfrom(4096)
# handle the UDP packet appropriately
handleNewUdpPacket(data, addr)
# make sure to close all the connections
zigbeeConnection.halt()
- receiveSoceket.close()
- sendSoceket.close()
+ receiveSocket.close()
+ sendSocket.close()
if __name__ == "__main__":
# call main function since this is being run as the start