Completing xbee_driver.py with door lock subroutines
[iot2.git] / benchmarks / other / XbeePythonDriver / xbee_driver.py
index 99e93ae948319a18c75e861be05737f96033e139..955ed9cec7e11d6e4f82f0cf030ea3fed268b766 100644 (file)
@@ -16,7 +16,10 @@ import threading
 # -----------------------------------------------------------------------------
 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.2.108", 12345) # ip address and portof the system master node
+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)
 
 # time for messages to wait for a response before the system clears away that 
 # sequence identifier
@@ -79,6 +82,7 @@ doEndFlag = False
 sendSoceket = socket(AF_INET, SOCK_DGRAM)
 receiveSoceket = socket(AF_INET, SOCK_DGRAM)
 
+
 # zigbee address authority list
 zigbeeAddressAuthorityDict = dict()
 
@@ -369,7 +373,8 @@ def getConnectedRadioLongAddress():
         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(2)
+        time.sleep(0.5)
 
 def addressUpdateWorkerMethod():
     ''' Method to keep refreshing the short addresses of the known zigbee devices'''
@@ -421,7 +426,8 @@ def addressUpdateWorkerMethod():
                                 )
             zigbeeConnectionMutex.release()
 
-        time.sleep(8)
+        #time.sleep(8)
+        time.sleep(1)
 
 
 # -------------
@@ -578,6 +584,8 @@ def processUdpSendAddressMessage(parsedData, addr):
     zigbeeUnregisteredAddresses.append(parsedData['device_address_long'])
     zigbeeUnregisteredAddressesMutex.release()
 
+
+
 #made by changwoo
 def processUdpEnrollmentResponse(parsedData, addr):
 
@@ -791,6 +799,141 @@ def processUdpZclChangeSwitchReqMessage(parsedData, addr):
         pass
 
 
+#made by Jiawei
+def processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr):
+
+    global zigbeeLongShortAddr
+    global zigbeeLongShortAddrMutex
+    global zigeeBindRequestMutex
+    global zigeeBindRequest
+    global zigbeeConnectionMutex
+    global zigbeeConnection
+    shortAddr = None
+
+    # get the short address for this device long address if possible
+    zigbeeLongShortAddrMutex.acquire()
+    if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
+        shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
+    zigbeeLongShortAddrMutex.release()
+
+
+    # if there is a short address than we can send the message
+    # if there is not one then we cannot since we need both the short and
+    # the long address
+    if(shortAddr != None):
+
+        # get a request number
+        seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
+
+        # send back failure
+        if(seqNumber == -1):
+
+            # send an error message, could not get a sequence number to use at this time
+            sendUdpSuccessFail(addr, 'lock_or_unlock_door_request', parsedData['packet_id'], False, 'out_of_space')
+            return
+
+        # get the info for sending
+        destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
+        destShortAddr = hexStringToZigbeeHexString(shortAddr)
+        dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
+        clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
+        profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
+        value = hexStringToZigbeeHexString(parsedData['value'])
+
+        # create and send binding command
+        zigbeeConnectionMutex.acquire()
+
+        zigbeeConnection.send('tx_explicit',
+                            frame_id='\x40',
+                            dest_addr_long=destLongAddr,
+                            dest_addr=destShortAddr,
+                            src_endpoint='\x01',
+                            dest_endpoint=dstEndpoint,
+                            cluster=clusterId,  
+                            profile=profileId,
+                            data='\x01'+chr(seqNumber)+value
+                            )
+        time.sleep(1)
+        if value == '\x01':
+            print '> The door lock is unlocked'
+        elif value == '\x00':
+            print '> The door lock is locked'
+        else:
+            print '> Unknown door lock value: ' + str(value)
+
+        zigbeeConnectionMutex.release()
+
+
+    else:
+        # send a fail response
+        sendUdpSuccessFail(addr, 'lock_or_unlock_door_request', parsedData['packet_id'], False, 'short_address_unknown')
+
+
+#made by Jiawei
+def processUdpZclReadDoorStatusReqMessage(parsedData, addr):
+
+    global zigbeeLongShortAddr
+    global zigbeeLongShortAddrMutex
+    global zigeeBindRequestMutex
+    global zigeeBindRequest
+    global zigbeeConnectionMutex
+    global zigbeeConnection
+    shortAddr = None
+
+    # get the short address for this device long address if possible
+    zigbeeLongShortAddrMutex.acquire()
+    if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
+        shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
+    zigbeeLongShortAddrMutex.release()
+
+
+    # if there is a short address than we can send the message
+    # if there is not one then we cannot since we need both the short and
+    # the long address
+    if(shortAddr != None):
+
+        # get a request number
+        seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
+
+        # send back failure
+        if(seqNumber == -1):
+
+            # send an error message, could not get a sequence number to use at this time
+            sendUdpSuccessFail(addr, 'read_door_status_request', parsedData['packet_id'], False, 'out_of_space')
+            return
+
+        # get the info for sending
+        destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
+        destShortAddr = hexStringToZigbeeHexString(shortAddr)
+        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()
+
+        zigbeeConnection.send('tx_explicit',
+                            frame_id='\x40',
+                            dest_addr_long=destLongAddr,
+                            dest_addr=destShortAddr,
+                            src_endpoint='\x01',
+                            dest_endpoint=dstEndpoint,
+                            cluster=clusterId,  
+                            profile=profileId,
+                            data='\x10' + chr(seqNumber) + '\x00' + '\x00\x00'
+                            )
+        time.sleep(1)
+
+        zigbeeConnectionMutex.release()
+        print "send read door status"
+
+    else:
+        # send a fail response
+        sendUdpSuccessFail(addr, 'read_door_status_request', parsedData['packet_id'], False, 'short_address_unknown')
+
 
 # made by changwoo
 def processUdpBroadcastingRouteRecordReqMessage(parsedData, addr):
@@ -1102,7 +1245,6 @@ def processUdpZclConfigureReportingMessage(parsedData, addr):
         sendUdpSuccessFail(addr, 'zcl_configure_reporting', parsedData['packet_id'], False, 'short_address_unknown')
         pass
 
-
 def processUdpPolicySet(parsedData, addr):
     ''' Method handle a policy set message
 
@@ -1116,8 +1258,7 @@ def processUdpPolicySet(parsedData, addr):
 
     # 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 :
-    if addr[0] == SYSTEM_MASTER_ADDRESS[0]:
+    if addr == SYSTEM_MASTER_ADDRESS :
         key = (parsedData['ip_address'], int(parsedData['port']))
         if (zigbeeAddressAuthorityDict.has_key(key)):
             zigbeeAddressAuthorityDict[key].append(parsedData['device_address_long'])
@@ -1211,6 +1352,170 @@ def processZigbeeRxExplicitCommandMessage(parsedData):
     global deviceAnnouncementSingleton
     global seqNumberForNotification
 
+    #made by Jiawei
+    #doorlock response
+    if (parsedData['cluster'] == '\x01\x01' and parsedData['profile'] == '\x01\x04'):
+        zclSeqNumber = parsedData['rf_data'][1]
+        tup = None
+        zigbeeSeqNumberToClientMutex.acquire()
+        if(zigbeeSeqNumberToClient.has_key(ord(zclSeqNumber))):
+            tup = zigbeeSeqNumberToClient[ord(zclSeqNumber)]
+            del zigbeeSeqNumberToClient[ord(zclSeqNumber)]
+        zigbeeSeqNumberToClientMutex.release()
+
+        rfdata = parsedData['rf_data']
+        framecontrol = rfdata[0]
+        command = rfdata[2]
+
+        if tup != None:
+            packetId = tup[2]
+        
+        if framecontrol == '\x19':
+            if(command == '\x00'):
+                print ''
+                print "( 0x0101 ) Door Lock: Lock Door Response"
+                print time.strftime("%H:%M:%S", time.localtime())
+                value = rfdata[3]
+                if(value == '\x00'):
+                    print "Door locked successfully"
+                else:
+                    print "An error occurred in door locking"
+            elif(command == '\x01'):
+                print ''
+                print "( 0x0101 ) Door Lock: Unlock Door Response"
+                print time.strftime("%H:%M:%S", time.localtime())
+                value = rfdata[3]
+                if(value == '\x00'):
+                    print "Door unlocked successfully"
+                else:
+                    print "An error occurred in door unlocking"
+            return
+        elif framecontrol == '\x18':
+            if(command == '\x01'):
+                attributeId = (ord(rfdata[3]) * 256) + ord(rfdata[4])
+                if attributeId == 0x0000:
+                    value = rfdata[7]
+                    print "Door status: "
+                    if value == '\x00':
+                        print "Not fully locked"
+                    elif value == '\x01':
+                        print "Locked"
+                    elif value == '\x02':
+                        print "Unlocked"
+                    else:
+                        print "Unknown value: " + zigbeeHexStringToHexString(value)
+                           
+                    message = "type : zcl_read_attributes_response \n"
+                    message += "packet_id: " + packetId + "\n"
+                    message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
+                    message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
+                    message += "attributes: "
+
+                    attrIdStr = "%0.4x" % attributeId
+                    attrIdStr = changeEndian(attrIdStr)
+                    message += attrIdStr
+                    message += ", "
+
+                    zclPayload = parsedData['rf_data'][3:]
+                    zclPayload = zclPayload[3:]
+                    attributeType = zclPayload[0]
+                    message += "%0.2x" % ord(attributeType)
+                    message += ", "
+
+                    message += "success"
+                    message += ", "
+
+                    message += "%0.2x" % ord(value)
+                    message += ";"
+
+                    message += ";"
+                    
+                    message = message[0:len(message) - 1]
+                    message += "\n"
+
+                    # no one to send the response to so just move on
+                    if(tup == None):
+                        # cant really do anything here
+                        return
+                    sendSoceket.sendto(message,tup[0])
+            elif command == '\x07':
+                status = rfdata[3]
+                print ''
+                print "( 0x0101 ) Door Lock: Configure reporting response"
+                print 'rfdata : ' + zigbeeHexStringToHexString(rfdata)
+                if status == '\x00':
+                    print "Configure report successfully"
+                    message = "type : zcl_configure_reporting_response \n"
+                    message += "packet_id: " + packetId + "\n"
+                    message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
+                    message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
+                    message += "attributes: " 
+                    message +=  "all_success \n";
+
+                    # no one to send the response to so just move on
+                    if(tup == None):
+                        # cant really do anything here
+                        return
+                    sendSoceket.sendto(message,tup[0])
+                else:     
+                    print "Configure report unsuccessfully, status =", zigbeeHexStringToHexString(status)
+            elif(command == '\x0A'):
+                print "New update"
+                attributeId = (ord(rfdata[3]) * 256) + ord(rfdata[4])
+                if attributeId == 0x0000:
+                    value = rfdata[6]
+                    if value == '\x00':
+                        print "Not fully locked"
+                    elif value == '\x01':
+                        print "Locked"
+                    elif value == '\x02':
+                        print "Unlocked"
+                    else:
+                        print "Unknown value: " + zigbeeHexStringToHexString(value)
+
+                    message = "type : zcl_read_attributes_response \n"
+                    message += "packet_id: " + ("%0.2x" % ord(zclSeqNumber)) + "\n"
+                    message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
+                    message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
+                    message += "attributes: "
+
+                    attrIdStr = "%0.4x" % attributeId
+                    attrIdStr = changeEndian(attrIdStr)
+                    message += attrIdStr
+                    message += ", "
+
+                    zclPayload = parsedData['rf_data'][3:]
+                    zclPayload = zclPayload[3:]
+                    attributeType = zclPayload[0]
+                    message += "%0.2x" % ord(attributeType)
+                    message += ", "
+
+                    message += "success"
+                    message += ", "
+
+                    message += "%0.2x" % ord(value)
+                    message += ";"
+
+                    message += ";"
+                    
+                    message = message[0:len(message) - 1]
+                    message += "\n"
+
+                    # get callback clients to respond to
+                    callbackIndex = (zigbeeHexStringToHexString(parsedData['source_addr_long']), zigbeeHexStringToHexString(parsedData['cluster']))
+                    retAddr = None
+                    zibeeHACallbackMutex.acquire()
+                    if(zibeeHACallback.has_key(callbackIndex)):
+                        retAddr = zibeeHACallback[callbackIndex]
+                    zibeeHACallbackMutex.release()
+
+                    # no one to respond to so do nothing here
+                    if(retAddr == None):
+                        return
+                    for ra in retAddr:
+                        sendSoceket.sendto(message,ra)
+            return
+
     # if this is a ZDO message/response
     #print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
     #print parsedData
@@ -1744,6 +2049,8 @@ def handleNewZigbeeMessage(parsedData):
 
     #print "=================================================================="
 
+
+
 def handleNewUdpPacket(data, addr):
     ''' Method to parse and handle an incoming UDP packet.
 
@@ -1807,8 +2114,12 @@ def handleNewUdpPacket(data, addr):
            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
+            processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr)
+        elif(parsedData["type"] == "zcl_read_door_status_request"): #made by Jiawei
+            processUdpZclReadDoorStatusReqMessage(parsedData, addr)
         else:
-            print "unknown Packet: " + parsedData["type"]
+            #print "unknown Packet: " + parsedData["type"]
             pass
     except:
         # if we ever get here then something went wrong and so just ignore this
@@ -1851,7 +2162,7 @@ def main():
     # 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.2.192', UDP_RECEIVE_PORT))
+    receiveSoceket.bind(('192.168.1.192', UDP_RECEIVE_PORT))
 
     # create the thread that does short address lookups
     addressUpdateWorkerThread = threading.Thread(target=addressUpdateWorkerMethod)