955ed9cec7e11d6e4f82f0cf030ea3fed268b766
[iot2.git] / benchmarks / other / XbeePythonDriver / xbee_driver.py
1 from xbee import ZigBee
2 import serial
3 import time
4 import collections
5 import sys
6 import getopt
7 from socket import *
8 import traceback
9 from threading import Thread, Lock
10 import random
11 import threading
12
13
14 # -----------------------------------------------------------------------------
15 # Constants ans Pseudo-Constants
16 # -----------------------------------------------------------------------------
17 UDP_RECEIVE_PORT = 5005        # port used for incoming UDP data
18 UDP_RECEIVE_BUFFER_SIZE = 4096  # max buffer size of an incoming UDP packet
19 SYSTEM_MASTER_ADDRESS = ("192.168.1.198", 12345) # ip address and portof the system master node
20 #SYSTEM_MASTER_ADDRESS = ("192.168.2.108", 22222) # ip address and portof the system master node
21 #SYSTEM_MASTER_ADDRESS2 = ("192.168.2.108", 11111)
22 #SYSTEM_MASTER_ADDRESS3 = ("192.168.2.108", 11222)
23
24 # time for messages to wait for a response before the system clears away that 
25 # sequence identifier
26 ZIGBEE_SEQUENCE_NUMBER_CLEAR_TIME_SEC = 5 
27
28 #ZIGBEE_SERIAL_PORT = "/dev/cu.usbserial-DN01DCRH"  # USB-Serial port of local radio
29 ZIGBEE_SERIAL_PORT = "/dev/ttyUSB0"
30 ZIGBEE_SERIAL_BAUD = 115200                       # Baud rate for above port
31
32 # address of our local zigbee radio
33 #ZIGBEE_DEVICE_ADDRESS = "0013a20040d99cb4"
34 ZIGBEE_DEVICE_ADDRESS = "xxxxxxxxxxxxxxxx"
35
36 # -----------------------------------------------------------------------------
37 # Global Variables and Objects
38 # -----------------------------------------------------------------------------
39
40 # signals to see if a request needs to be made
41 didGetLocalRadioHighAddress = False;
42 didGetLocalRadioLowAddress = False;
43
44 # zigbee communications object and its mutex
45 zigbeeConnection = None
46 zigbeeConnectionMutex = Lock()
47
48 #singleton mabe by changwoo
49 matchDescriptorReqSingleton = True
50 deviceAnnouncementSingleton = True
51 ManagementPermitJoiningReqSuccess = False
52
53 # zigbee mapping from long to short object dict
54 zigbeeLongShortAddr = dict()
55 zigbeeLongShortAddrMutex = Lock()
56
57 # zigbee mapping from a sequence number to a client 
58 # for correct response handling
59 zigbeeSeqNumberToClient = dict()
60 zigbeeSeqNumberToClientMutex = Lock()
61
62 zigeeBindRequest = dict()
63 zigeeBindRequestMutex = Lock()
64
65 # Keeps record of where to send callbacks to when an HA message is received
66 zibeeHACallback = dict()
67 zibeeHACallbackMutex = Lock()
68
69
70 # Keeps a record of device addresses whose short addresses have not been 
71 # determined yet
72 zigbeeUnregisteredAddresses = []
73 zigbeeUnregisteredAddressesMutex = Lock()
74
75 # used to signal all threads to end
76 doEndFlag = False
77
78
79 # 2 sockets, one for sending (not bound to a port manually)
80 # and one for receiving, known port binding by application
81 # both UDP sockets
82 sendSoceket = socket(AF_INET, SOCK_DGRAM)
83 receiveSoceket = socket(AF_INET, SOCK_DGRAM)
84
85
86 # zigbee address authority list
87 zigbeeAddressAuthorityDict = dict()
88
89 # made by changwoo
90 seqNumberForNotification = dict()
91
92 # -----------------------------------------------------------------------------
93 # Helper Methods
94 # -----------------------------------------------------------------------------
95 def reverseShortAddress(shortAddr):
96     result = shortAddr[len(shortAddr)/2:]+shortAddr[0:len(shortAddr)/2]
97     return result
98
99 def parseCommandLineArgs(argv):
100     global ZIGBEE_SERIAL_PORT
101     global ZIGBEE_SERIAL_BAUD
102     try:
103         opts, args = getopt.getopt(
104             argv, "hp:b:u:", ["port=", "baud=", "udpport="])
105
106     except getopt.GetoptError:
107         print 'test.py -p <serial_port> -b <baud_rate> -u <udp_port>'
108         sys.exit(2)
109
110     for opt, arg in opts:
111         if opt == '-h':
112             print 'test.py -p <serial_port> -b <baud_rate> -u <udp_port>'
113             sys.exit()
114
115         elif opt in ("-p", "--port"):
116             ZIGBEE_SERIAL_PORT = arg
117
118         elif opt in ("-b", "--baud"):
119             try:
120                 ZIGBEE_SERIAL_BAUD = int(arg)
121             except ValueError:
122                 print "Buad rate must be an integer"
123                 sys.exit()
124
125
126 # -------------
127 # Convenience (Stateless)
128 # -------------
129
130 def hexListToChar(hexList):
131     ''' Method to convert a list/string of characters into their corresponding values
132
133         hexList -- list or string of hex characters
134     '''
135     retString = ""
136     for h in hexList:
137         retString += chr(int(h, 16))
138     return retString
139
140 def splitByN(seq, n):
141     ''' Method to split a string into groups of n characters
142
143         seq -- string
144         n -- group by number
145     '''
146     return [seq[i:i+n] for i in range(0, len(seq), n)]
147
148 def changeEndian(hexString):
149     ''' Method to change endian of a hex string
150
151         hexList -- string of hex characters
152     '''
153     split = splitByN(hexString, 2) # get each byte
154     split.reverse();               # reverse ordering of the bytes
155
156     # reconstruct 
157     retString = ''
158     for s in split:
159         retString += s
160     return retString
161
162 def printMessageData(data):
163     ''' Method to print a zigbee message to the console
164
165         data -- pre-parsed zigbee message
166     '''
167     for d in data:
168         print d, ' : ',
169         for e in data[d]:
170             print "{0:02x}".format(ord(e)),
171         if (d == 'id'):
172             print "({})".format(data[d]),
173         print
174
175 def hexStringToZigbeeHexString(hexString):
176     ''' Method to change a hex string to a string of characters with the hex values
177
178         hexList -- string of hex characters
179     '''
180     return hexListToChar(splitByN(hexString, 2))
181
182 def zigbeeHexStringToHexString(zigbeeHexString):
183     ''' Method to change string of characters with the hex values to a hex string
184
185         hexList -- string of characters with hex values
186     '''
187
188     retString = ''
189     for e in zigbeeHexString:
190         retString += "{0:02x}".format(ord(e))
191     return retString
192
193 def zclDataTypeToBytes(zclPayload):
194     ''' Method to determine data length of a zcl attribute
195
196         zclPayload -- ZCL payload data, must have dataType as first byte
197     '''
198     attrType = ord(zclPayload[0])
199
200     if(attrType == 0x00):
201         return 0
202     elif (attrType == 0x08):
203         return 1
204     elif (attrType == 0x09):
205         return 2
206     elif (attrType == 0x0a):
207         return 3
208     elif (attrType == 0x0b):
209         return 4
210     elif (attrType == 0x0c):
211         return 5
212     elif (attrType == 0x0d):
213         return 6
214     elif (attrType == 0x0e):
215         return 7
216     elif (attrType == 0x0f):
217         return 8
218     elif (attrType == 0x10):
219         return 1
220     elif (attrType == 0x18):
221         return 1
222     elif (attrType == 0x19):
223         return 2
224     elif (attrType == 0x1a):
225         return 3
226     elif (attrType == 0x1b):
227         return 4
228     elif (attrType == 0x1c):
229         return 5
230     elif (attrType == 0x1d):
231         return 6
232     elif (attrType == 0x1e):
233         return 7
234     elif (attrType == 0x1f):
235         return 8
236     elif (attrType == 0x20):
237         return 1
238     elif (attrType == 0x21):
239         return 2
240     elif (attrType == 0x22):
241         return 3
242     elif (attrType == 0x23):
243         return 4
244     elif (attrType == 0x24):
245         return 5
246     elif (attrType == 0x25):
247         return 6
248     elif (attrType == 0x26):
249         return 7
250     elif (attrType == 0x27):
251         return 8
252     elif (attrType == 0x28):
253         return 1
254     elif (attrType == 0x29):
255         return 2
256     elif (attrType == 0x2a):
257         return 3
258     elif (attrType == 0x2b):
259         return 4
260     elif (attrType == 0x2c):
261         return 5
262     elif (attrType == 0x2d):
263         return 6
264     elif (attrType == 0x2e):
265         return 7
266     elif (attrType == 0x2f):
267         return 8
268     elif (attrType == 0x30):
269         return 1
270     elif (attrType == 0x31):
271         return 2
272     elif (attrType == 0x38):
273         return 2
274     elif (attrType == 0x39):
275         return 4
276     elif (attrType == 0x3a):
277         return 8
278     elif (attrType == 0x41):
279         return ord(zclPayload[1])
280     elif (attrType == 0x42):
281         return ord(zclPayload[1])
282     elif (attrType == 0x43):
283         return ord(zclPayload[1]) + (256 * ord(zclPayload[2]))
284     elif (attrType == 0x44):
285         return ord(zclPayload[1]) + (256 * ord(zclPayload[2]))
286     elif (attrType == 0xe0):
287         return 4
288     elif (attrType == 0xe1):
289         return 4
290     elif (attrType == 0xe2):
291         return 4
292     elif (attrType == 0xe8):
293         return 2
294     elif (attrType == 0xe9):
295         return 2
296     elif (attrType == 0xea):
297         return 4
298     elif (attrType == 0xf0):
299         return 8
300     elif (attrType == 0xf1):
301         return 16
302     elif (attrType == 0xff):
303         return 0
304
305 # -------------
306 # Other
307 # -------------
308
309 def createSequenceNumberForClient(addr, packetId):
310     ''' Method to get and store a sequence number with a specific client 
311         for a specific message.
312
313         addr -- UDP address of the client to associate with the seq. number
314         packetId -- packet id from the UDP packet
315     '''
316     # keep trying to find a number to return
317     while(True):
318
319         # get the current time
320         epoch_time = int(time.time())
321
322         # get the current list of used numbers
323         zigbeeSeqNumberToClientMutex.acquire()
324         keysList = zigbeeSeqNumberToClient.keys()
325         zigbeeSeqNumberToClientMutex.release()
326     
327         # if all the numbers are already used
328         if(len(keysList) == 256):
329
330             # get a list of all the items
331             zigbeeSeqNumberToClientMutex.acquire()
332             itemsList = zigbeeSeqNumberToClient.items()
333             zigbeeSeqNumberToClientMutex.release()
334
335             # search for a number that is old enough to get rid of otherwise use -1
336             seqNum = -1
337             for item in itemsList:
338                 if((epoch_time - item[1][1]) > ZIGBEE_SEQUENCE_NUMBER_CLEAR_TIME_SEC):
339                     seqNumber = item[0]
340                     break
341
342             if(seqNum != -1):
343                 # replace the record with new data if we found one to replace
344                 zigbeeSeqNumberToClientMutex.acquire()
345                 zigbeeSeqNumberToClient[seqNumber] = (addr, epoch_time, packetId)
346                 zigbeeSeqNumberToClientMutex.release()
347
348             return seqNumber
349             
350         else:
351             # not all numbers used yet so pick one randomly
352             randNum = random.randrange(0,256)
353
354             # check if we are using the number yet
355             if(randNum not in keysList):
356
357                 # we are not so insert to keep track who this number is for and return it
358                 zigbeeSeqNumberToClientMutex.acquire()
359                 zigbeeSeqNumberToClient[randNum] = (addr, epoch_time, packetId)
360                 zigbeeSeqNumberToClientMutex.release()
361                 return randNum
362
363 def getConnectedRadioLongAddress():
364     """ Method to make sure we get the MAC address of our local radio"""
365     global zigbeeConnection
366     global zigbeeMutex
367
368     # keep looping until we get both the MSBs and the LSBs
369     while ((not didGetLocalRadioHighAddress) or (not didGetLocalRadioLowAddress)):
370
371         # reissue requests
372         zigbeeConnection.send('at', command="SH")
373         zigbeeConnection.send('at', command="SL")
374         
375         # sleep for a bit to give the radio time to respond before we check again
376         #time.sleep(2)
377         time.sleep(0.5)
378
379 def addressUpdateWorkerMethod():
380     ''' Method to keep refreshing the short addresses of the known zigbee devices'''
381     global doEndFlag
382     global zigbeeLongShortAddr
383     global zigbeeLongShortAddrMutex
384     global zigbeeUnregisteredAddresses
385     global zigbeeUnregisteredAddressesMutex
386     global zigbeeConnectionMutex
387     global zigbeeConnection
388
389     # keep looping until signaled to quit
390     while(not doEndFlag):
391
392         addrList = []
393
394         # add unregistered (short addresses unknown) devices so
395         # that we can look them up
396         zigbeeUnregisteredAddressesMutex.acquire()
397         addrList.extend(zigbeeUnregisteredAddresses)
398         zigbeeUnregisteredAddressesMutex.release()
399
400         # add the devices that we have short addresses for so we can 
401         # get their most recent short addresses
402         zigbeeLongShortAddrMutex.acquire()
403         addrList.extend(zigbeeLongShortAddr.keys())
404         zigbeeLongShortAddrMutex.release()
405
406         # Loop through all the addresses and send messages for each address
407         for ad in addrList:
408
409             # create payload for a query on the network for a short address
410             payload = '\x00'
411             payload += hexStringToZigbeeHexString(changeEndian(ad))
412             payload += '\x00'
413
414             # create and send binding command
415             zigbeeConnectionMutex.acquire()
416             
417             zigbeeConnection.send('tx_explicit',
418                                 frame_id='\x01',
419                                 dest_addr_long=hexStringToZigbeeHexString(ad),
420                                 dest_addr='\xff\xfd',
421                                 src_endpoint='\x00',
422                                 dest_endpoint='\x00',
423                                 cluster='\x00\x00',  
424                                 profile='\x00\x00',
425                                 data=payload
426                                 )
427             zigbeeConnectionMutex.release()
428
429         #time.sleep(8)
430         time.sleep(1)
431
432
433 # -------------
434 # UDP 
435 # -------------
436
437 def sendUdpSuccessFail(addr, packetTypeStr, packetIdStr, sucOrFail, reason=None):
438     ''' Method to send a success or fail back to a client.
439
440         addr -- UDP address to send packet to
441         packetTypeStr -- name of this specific packet
442         packetIdStr -- packet id to send
443         sucOrFail -- whether this is a success or fail message (True = success)
444         reason -- reason of failure (if needed, default is None)
445
446     '''
447
448     global sendSoceket
449
450     # construct the message
451     message = "type: " + packetTypeStr.strip() + "\n"
452     message += "packet_id: " + packetIdStr + "\n"
453
454     if(sucOrFail):
455         message += "response: success \n"
456     else:
457         message += "response: fail \n"
458         message += "reason: " + reason + "\n"
459
460     # send message in a UDP packet
461     sendSoceket.sendto(message,addr)
462
463 def processUdpZdoBindReqMessage(parsedData, addr):
464
465     shortAddr = None
466
467     if(zigbeeAddressAuthorityDict.has_key(addr)):
468         l = zigbeeAddressAuthorityDict[addr]
469         if(parsedData['device_address_long'] not in l):
470             return
471     else:
472         return
473
474     # get the short address for this device long address if possible
475     zigbeeLongShortAddrMutex.acquire()
476     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
477         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
478     zigbeeLongShortAddrMutex.release()
479
480     # if there is a short address than we can send the message
481     # if there is not one then we cannot since we need both the short and
482     # the long address
483     if(shortAddr != None):
484
485         # get a request number
486         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
487         
488         # send back failure
489         if(seqNumber == -1):
490
491             # send an error message, could not get a sequence number to use at this time
492             sendUdpSuccessFail(addr, 'zdo_bind_request', parsedData['packet_id'], False, 'out_of_space')
493             return
494
495         # a bind request was made so must store and wait for response 
496         # before we setup callbacks, so keep just the data we need to create the callback
497         zigeeBindRequestMutex.acquire()
498         zigeeBindRequest[seqNumber] = (parsedData['device_address_long'],
499                                         parsedData['cluster_id'], 
500                                         parsedData['packet_id'], 
501                                         addr)
502         zigeeBindRequestMutex.release()
503
504         # construct the short and long addresses of the message for sending
505         # make sure they are in the correct format
506         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
507         destShortAddr = hexStringToZigbeeHexString(shortAddr)
508
509         # create the payload data
510         payloadData = ""
511         payloadData += chr(seqNumber)
512         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['device_address_long']))
513         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['device_endpoint']))
514         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['cluster_id'])) 
515         payloadData += '\x03' 
516         payloadData += hexStringToZigbeeHexString(changeEndian(ZIGBEE_DEVICE_ADDRESS))
517         payloadData += '\x00'
518
519         # create and send binding command
520         zigbeeConnectionMutex.acquire()
521         zigbeeConnection.send('tx_explicit',
522                             frame_id='\x01',
523                             # frame_id=chr(seqNumber),
524                             dest_addr_long=destLongAddr,
525                             dest_addr=destShortAddr,
526                             src_endpoint='\x00',
527                             dest_endpoint='\x00',
528                             cluster='\x00\x21',  
529                             profile='\x00\x00',
530                             data=payloadData
531                             )
532         zigbeeConnectionMutex.release()
533
534
535     else:
536         # send a failure packet since there is no short address available
537         sendUdpSuccessFail(addr, 'zdo_bind_request', parsedData['packet_id'], False, 'short_address_unknown')
538         pass
539
540 def processUdpZdoUnBindReqMessage(parsedData, addr):
541     zibeeHACallbackMutex.acquire();
542     if(zibeeHACallback.has_key(parsedData['device_address_long'], parsedData['cluster_id'])):
543         zibeeHACallback(parsedData['device_address_long'], parsedData['cluster_id']).remove(addr)
544     zibeeHACallbackMutex.release()
545     sendUdpSuccessFail(addr, 'zdo_unbind_request', parsedData['packet_id'], True)
546
547
548
549 def processUdpSendAddressMessage(parsedData, addr):
550     ''' Method handle a send address command
551
552         parsedData -- Pre-parsed Data that was in the UDP packet.
553         addr -- Address (IP and Port) of the UDP packet origin.
554     '''
555     global zigbeeLongShortAddr
556     global zigbeeLongShortAddrMutex
557     global zigbeeUnregisteredAddresses
558     global zigbeeUnregisteredAddressesMutex
559     global sendSoceket
560
561     print "process send address"
562     
563
564     # construct success message
565     message = "type: send_address_response\n"
566     message += "packet_id: " + parsedData['packet_id'] + "\n"
567     message += "response: success\n"
568
569     # tell client that we got their request
570     sendSoceket.sendto(message,addr)
571     print "responding", message
572     
573     # construct 
574     zigbeeLongShortAddrMutex.acquire()
575     doesHaveKey = zigbeeLongShortAddr.has_key(parsedData['device_address_long'])
576     zigbeeLongShortAddrMutex.release()
577
578     if(doesHaveKey):
579         # long address is already registered with the system so no need to do anything
580         return
581
582     # long address not registered so add it for short address lookup
583     zigbeeUnregisteredAddressesMutex.acquire()
584     zigbeeUnregisteredAddresses.append(parsedData['device_address_long'])
585     zigbeeUnregisteredAddressesMutex.release()
586
587
588
589 #made by changwoo
590 def processUdpEnrollmentResponse(parsedData, addr):
591
592     global zigbeeLongShortAddr
593     global zigbeeLongShortAddrMutex
594     global zigeeBindRequestMutex
595     global zigeeBindRequest
596     global zigbeeConnectionMutex
597     global zigbeeConnection
598     shortAddr = None
599
600     # get the short address for this device long address if possible
601     zigbeeLongShortAddrMutex.acquire()
602     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
603         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
604     zigbeeLongShortAddrMutex.release()
605
606
607     # if there is a short address than we can send the message
608     # if there is not one then we cannot since we need both the short and
609     # the long address
610     if(shortAddr != None):
611
612         # get a request number
613         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
614         
615         # send back failure
616         if(seqNumber == -1):
617
618             # send an error message, could not get a sequence number to use at this time
619             sendUdpSuccessFail(addr, 'zcl_enrollment_response', parsedData['packet_id'], False, 'out_of_space')
620             return
621
622         # get the info for sending
623         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
624         destShortAddr = hexStringToZigbeeHexString(shortAddr)
625         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
626         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
627         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
628
629         # create the payload data
630         payloadData = ""
631         payloadData += '\x01'
632         payloadData += chr(seqNumber)
633         payloadData += '\x00'
634         payloadData += '\x00\x00'
635
636         # create and send binding command
637         zigbeeConnectionMutex.acquire()
638         zigbeeConnection.send('tx_explicit',
639                             frame_id='\x40',
640                             # frame_id=chr(seqNumber),
641                             dest_addr_long=destLongAddr,
642                             dest_addr=destShortAddr,
643                             src_endpoint='\x01',
644                             dest_endpoint=dstEndpoint,
645                             cluster=clusterId,  
646                             profile=profileId,
647                             data=payloadData
648                             )
649         print '> EnrollmentResponse is sent'
650         zigbeeConnectionMutex.release()
651
652
653     else:
654         # send a fail response
655         sendUdpSuccessFail(addr, 'zcl_enrollment_response', parsedData['packet_id'], False, 'short_address_unknown')
656         pass
657
658
659
660
661 #made by changwoo
662 def processUdpZclWriteAttributesMessage(parsedData, addr):
663
664     global zigbeeLongShortAddr
665     global zigbeeLongShortAddrMutex
666     global zigeeBindRequestMutex
667     global zigeeBindRequest
668     global zigbeeConnectionMutex
669     global zigbeeConnection
670     shortAddr = None
671
672     # get the short address for this device long address if possible
673     zigbeeLongShortAddrMutex.acquire()
674     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
675         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
676     zigbeeLongShortAddrMutex.release()
677
678     # if there is a short address than we can send the message
679     # if there is not one then we cannot since we need both the short and
680     # the long address
681     if(shortAddr != None):
682         # get a request number
683         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
684         
685         # send back failure
686         if(seqNumber == -1):
687
688             # send an error message, could not get a sequence number to use at this time
689             sendUdpSuccessFail(addr, 'zcl_write_attributes', parsedData['packet_id'], False, 'out_of_space')
690             return
691
692         # get the info for sending
693         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
694         destShortAddr = hexStringToZigbeeHexString(shortAddr)
695         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
696         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
697         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
698
699         # create the payload data
700         payloadData = ""
701         payloadData += '\x00'
702         payloadData += chr(seqNumber)
703         payloadData += '\x02'
704         payloadData += '\x10\x00'
705         payloadData += '\xF0'
706 #        payloadData += '\xDA\x9A\xD9\x40\x00\xA2\x13\x00'
707         payloadData += hexStringToZigbeeHexString(changeEndian(ZIGBEE_DEVICE_ADDRESS))
708
709         zigbeeConnectionMutex.acquire()
710         zigbeeConnection.send('tx_explicit',
711                             frame_id='\x08',
712                             # frame_id=chr(seqNumber),
713                             dest_addr_long=destLongAddr,
714                             dest_addr=destShortAddr,
715                             src_endpoint='\x01',
716                             dest_endpoint=dstEndpoint,
717                             cluster=clusterId,
718                             profile=profileId,
719                             data=payloadData
720                             )
721
722         print ''
723         print '> WriteAttributesReq is sent : '+str(shortAddr)
724         zigbeeConnectionMutex.release()
725
726
727     else:
728         # send a fail response
729         sendUdpSuccessFail(addr, 'zcl_write_attributes', parsedData['packet_id'], False, 'short_address_unknown')
730         pass
731
732 #made by changwoo
733 def processUdpZclChangeSwitchReqMessage(parsedData, addr):
734
735     global zigbeeLongShortAddr
736     global zigbeeLongShortAddrMutex
737     global zigeeBindRequestMutex
738     global zigeeBindRequest
739     global zigbeeConnectionMutex
740     global zigbeeConnection
741     shortAddr = None
742
743     # get the short address for this device long address if possible
744     zigbeeLongShortAddrMutex.acquire()
745     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
746         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
747     zigbeeLongShortAddrMutex.release()
748
749
750     # if there is a short address than we can send the message
751     # if there is not one then we cannot since we need both the short and
752     # the long address
753     if(shortAddr != None):
754
755         # get a request number
756         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
757
758         # send back failure
759         if(seqNumber == -1):
760
761             # send an error message, could not get a sequence number to use at this time
762             sendUdpSuccessFail(addr, 'change_switch_request', parsedData['packet_id'], False, 'out_of_space')
763             return
764
765         # get the info for sending
766         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
767         destShortAddr = hexStringToZigbeeHexString(shortAddr)
768         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
769         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
770         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
771         value = hexStringToZigbeeHexString(parsedData['value'])
772
773         # create and send binding command
774         zigbeeConnectionMutex.acquire()
775
776         zigbeeConnection.send('tx_explicit',
777                             frame_id='\x40',
778                             # frame_id=chr(seqNumber),
779                             dest_addr_long=destLongAddr,
780                             dest_addr=destShortAddr,
781                             src_endpoint='\x01',
782                             dest_endpoint=dstEndpoint,
783                             cluster=clusterId,  
784                             profile=profileId,
785                             data='\x01'+chr(seqNumber)+value
786                             )
787         time.sleep(1)
788         if parsedData['value']==1:
789                 print '> The outlet sensor turned on'
790         else :
791                 print '> The outlet sensor turned off'
792
793         zigbeeConnectionMutex.release()
794
795
796     else:
797         # send a fail response
798         sendUdpSuccessFail(addr, 'zcl_read_attributes', parsedData['packet_id'], False, 'short_address_unknown')
799         pass
800
801
802 #made by Jiawei
803 def processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr):
804
805     global zigbeeLongShortAddr
806     global zigbeeLongShortAddrMutex
807     global zigeeBindRequestMutex
808     global zigeeBindRequest
809     global zigbeeConnectionMutex
810     global zigbeeConnection
811     shortAddr = None
812
813     # get the short address for this device long address if possible
814     zigbeeLongShortAddrMutex.acquire()
815     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
816         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
817     zigbeeLongShortAddrMutex.release()
818
819
820     # if there is a short address than we can send the message
821     # if there is not one then we cannot since we need both the short and
822     # the long address
823     if(shortAddr != None):
824
825         # get a request number
826         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
827
828         # send back failure
829         if(seqNumber == -1):
830
831             # send an error message, could not get a sequence number to use at this time
832             sendUdpSuccessFail(addr, 'lock_or_unlock_door_request', parsedData['packet_id'], False, 'out_of_space')
833             return
834
835         # get the info for sending
836         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
837         destShortAddr = hexStringToZigbeeHexString(shortAddr)
838         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
839         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
840         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
841         value = hexStringToZigbeeHexString(parsedData['value'])
842
843         # create and send binding command
844         zigbeeConnectionMutex.acquire()
845
846         zigbeeConnection.send('tx_explicit',
847                             frame_id='\x40',
848                             dest_addr_long=destLongAddr,
849                             dest_addr=destShortAddr,
850                             src_endpoint='\x01',
851                             dest_endpoint=dstEndpoint,
852                             cluster=clusterId,  
853                             profile=profileId,
854                             data='\x01'+chr(seqNumber)+value
855                             )
856         time.sleep(1)
857         if value == '\x01':
858             print '> The door lock is unlocked'
859         elif value == '\x00':
860             print '> The door lock is locked'
861         else:
862             print '> Unknown door lock value: ' + str(value)
863
864         zigbeeConnectionMutex.release()
865
866
867     else:
868         # send a fail response
869         sendUdpSuccessFail(addr, 'lock_or_unlock_door_request', parsedData['packet_id'], False, 'short_address_unknown')
870
871
872 #made by Jiawei
873 def processUdpZclReadDoorStatusReqMessage(parsedData, addr):
874
875     global zigbeeLongShortAddr
876     global zigbeeLongShortAddrMutex
877     global zigeeBindRequestMutex
878     global zigeeBindRequest
879     global zigbeeConnectionMutex
880     global zigbeeConnection
881     shortAddr = None
882
883     # get the short address for this device long address if possible
884     zigbeeLongShortAddrMutex.acquire()
885     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
886         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
887     zigbeeLongShortAddrMutex.release()
888
889
890     # if there is a short address than we can send the message
891     # if there is not one then we cannot since we need both the short and
892     # the long address
893     if(shortAddr != None):
894
895         # get a request number
896         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
897
898         # send back failure
899         if(seqNumber == -1):
900
901             # send an error message, could not get a sequence number to use at this time
902             sendUdpSuccessFail(addr, 'read_door_status_request', parsedData['packet_id'], False, 'out_of_space')
903             return
904
905         # get the info for sending
906         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
907         destShortAddr = hexStringToZigbeeHexString(shortAddr)
908         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
909         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
910         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
911         # framecontrol = hexStringToZigbeeHexString(parsedData['framecontrol'])
912         # commandframe = hexStringToZigbeeHexString(parsedData['commandframe'])
913         # attribute_id = hexStringToZigbeeHexString(parsedData['attribute_id'])
914
915         # create and send binding command
916         zigbeeConnectionMutex.acquire()
917
918         zigbeeConnection.send('tx_explicit',
919                             frame_id='\x40',
920                             dest_addr_long=destLongAddr,
921                             dest_addr=destShortAddr,
922                             src_endpoint='\x01',
923                             dest_endpoint=dstEndpoint,
924                             cluster=clusterId,  
925                             profile=profileId,
926                             data='\x10' + chr(seqNumber) + '\x00' + '\x00\x00'
927                             )
928         time.sleep(1)
929
930         zigbeeConnectionMutex.release()
931         print "send read door status"
932
933     else:
934         # send a fail response
935         sendUdpSuccessFail(addr, 'read_door_status_request', parsedData['packet_id'], False, 'short_address_unknown')
936
937
938 # made by changwoo
939 def processUdpBroadcastingRouteRecordReqMessage(parsedData, addr):
940
941     global zigbeeLongShortAddr
942     global zigbeeLongShortAddrMutex
943     global zigeeBindRequestMutex
944     global zigeeBindRequest
945     global zigbeeConnectionMutex
946     global zigbeeConnection
947     shortAddr = None
948
949     # get the short address for this device long address if possible
950     zigbeeLongShortAddrMutex.acquire()
951     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
952         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
953     zigbeeLongShortAddrMutex.release()
954
955
956     # if there is a short address than we can send the message
957     # if there is not one then we cannot since we need both the short and
958     # the long address
959     if(shortAddr != None):
960
961         # get a request number
962         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
963
964         # send back failure
965         if(seqNumber == -1):
966
967             # send an error message, could not get a sequence number to use at this time
968             sendUdpSuccessFail(addr, 'broadcast_route_record_request', parsedData['packet_id'], False, 'out_of_space')
969             return
970
971         # get the info for sending
972         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
973         destShortAddr = hexStringToZigbeeHexString(shortAddr)
974         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
975
976         # create and send binding command
977         zigbeeConnectionMutex.acquire()
978
979         zigbeeConnection.send('tx_explicit',
980                             frame_id='\x01',
981                             # frame_id=chr(seqNumber),
982                             dest_addr_long='\x00\x00\x00\x00\x00\x00\xff\xff',
983                             dest_addr='\xff\xfe',
984                             src_endpoint='\x00',
985                             dest_endpoint=dstEndpoint,
986                             cluster='\x00\x32',  
987                             profile='\x00\x00',
988                             data='\x12'+'\x01'
989                             )
990         time.sleep(1)
991         print '> BroadcastingRouteRecordReq is sent'
992
993         zigbeeConnectionMutex.release()
994
995
996     else:
997         # send a fail response
998         sendUdpSuccessFail(addr, 'zcl_read_attributes', parsedData['packet_id'], False, 'short_address_unknown')
999         pass
1000
1001
1002 #made by changwoo
1003 def processUdpManagementPermitJoiningReqMessage(parsedData, addr):
1004
1005     global zigbeeLongShortAddr
1006     global zigbeeLongShortAddrMutex
1007     global zigeeBindRequestMutex
1008     global zigeeBindRequest
1009     global zigbeeConnectionMutex
1010     global zigbeeConnection
1011     global matchDescriptorReqSingleton
1012     shortAddr = None
1013
1014     # get the short address for this device long address if possible
1015     zigbeeLongShortAddrMutex.acquire()
1016     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
1017         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
1018     zigbeeLongShortAddrMutex.release()
1019
1020
1021     # if there is a short address than we can send the message
1022     # if there is not one then we cannot since we need both the short and
1023     # the long address
1024     if(shortAddr != None):
1025
1026         # get a request number
1027         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
1028         
1029         # send back failure
1030         if(seqNumber == -1):
1031
1032             # send an error message, could not get a sequence number to use at this time
1033             sendUdpSuccessFail(addr, 'management_permit_joining_request', parsedData['packet_id'], False, 'out_of_space')
1034             return
1035
1036         # get the info for sending
1037         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
1038         destShortAddr = hexStringToZigbeeHexString(shortAddr)
1039         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
1040
1041         # create the payload data
1042         payloadData = ""
1043         payloadData += chr(seqNumber)
1044         payloadData += '\x5a'
1045         payloadData += '\x00'
1046
1047         # create and send binding command
1048         zigbeeConnectionMutex.acquire()
1049         zigbeeConnection.send('tx_explicit',
1050                             frame_id='\x01',
1051                             # frame_id=chr(seqNumber),
1052                             dest_addr_long=destLongAddr,
1053                             dest_addr=destShortAddr,
1054                             src_endpoint='\x00',
1055                             dest_endpoint='\x00',
1056                             cluster=clusterId,  
1057                             profile='\x00\x00',
1058                             data=payloadData
1059                             )
1060         print '> ManagementPermitJoiningReq is sent'
1061
1062         #stop answering 0x6
1063         matchDescriptorReqSingleton= False
1064         zigbeeConnectionMutex.release()
1065
1066
1067     else:
1068         # send a fail response
1069         sendUdpSuccessFail(addr, 'management_permit_joining_request', parsedData['packet_id'], False, 'short_address_unknown')
1070         pass
1071
1072
1073 def processUdpZclReadAttributesMessage(parsedData, addr):
1074     ''' Method handle a ZCL read attribute command
1075
1076         parsedData -- Pre-parsed Data that was in the UDP packet.
1077         addr -- Address (IP and Port) of the UDP packet origin.
1078     '''
1079
1080     global zigbeeLongShortAddr
1081     global zigbeeLongShortAddrMutex
1082     global zigeeBindRequestMutex
1083     global zigeeBindRequest
1084     global zigbeeConnectionMutex
1085     global zigbeeConnection
1086
1087
1088
1089     if(zigbeeAddressAuthorityDict.has_key(addr)):
1090         l = zigbeeAddressAuthorityDict[addr]
1091         if(parsedData['device_address_long'] not in l):
1092             return
1093     else:
1094         return
1095
1096
1097     shortAddr = None
1098
1099     # get the short address for this device long address if possible
1100     zigbeeLongShortAddrMutex.acquire()
1101     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
1102         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
1103     zigbeeLongShortAddrMutex.release()
1104
1105
1106     # if there is a short address than we can send the message
1107     # if there is not one then we cannot since we need both the short and
1108     # the long address
1109     if(shortAddr != None):
1110
1111         # get a request number
1112         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
1113         
1114         # send back failure
1115         if(seqNumber == -1):
1116
1117             # send an error message, could not get a sequence number to use at this time
1118             sendUdpSuccessFail(addr, 'zcl_read_attributes', parsedData['packet_id'], False, 'out_of_space')
1119             return
1120
1121         # get the info for sending
1122         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
1123         destShortAddr = hexStringToZigbeeHexString(shortAddr)
1124         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
1125         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
1126         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
1127
1128         # get all the attributes
1129         attributeIds = parsedData['attribute_ids'].split(',')
1130
1131         # create the payload data
1132         payloadData = ""
1133         payloadData += '\x00'
1134         payloadData += chr(seqNumber)
1135         payloadData += '\x00'
1136
1137         # make all the attributes payloads
1138         for attr in attributeIds:
1139             attr = attr.strip()
1140             attr = changeEndian(attr)
1141             payloadData += hexStringToZigbeeHexString(attr)
1142
1143         # create and send binding command
1144         zigbeeConnectionMutex.acquire()
1145         zigbeeConnection.send('tx_explicit',
1146                             frame_id='\x01',
1147                             # frame_id=chr(seqNumber),
1148                             dest_addr_long=destLongAddr,
1149                             dest_addr=destShortAddr,
1150                             src_endpoint='\x00',
1151                             dest_endpoint=dstEndpoint,
1152                             cluster=clusterId,  
1153                             profile=profileId,
1154                             data=payloadData
1155                             )
1156         zigbeeConnectionMutex.release()
1157
1158
1159     else:
1160         # send a fail response
1161         sendUdpSuccessFail(addr, 'zcl_read_attributes', parsedData['packet_id'], False, 'short_address_unknown')
1162         pass
1163
1164 def processUdpZclConfigureReportingMessage(parsedData, addr):
1165     ''' Method handle a zcl configure reporting message
1166
1167         parsedData -- Pre-parsed Data that was in the UDP packet.
1168         addr -- Address (IP and Port) of the UDP packet origin.
1169     '''
1170
1171     global zigbeeLongShortAddr
1172     global zigbeeLongShortAddrMutex
1173     global zigeeBindRequestMutex
1174     global zigeeBindRequest
1175     global zigbeeConnectionMutex
1176     global zigbeeConnection
1177
1178     if(zigbeeAddressAuthorityDict.has_key(addr)):
1179         l = zigbeeAddressAuthorityDict[addr]
1180         if(parsedData['device_address_long'] not in l):
1181             return
1182     else:
1183         return
1184
1185
1186     shortAddr = None
1187
1188     # get the short address for this device long address if possible
1189     zigbeeLongShortAddrMutex.acquire()
1190     if(zigbeeLongShortAddr.has_key(parsedData['device_address_long'])):
1191         shortAddr = zigbeeLongShortAddr[parsedData['device_address_long']]
1192     zigbeeLongShortAddrMutex.release()
1193
1194     # if there is a short address than we can send the message
1195     # if there is not one then we cannot since we need both the short and
1196     # the long address
1197     if(shortAddr != None):
1198
1199         # get a request number
1200         seqNumber = createSequenceNumberForClient(addr, parsedData['packet_id'])
1201         
1202         # send back failure
1203         if(seqNumber == -1):
1204             sendUdpSuccessFail(addr, 'zcl_configure_reporting', parsedData['packet_id'], False, 'out_of_space')
1205             return
1206
1207         destLongAddr = hexStringToZigbeeHexString(parsedData['device_address_long'])
1208         destShortAddr = hexStringToZigbeeHexString(shortAddr)
1209         profileId = hexStringToZigbeeHexString(parsedData['profile_id'])
1210         clusterId = hexStringToZigbeeHexString(parsedData['cluster_id'])
1211         dstEndpoint = hexStringToZigbeeHexString(parsedData['device_endpoint'])
1212
1213         # create the payload data
1214         payloadData = ""
1215         payloadData += '\x00'
1216         payloadData += chr(seqNumber)
1217         payloadData += '\x06'
1218         payloadData += '\x00'
1219         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['attribute_id']))
1220         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['data_type']))
1221         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['min_reporting_interval']))
1222         payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['max_reporting_interval']))
1223
1224         if(parsedData.has_key('reportable_change')):
1225             payloadData += hexStringToZigbeeHexString(changeEndian(parsedData['reportable_change']))
1226
1227
1228         # create and send binding command
1229         zigbeeConnectionMutex.acquire()
1230         zigbeeConnection.send('tx_explicit',
1231                             frame_id='\x01',
1232                             # frame_id=chr(seqNumber),
1233                             dest_addr_long=destLongAddr,
1234                             dest_addr=destShortAddr,
1235                             src_endpoint='\x00',
1236                             dest_endpoint=dstEndpoint,
1237                             cluster=clusterId,  
1238                             profile=profileId,
1239                             data=payloadData
1240                             )
1241         zigbeeConnectionMutex.release()
1242
1243
1244     else:
1245         sendUdpSuccessFail(addr, 'zcl_configure_reporting', parsedData['packet_id'], False, 'short_address_unknown')
1246         pass
1247
1248 def processUdpPolicySet(parsedData, addr):
1249     ''' Method handle a policy set message
1250
1251         parsedData -- Pre-parsed Data that was in the UDP packet.
1252         addr -- Address (IP and Port) of the UDP packet origin.
1253     '''
1254     print "=================================================================="
1255     print "Policy set: ", parsedData
1256     print 'addr : ', addr
1257
1258
1259     # do nothing if wrong source
1260     #if addr == SYSTEM_MASTER_ADDRESS or addr == SYSTEM_MASTER_ADDRESS2 or addr == SYSTEM_MASTER_ADDRESS3 :
1261     if addr == SYSTEM_MASTER_ADDRESS :
1262         key = (parsedData['ip_address'], int(parsedData['port']))
1263         if (zigbeeAddressAuthorityDict.has_key(key)):
1264             zigbeeAddressAuthorityDict[key].append(parsedData['device_address_long'])
1265         else:
1266             zigbeeAddressAuthorityDict[key] = [parsedData['device_address_long']]
1267
1268
1269 def processUdpPolicyClear(parsedData, addr):
1270     ''' Method handle a policy set message
1271
1272         parsedData -- Pre-parsed Data that was in the UDP packet.
1273         addr -- Address (IP and Port) of the UDP packet origin.
1274     '''
1275     print "=================================================================="
1276     print "Clear policy: ", parsedData
1277     
1278     # do nothing if wrong source
1279     #if addr == SYSTEM_MASTER_ADDRESS or addr == SYSTEM_MASTER_ADDRESS2 or addr == SYSTEM_MASTER_ADDRESS3:
1280     if addr == SYSTEM_MASTER_ADDRESS :
1281         zigbeeAddressAuthorityDict.clear()
1282
1283
1284 # -------------
1285 # Zigbee 
1286 # -------------
1287
1288 def processZigbeeATCommandMessage(parsedData):
1289     ''' Method to process an AT zigbee message
1290
1291         parsedData -- Pre-parsed (into a dict) data from message.
1292     '''
1293     global ZIGBEE_DEVICE_ADDRESS
1294     global didGetLocalRadioHighAddress
1295     global didGetLocalRadioLowAddress
1296
1297     # command response for the high bytes of the local device long address
1298     if(parsedData['command'] == 'SH'):
1299         # convert the parameter to a string value (human readable)
1300         value = ""
1301         for e in parsedData['parameter']:
1302             value += "{0:02x}".format(ord(e))
1303
1304         # set the correct portion of the address
1305         ZIGBEE_DEVICE_ADDRESS = value + ZIGBEE_DEVICE_ADDRESS[8:]
1306         
1307         #signal that we got this part of the address
1308         didGetLocalRadioHighAddress = True
1309
1310     # command response for the low bytes of the local device long address
1311     elif(parsedData['command'] == 'SL'):
1312         # convert the parameter to a string value (human readable)
1313         value = ""
1314         for e in parsedData['parameter']:
1315             value += "{0:02x}".format(ord(e))
1316
1317         # set the correct portion of the address
1318         ZIGBEE_DEVICE_ADDRESS = ZIGBEE_DEVICE_ADDRESS[0:8] + value
1319
1320         #signal that we got this part of the address
1321         didGetLocalRadioLowAddress = True
1322
1323 def processZigbeeRxExplicitCommandMessage(parsedData):
1324     ''' Method to process a rx-explicit zigbee message
1325
1326         parsedData -- Pre-parsed (into a dict) data from message.
1327     '''
1328     global zigeeBindRequestMutex
1329     global zigeeBindRequest
1330     global zigbeeConnectionMutex
1331     global zigbeeConnection
1332     global ManagementPermitJoiningReqSuccess
1333
1334     # get the long and short addresses from the message payload since we can 
1335     # use these to update the short addresses since this short address is fresh
1336     longAddr = zigbeeHexStringToHexString(parsedData['source_addr_long'])
1337     shortAddr = zigbeeHexStringToHexString(parsedData['source_addr'])
1338
1339     # check if this short address is for a device that has yet to be 
1340     # registered
1341     zigbeeUnregisteredAddressesMutex.acquire()
1342     if(longAddr in zigbeeUnregisteredAddresses):
1343         zigbeeUnregisteredAddresses.remove(longAddr)
1344     zigbeeUnregisteredAddressesMutex.release()
1345
1346     # update/ or insert the short address
1347     zigbeeLongShortAddrMutex.acquire()
1348     zigbeeLongShortAddr[longAddr] = shortAddr
1349     zigbeeLongShortAddrMutex.release()
1350
1351     global matchDescriptorReqSingleton
1352     global deviceAnnouncementSingleton
1353     global seqNumberForNotification
1354
1355     #made by Jiawei
1356     #doorlock response
1357     if (parsedData['cluster'] == '\x01\x01' and parsedData['profile'] == '\x01\x04'):
1358         zclSeqNumber = parsedData['rf_data'][1]
1359         tup = None
1360         zigbeeSeqNumberToClientMutex.acquire()
1361         if(zigbeeSeqNumberToClient.has_key(ord(zclSeqNumber))):
1362             tup = zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1363             del zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1364         zigbeeSeqNumberToClientMutex.release()
1365
1366         rfdata = parsedData['rf_data']
1367         framecontrol = rfdata[0]
1368         command = rfdata[2]
1369
1370         if tup != None:
1371             packetId = tup[2]
1372         
1373         if framecontrol == '\x19':
1374             if(command == '\x00'):
1375                 print ''
1376                 print "( 0x0101 ) Door Lock: Lock Door Response"
1377                 print time.strftime("%H:%M:%S", time.localtime())
1378                 value = rfdata[3]
1379                 if(value == '\x00'):
1380                     print "Door locked successfully"
1381                 else:
1382                     print "An error occurred in door locking"
1383             elif(command == '\x01'):
1384                 print ''
1385                 print "( 0x0101 ) Door Lock: Unlock Door Response"
1386                 print time.strftime("%H:%M:%S", time.localtime())
1387                 value = rfdata[3]
1388                 if(value == '\x00'):
1389                     print "Door unlocked successfully"
1390                 else:
1391                     print "An error occurred in door unlocking"
1392             return
1393         elif framecontrol == '\x18':
1394             if(command == '\x01'):
1395                 attributeId = (ord(rfdata[3]) * 256) + ord(rfdata[4])
1396                 if attributeId == 0x0000:
1397                     value = rfdata[7]
1398                     print "Door status: "
1399                     if value == '\x00':
1400                         print "Not fully locked"
1401                     elif value == '\x01':
1402                         print "Locked"
1403                     elif value == '\x02':
1404                         print "Unlocked"
1405                     else:
1406                         print "Unknown value: " + zigbeeHexStringToHexString(value)
1407                            
1408                     message = "type : zcl_read_attributes_response \n"
1409                     message += "packet_id: " + packetId + "\n"
1410                     message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1411                     message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1412                     message += "attributes: "
1413
1414                     attrIdStr = "%0.4x" % attributeId
1415                     attrIdStr = changeEndian(attrIdStr)
1416                     message += attrIdStr
1417                     message += ", "
1418
1419                     zclPayload = parsedData['rf_data'][3:]
1420                     zclPayload = zclPayload[3:]
1421                     attributeType = zclPayload[0]
1422                     message += "%0.2x" % ord(attributeType)
1423                     message += ", "
1424
1425                     message += "success"
1426                     message += ", "
1427
1428                     message += "%0.2x" % ord(value)
1429                     message += ";"
1430
1431                     message += ";"
1432                     
1433                     message = message[0:len(message) - 1]
1434                     message += "\n"
1435
1436                     # no one to send the response to so just move on
1437                     if(tup == None):
1438                         # cant really do anything here
1439                         return
1440                     sendSoceket.sendto(message,tup[0])
1441             elif command == '\x07':
1442                 status = rfdata[3]
1443                 print ''
1444                 print "( 0x0101 ) Door Lock: Configure reporting response"
1445                 print 'rfdata : ' + zigbeeHexStringToHexString(rfdata)
1446                 if status == '\x00':
1447                     print "Configure report successfully"
1448                     message = "type : zcl_configure_reporting_response \n"
1449                     message += "packet_id: " + packetId + "\n"
1450                     message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1451                     message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1452                     message += "attributes: " 
1453                     message +=  "all_success \n";
1454
1455                     # no one to send the response to so just move on
1456                     if(tup == None):
1457                         # cant really do anything here
1458                         return
1459                     sendSoceket.sendto(message,tup[0])
1460                 else:     
1461                     print "Configure report unsuccessfully, status =", zigbeeHexStringToHexString(status)
1462             elif(command == '\x0A'):
1463                 print "New update"
1464                 attributeId = (ord(rfdata[3]) * 256) + ord(rfdata[4])
1465                 if attributeId == 0x0000:
1466                     value = rfdata[6]
1467                     if value == '\x00':
1468                         print "Not fully locked"
1469                     elif value == '\x01':
1470                         print "Locked"
1471                     elif value == '\x02':
1472                         print "Unlocked"
1473                     else:
1474                         print "Unknown value: " + zigbeeHexStringToHexString(value)
1475
1476                     message = "type : zcl_read_attributes_response \n"
1477                     message += "packet_id: " + ("%0.2x" % ord(zclSeqNumber)) + "\n"
1478                     message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1479                     message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1480                     message += "attributes: "
1481
1482                     attrIdStr = "%0.4x" % attributeId
1483                     attrIdStr = changeEndian(attrIdStr)
1484                     message += attrIdStr
1485                     message += ", "
1486
1487                     zclPayload = parsedData['rf_data'][3:]
1488                     zclPayload = zclPayload[3:]
1489                     attributeType = zclPayload[0]
1490                     message += "%0.2x" % ord(attributeType)
1491                     message += ", "
1492
1493                     message += "success"
1494                     message += ", "
1495
1496                     message += "%0.2x" % ord(value)
1497                     message += ";"
1498
1499                     message += ";"
1500                     
1501                     message = message[0:len(message) - 1]
1502                     message += "\n"
1503
1504                     # get callback clients to respond to
1505                     callbackIndex = (zigbeeHexStringToHexString(parsedData['source_addr_long']), zigbeeHexStringToHexString(parsedData['cluster']))
1506                     retAddr = None
1507                     zibeeHACallbackMutex.acquire()
1508                     if(zibeeHACallback.has_key(callbackIndex)):
1509                         retAddr = zibeeHACallback[callbackIndex]
1510                     zibeeHACallbackMutex.release()
1511
1512                     # no one to respond to so do nothing here
1513                     if(retAddr == None):
1514                         return
1515                     for ra in retAddr:
1516                         sendSoceket.sendto(message,ra)
1517             return
1518
1519     # if this is a ZDO message/response
1520     #print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1521     #print parsedData
1522     #print "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
1523     if(parsedData['profile'] == '\x00\x00'):
1524
1525         # made by changwoo
1526         # if this is a Match Descriptor Request so we need to answer.
1527         if(parsedData['cluster'] == '\x00\x06' and matchDescriptorReqSingleton):
1528             zigbeeConnectionMutex.acquire()
1529             zigbeeConnection.send('tx_explicit',
1530                             frame_id='\x08',
1531                             # frame_id=chr(seqNumber),
1532                             dest_addr_long=parsedData['source_addr_long'],
1533                             dest_addr=parsedData['source_addr'],
1534                             src_endpoint='\x00',
1535                             dest_endpoint='\x00',
1536                             cluster='\x00\x06',
1537                             profile='\x00\x00',
1538                             data=parsedData['rf_data']
1539                             )
1540             time.sleep(1)
1541             zigbeeConnection.send('tx_explicit',
1542                             frame_id='\x40',
1543                             # frame_id=chr(seqNumber),
1544                             dest_addr_long=parsedData['source_addr_long'],
1545                             dest_addr=parsedData['source_addr'],
1546                             src_endpoint='\x00',
1547                             dest_endpoint='\x00',
1548                             cluster='\x80\x06',
1549                             profile='\x00\x00',
1550                             data=parsedData['rf_data'][0]+ '\x00\x00\x00' + '\x01\x01'
1551                             )
1552             time.sleep(1)
1553             print ''
1554             print '[ 0x0006 ] Match Descriptor Request - answered'
1555             print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1556             zigbeeConnectionMutex.release()
1557
1558
1559         # if this is a device announcement so we can get some useful data from it
1560         elif(parsedData['cluster'] == '\x00\x13' and deviceAnnouncementSingleton):
1561             #print parsedData
1562             # pick out the correct parts of the payload
1563             longAddr = zigbeeHexStringToHexString(parsedData['rf_data'][3:11])
1564             shortAddr = zigbeeHexStringToHexString(parsedData['rf_data'][1:3])
1565
1566             # change the endian of the address
1567             longAddr = changeEndian(longAddr)
1568             shortAddr = changeEndian(shortAddr)
1569
1570             # update the table with the new information
1571             zigbeeLongShortAddrMutex.acquire()
1572             zigbeeLongShortAddr[longAddr] = shortAddr
1573             zigbeeLongShortAddrMutex.release()
1574
1575             # check if this short address is for a device that has yet to be 
1576             # registered
1577             zigbeeUnregisteredAddressesMutex.acquire()
1578             if(longAddr in zigbeeUnregisteredAddresses):
1579                 zigbeeUnregisteredAddresses.remove(longAddr)
1580             zigbeeUnregisteredAddressesMutex.release()
1581
1582
1583             # made by changwoo
1584             zigbeeConnectionMutex.acquire()
1585             zigbeeConnection.send('tx_explicit',
1586                             frame_id='\x08',
1587                             # frame_id=chr(seqNumber),
1588                             dest_addr_long=parsedData['source_addr_long'],
1589                             dest_addr=parsedData['source_addr'],
1590                             src_endpoint='\x00',
1591                             dest_endpoint='\x00',
1592                             cluster='\x00\x13',
1593                             profile='\x00\x00',
1594                             data=parsedData['rf_data']
1595                             )
1596             print ''
1597             print '[ 0x0013 ] device announcement - answered'
1598             print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1599             deviceAnnouncementSingleton = False
1600             zigbeeConnectionMutex.release()
1601
1602
1603         # if this is a response to a zdo bind_req message
1604         elif(parsedData['cluster'] == '\x80\x21'):
1605
1606             # get the status and sequence number from the message
1607             seqNumber = parsedData['rf_data'][0]
1608             statusCode = parsedData['rf_data'][1]
1609             print ">response to a zdo bind_req message parsedData>"
1610
1611             # get the bind tuple information
1612             # for this specific bind request
1613             tup = None
1614             zigeeBindRequestMutex.acquire() 
1615             if(zigeeBindRequest.has_key(ord(seqNumber))):
1616                 tup = zigeeBindRequest[ord(seqNumber)]
1617             zigeeBindRequestMutex.release()
1618
1619             if(tup == None):
1620                 # cant really do anything in this case...
1621                 # don't have any information on who the data is for
1622                 return
1623
1624             # successful binding
1625             if(ord(statusCode) == 0):
1626
1627                 # add a callback for this specific device and cluster 
1628                 # to the HA callback dict 
1629                 zibeeHACallbackMutex.acquire();
1630                 if(zibeeHACallback.has_key((tup[0], tup[1]))):
1631                     if(tup[3] not in zibeeHACallback[(tup[0], tup[1])]):
1632                         zibeeHACallback[(tup[0], tup[1])].append(tup[3])
1633                 else:
1634                     zibeeHACallback[(tup[0], tup[1])] = [tup[3]]
1635                 zibeeHACallbackMutex.release()
1636
1637                 # send success message
1638                 sendUdpSuccessFail(tup[3], 'zdo_bind_request', tup[2], True)
1639
1640             # Not Supported
1641             elif (ord(statusCode) == 170):
1642                 sendUdpSuccessFail(tup[3], 'zdo_bind_request', tup[2], False, 'not_supported')
1643
1644             # Table Full
1645             elif (ord(statusCode) == 174):
1646                 sendUdpSuccessFail(tup[3], 'zdo_bind_request', tup[2], False, 'table_full')
1647
1648             # Other issue, dont have code for
1649             else:
1650                 sendUdpSuccessFail(tup[3], 'zdo_bind_request', tup[2], False, 'other')
1651
1652         # if this is a response to a short address query
1653         elif(parsedData['cluster'] == '\x80\x00'):
1654             print ">response to a short address query 0x8000"
1655             
1656             # get a status code
1657             statusCode = parsedData['rf_data'][0]
1658
1659             # does not matter if this is not a success, we can try again later
1660             if(statusCode != '\x00'):
1661                 # status code was not success so do not do anything
1662                 return
1663
1664             # get the short and long address information
1665             longAddr = changeEndian(zigbeeHexStringToHexString(parsedData['rf_data'][2:10]))
1666             shortAddr = changeEndian(zigbeeHexStringToHexString( parsedData['rf_data'][10:12]))
1667
1668             # remove device from list of unregistered devices if it is in it
1669             zigbeeUnregisteredAddressesMutex.acquire()
1670             if(longAddr in zigbeeUnregisteredAddresses):
1671                 zigbeeUnregisteredAddresses.remove(longAddr)
1672             zigbeeUnregisteredAddressesMutex.release()
1673
1674             # update/insert the short address
1675             zigbeeLongShortAddrMutex.acquire()
1676             zigbeeLongShortAddr[longAddr] = shortAddr
1677             zigbeeLongShortAddrMutex.release()
1678
1679         #made by changwoo
1680         elif(parsedData['cluster'] == '\x80\x06'):
1681             print ''
1682             print '[ 0x8006 ] get Match Descriptor Response'
1683             print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1684
1685         #made by changwoo
1686         elif(parsedData['cluster'] == '\x80\x36'):
1687             print ''
1688             print '[ 0x8036 ] get Management Permit Joining Response'
1689             print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1690
1691             ManagementPermitJoiningReqSuccess = True
1692
1693         #made by changwoo
1694         else :
1695             print ''
1696             print '[ '+zigbeeHexStringToHexString(parsedData['cluster'])+' ] ...'
1697             print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1698
1699
1700     # if this is a home automation zcl message/response
1701     elif (parsedData['profile'] == '\x01\x04'):
1702
1703         # get the zcl message header
1704         zclFrameControl = parsedData['rf_data'][0]
1705         zclSeqNumber = parsedData['rf_data'][1]
1706         zclCommand = parsedData['rf_data'][2]
1707         zclStatus = parsedData['rf_data'][3]
1708
1709         #made by changwoo
1710         if(zclCommand == '\x00'):
1711             print ''
1712             print '> ('+zigbeeHexStringToHexString(zclStatus)+') notification! : '+ zigbeeHexStringToHexString( parsedData['rf_data'] )
1713             
1714             # find who to send response 
1715             tup = None
1716             zigbeeSeqNumberToClientMutex.acquire()
1717
1718             if(longAddr in seqNumberForNotification):
1719                 key = longAddr
1720                 if(zigbeeSeqNumberToClient.has_key(seqNumberForNotification[key])):
1721                     tup = zigbeeSeqNumberToClient[seqNumberForNotification[key]]
1722                     #del zigbeeSeqNumberToClient[seqNumberForNotification] # don't delete.
1723             zigbeeSeqNumberToClientMutex.release()
1724
1725             # no one to send the response to so just move on
1726             if(tup == None):
1727                 # cant really do anything here
1728                 return
1729             # create the response message
1730             packetId = tup[2]
1731             message = "type : zcl_zone_status_change_notification\n"
1732             message += "packet_id: " + packetId + "\n"
1733             message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1734             message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1735             message += "status: " + zigbeeHexStringToHexString(zclStatus) + "\n"
1736             message += "attributes: success"
1737             message += "\n"
1738             # send the socket
1739             sendSoceket.sendto(message,tup[0])
1740             print(">port : ", tup[0][1])
1741
1742
1743
1744         # this is a zcl read attribute response
1745         elif(zclCommand == '\x01'):
1746
1747             # get the zcl payload
1748             zclPayload = parsedData['rf_data'][3:]
1749             attibuteResponseList = []
1750
1751             # get the data for each data
1752             while(len(zclPayload) > 0):
1753                 attributeId = zclPayload[0:2]
1754                 attributeStatus = zclPayload[2]
1755                 zclPayload = zclPayload[3:]
1756                 
1757                 if(ord(attributeStatus) != 0):
1758                     # if attribute is not supported then it has no data
1759                     # package the data and add it to the list
1760                     attibuteResponseList.append((attributeId,"not_supported"))
1761                 else:
1762
1763                     # get the data type and data length of the attributre
1764                     attributeType = zclPayload[0]
1765                     dataLength = zclDataTypeToBytes(zclPayload)
1766
1767                     # consume zcl payload data
1768                     if ((ord(attributeType) == 0x41) or (ord(attributeType) == 0x42)):
1769                         zclPayload = zclPayload[2:]
1770                     elif ((ord(attributeType) == 0x43) or (ord(attributeType) == 0x44)):
1771                         zclPayload = zclPayload[3:]
1772                     else:
1773                         zclPayload = zclPayload[1:]
1774
1775                     # package the data and add it to the list
1776                     newData = (attributeId,"success", attributeType ,zclPayload[0:dataLength])
1777                     attibuteResponseList.append(newData)
1778
1779                     # consume the data size of the payload
1780                     zclPayload = zclPayload[dataLength:]
1781
1782             # find who to send response to 
1783             tup = None
1784             zigbeeSeqNumberToClientMutex.acquire()
1785             if(zigbeeSeqNumberToClient.has_key(ord(zclSeqNumber))):
1786                 tup = zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1787                 del zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1788             zigbeeSeqNumberToClientMutex.release()
1789
1790             # no one to send the response to so just move on
1791             if(tup == None):
1792                 # cant really do anything here
1793                 return
1794             
1795             # create the response message
1796             packetId = tup[2]
1797             message = "type : zcl_read_attributes_response \n"
1798             message += "packet_id: " + packetId + "\n"
1799             message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1800             message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1801             message += "attributes: " 
1802
1803             # create the message for each attribute
1804             for t in attibuteResponseList:
1805                 attrId = ord(t[0][0]) + (256 * ord(t[0][1]))
1806                 if(t[1] == "success"):
1807                     attrIdStr = "%0.4x" % attrId
1808                     attrIdStr = changeEndian(attrIdStr)
1809
1810                     message += attrIdStr
1811                     message += ", "
1812                     message +=  "success"
1813                     message += ", "
1814                     message += "%0.2x" % ord(t[2])
1815                     message += ", "
1816
1817                     dat = ""
1818                     for c in (t[3]):
1819                         dat += "%0.2x" % ord(c)
1820                     dat = changeEndian(dat)
1821                     message += dat
1822                     message += ";"
1823                 else:
1824                     attrIdStr = "%0.4x" % attrId
1825                     attrIdStr = changeEndian(attrIdStr)
1826
1827                     message += attrIdStr
1828                     message += ", "
1829                     message +=  "not_supported"
1830                     message += ";"
1831
1832             message = message[0:len(message) - 1]
1833             message += "\n"
1834             # send the socket
1835             sendSoceket.sendto(message,tup[0])
1836
1837
1838
1839
1840         # made by changwoo
1841         # this is a zcl write attribute response
1842         elif(zclCommand == '\x04'):
1843
1844             # get the zcl payload
1845             zclPayload = parsedData['rf_data'][3]
1846             # the response is '70' which means already resister the mac address or 'success', then let JAVA knows it
1847             if(zclStatus == '\x70' or zclPayload == '\x00'):
1848
1849                 # find who to send response to 
1850                 tup = None
1851                 zigbeeSeqNumberToClientMutex.acquire()
1852                 if(zigbeeSeqNumberToClient.has_key(ord(zclSeqNumber))):
1853                     tup = zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1854                     seqNumberForNotification[longAddr] = ord(zclSeqNumber)
1855                     #del zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1856                 zigbeeSeqNumberToClientMutex.release()
1857                 # no one to send the response to so just move on
1858                 if(tup == None):
1859                     # cant really do anything here
1860                     return
1861             
1862                 # create the response message
1863                 packetId = tup[2]
1864                 message = "type : zcl_write_attributes_response\n"
1865                 message += "packet_id: " + packetId + "\n"
1866                 message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1867                 message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1868                 message += "attributes: success"
1869                 message += "\n"
1870                 # send the socket
1871                 sendSoceket.sendto(message,tup[0])
1872                 print ''
1873                 print '[ 0x0500 ] get Write Attribute Response success'
1874                 print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1875
1876             else:
1877                 print ''
1878                 print '[ 0x0500 ] get Write Attribute Response'
1879                 print '> rfdata : '+zigbeeHexStringToHexString(parsedData['rf_data'])
1880
1881
1882
1883         # this is a zcl configure attribute response
1884         elif(zclCommand == '\x07'):
1885
1886             # find who to send response to 
1887             tup = None
1888             zigbeeSeqNumberToClientMutex.acquire()
1889             if(zigbeeSeqNumberToClient.has_key(ord(zclSeqNumber))):
1890                 tup = zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1891                 del zigbeeSeqNumberToClient[ord(zclSeqNumber)]
1892             zigbeeSeqNumberToClientMutex.release()
1893
1894             # no one to send the response to so just move on
1895             if(tup == None):
1896                 # cant really do anything here
1897                 return
1898
1899             # get zcl payload
1900             zclPayload = parsedData['rf_data'][3:]
1901             
1902             # construct the message
1903             packetId = tup[2]
1904             message = "type : zcl_configure_reporting_response \n"
1905             message += "packet_id: " + packetId + "\n"
1906             message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1907             message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1908             message += "attributes: " 
1909
1910             if(len(zclPayload) == 1):
1911                 # if all the configurations are a success then only send back a success
1912                 # based on zigbee specs
1913                 message +=  "all_success \n";
1914                 sendSoceket.sendto(message,tup[0])
1915             
1916             else:
1917                 attibuteResponseList = []
1918                 
1919                 # get each attributes data
1920                 while(len(zclPayload) > 0):
1921                     attributeStatus = zclPayload[0]
1922                     attributeDirection = zclPayload[1]
1923                     attributeId = zclPayload[2:4]
1924                     zclPayload = zclPayload[4:]
1925
1926                     newData = (attributeStatus,attributeDirection, attributeId)
1927                     attibuteResponseList.append(newData)
1928
1929                 # package each attribute 
1930                 for t in attibuteResponseList:
1931                     attrId = ord(t[2][0]) + (256 * ord(t[2][1]))
1932                     attrIdStr = "%0.4x" % attrId
1933                     attrIdStr = changeEndian(attrIdStr)
1934
1935                     message += attrIdStr
1936                     message += ", "
1937                     if(ord(t[0]) == 0):
1938                         message +=  "success"
1939                     else:
1940                         message +=  "error"
1941
1942                     message += ", "
1943
1944                     if(ord(t[1]) == 0):
1945                         message +=  "reported"
1946                     else:
1947                         message +=  "received"
1948                     message += ";"
1949
1950                 message = message[0:len(message) - 1]
1951                 message += "\n"
1952                 sendSoceket.sendto(message,tup[0])
1953
1954         # this is a zcl report attribute message
1955         elif(zclCommand == '\x0a'):
1956             print "get Report attribute "
1957             # get teh zcl payload
1958             zclPayload = parsedData['rf_data'][3:]
1959             attibuteResponseList = []
1960  
1961             # extract the attribute data
1962             while(len(zclPayload) > 0):
1963                 attributeId = zclPayload[0:2]
1964                 zclPayload = zclPayload[2:]
1965                 attributeType = zclPayload[0]
1966                 dataLength = zclDataTypeToBytes(zclPayload)
1967
1968                 if ((ord(attributeType) == 0x41) or (ord(attributeType) == 0x42)):
1969                     zclPayload = zclPayload[2:]
1970                 elif ((ord(attributeType) == 0x43) or (ord(attributeType) == 0x44)):
1971                     zclPayload = zclPayload[3:]
1972                 else:
1973                     zclPayload = zclPayload[1:]
1974
1975                 newData = (attributeId, attributeType ,zclPayload[0:dataLength])
1976                 attibuteResponseList.append(newData)
1977                 zclPayload = zclPayload[dataLength:]
1978
1979
1980             # get callback clients to respond to
1981             callbackIndex = (zigbeeHexStringToHexString(parsedData['source_addr_long']), zigbeeHexStringToHexString(parsedData['cluster']))
1982             retAddr = None
1983             zibeeHACallbackMutex.acquire()
1984             if(zibeeHACallback.has_key(callbackIndex)):
1985                 retAddr = zibeeHACallback[callbackIndex]
1986             zibeeHACallbackMutex.release()
1987
1988             # no one to respond to so do nothing here
1989             if(retAddr == None):
1990                 return
1991
1992             # construct the message
1993             message = "type : zcl_report_attributes \n"
1994             message += "packet_id: " + ("%0.2x" % ord(zclSeqNumber)) + "\n"
1995             message += "cluster_id: " + zigbeeHexStringToHexString(parsedData['cluster']) + "\n"
1996             message += "profile_id: " + zigbeeHexStringToHexString(parsedData['profile']) + "\n"
1997             message += "attributes: " 
1998
1999             # package the attributes
2000             for t in attibuteResponseList:
2001                 attrId = ord(t[0][0]) + (256 * ord(t[0][1]))
2002                 attrIdStr = "%0.4x" % attrId
2003                 attrIdStr = changeEndian(attrIdStr)
2004
2005                 message += attrIdStr
2006                 message += ", "
2007                 message += "%0.2x" % ord(t[1])
2008                 message += ", "
2009
2010                 dat = ""
2011                 for c in (t[2]):
2012                     dat += "%0.2x" % ord(c)
2013                 dat = changeEndian(dat)
2014                 message += dat
2015                 message += ";"
2016
2017             message = message[0:len(message) - 1]
2018             message += "\n"
2019             print "Sending", message
2020             
2021             # send to all client that want this callback
2022             for ra in retAddr:
2023                 sendSoceket.sendto(message,ra)
2024
2025 # -----------------------------------------------------------------------------
2026 # Communication Callback/Parse Methods
2027 # -----------------------------------------------------------------------------
2028 def handleNewZigbeeMessage(parsedData):
2029     ''' Method to process a zigbee message from the local radio.
2030
2031         parsedData -- Pre-parsed (into a dict) data from message.
2032     '''
2033     #print "=================================================================="
2034     #print ''
2035     print "New Zigbee Message"
2036     #printMessageData(parsedData)
2037
2038     # dispatch to the correct zigbee handler
2039     if (parsedData['id'] == 'at_response'):
2040         print "parsedDataID : at_response"
2041         processZigbeeATCommandMessage(parsedData)
2042
2043     elif (parsedData['id'] == 'rx_explicit'):
2044         print "parsedDataID : rx_explicit"
2045         processZigbeeRxExplicitCommandMessage(parsedData)
2046
2047     else:
2048         print "Unknown API format"
2049
2050     #print "=================================================================="
2051
2052
2053
2054 def handleNewUdpPacket(data, addr):
2055     ''' Method to parse and handle an incoming UDP packet.
2056
2057         data -- Data that was in the UDP packet.
2058         addr -- Address (IP and Port) of the UDP packet origin.
2059     '''
2060     global ManagementPermitJoiningReqSuccess
2061
2062     #print "=================================================================="
2063     #print ''
2064     #print "Got New UDP packet..."
2065     #print data
2066
2067
2068     # data comes in as 'key: value\n key: value...' string and so needs to be
2069     # parsed into a dict
2070     parsedData = dict()
2071
2072     # 1 key, value pair per line
2073     for line in data.split('\n'):
2074
2075         # key and values are split based on a ':'
2076         fields = line.split(':')
2077
2078         # make sure properly formated otherwise just ignore it
2079         if len(fields) == 2:
2080
2081             # do strips to remove any white spacing that may have resulted
2082             # from improper packing on the sender side
2083             parsedData[fields[0].strip()] = fields[1].strip()
2084
2085
2086     # wrap in try statement just in case there is an improperly formated packet we
2087     # can deal with it
2088     try:
2089         # dispatch to the correct process method
2090         if(parsedData["type"] == "zdo_bind_request"):
2091             print "> processUdpZdoBindReqMessage call"
2092             processUdpZdoBindReqMessage(parsedData, addr)
2093         elif(parsedData["type"] == "zdo_unbind_request"):
2094             processUdpZdoUnBindReqMessage(parsedData, addr)
2095         elif(parsedData["type"] == "send_address"):
2096             print "> processUdpSendAddressMessage call"
2097             processUdpSendAddressMessage(parsedData, addr)
2098         elif(parsedData["type"] == "zcl_read_attributes"):
2099             processUdpZclReadAttributesMessage(parsedData, addr)
2100         elif(parsedData["type"] == "zcl_configure_reporting"):
2101             print "> zcl_configure_reporting call"
2102             processUdpZclConfigureReportingMessage(parsedData, addr)
2103         elif(parsedData["type"] == "policy_set"):
2104             processUdpPolicySet(parsedData, addr)
2105         elif(parsedData["type"] == "policy_clear"):
2106             processUdpPolicyClear(parsedData, addr)
2107         elif(parsedData["type"] == "management_permit_joining_request"): #made by changwoo
2108             processUdpManagementPermitJoiningReqMessage(parsedData, addr)
2109         elif(parsedData["type"] == "zcl_write_attributes" and ManagementPermitJoiningReqSuccess): #made by changwoo
2110             processUdpZclWriteAttributesMessage(parsedData, addr)
2111         elif(parsedData["type"] == "zcl_enrollment_response"): #made by changwoo
2112             processUdpEnrollmentResponse(parsedData, addr)
2113         elif(parsedData["type"] == "zdo_broadcast_route_record_request"): #made by changwoo
2114             processUdpBroadcastingRouteRecordReqMessage(parsedData, addr)
2115         elif(parsedData["type"] == "zcl_change_switch_request"): #made by changwoo
2116             processUdpZclChangeSwitchReqMessage(parsedData, addr)
2117         elif(parsedData["type"] == "zcl_lock_or_unlock_door_request"): #made by Jiawei
2118             processUdpZclLockOrUnlockDoorReqMessage(parsedData, addr)
2119         elif(parsedData["type"] == "zcl_read_door_status_request"): #made by Jiawei
2120             processUdpZclReadDoorStatusReqMessage(parsedData, addr)
2121         else:
2122             #print "unknown Packet: " + parsedData["type"]
2123             pass
2124     except:
2125         # if we ever get here then something went wrong and so just ignore this
2126         # packet and try again later
2127         print "I didn't expect this error:", sys.exc_info()[0]
2128         traceback.print_exc()
2129
2130     #print "=================================================================="
2131
2132
2133 # -----------------------------------------------------------------------------
2134 # Main Running Methods
2135 # -----------------------------------------------------------------------------
2136
2137 def main():
2138     '''Main function used for starting the application as the main driver'''
2139
2140     global ZIGBEE_SERIAL_PORT
2141     global ZIGBEE_SERIAL_BAUD
2142     global UDP_RECEIVE_PORT
2143     global zigbeeConnection
2144     global zigbeeMutex
2145     global doEndFlag
2146
2147     parseCommandLineArgs(sys.argv[1:])
2148
2149     # create serial object used for communication to the zigbee radio
2150     sc = serial.Serial(ZIGBEE_SERIAL_PORT, ZIGBEE_SERIAL_BAUD)
2151
2152     # create a zigbee object that handles all zigbee communication
2153     # we use this to do all communication to and from the radio
2154     # when data comes from the radio it will get a bit of unpacking
2155     # and then a call to the callback specified will be done with the
2156     # unpacked data
2157     zigbeeConnection = ZigBee(sc, callback=handleNewZigbeeMessage)
2158
2159     # get the long address of our local radio before we start doing anything
2160     getConnectedRadioLongAddress();
2161
2162     # setup incoming UDP socket and bind it to self and specified UDP port
2163     # sending socket does not need to be bound to anything
2164     #receiveSoceket.bind(('192.168.2.227', UDP_RECEIVE_PORT))
2165     receiveSoceket.bind(('192.168.1.192', UDP_RECEIVE_PORT))
2166
2167     # create the thread that does short address lookups
2168     addressUpdateWorkerThread = threading.Thread(target=addressUpdateWorkerMethod)
2169     addressUpdateWorkerThread.start()
2170
2171     try:
2172         # Main running loop
2173         while(True):
2174             print "=================================================================="
2175             print ''
2176             print "Waiting..."
2177             print "=================================================================="
2178
2179             # wait for an incoming UDP packet
2180             # this is a blocking call
2181             data, addr = receiveSoceket.recvfrom(4096)
2182
2183             # handle the UDP packet appropriately
2184             handleNewUdpPacket(data, addr)
2185
2186     except KeyboardInterrupt:
2187         # use the keyboard interupt to catch a ctrl-c and kill the application
2188         pass
2189
2190     except:
2191         # something went really wrong and so exit with error message
2192         traceback.print_exc()
2193
2194     # signal all threads to exit
2195     doEndFlag = True
2196
2197     # wait for threads to finish before closing of the resources
2198     addressUpdateWorkerThread.join()
2199
2200
2201     # make sure to close all the connections
2202     zigbeeConnection.halt()
2203     receiveSoceket.close()
2204     sendSoceket.close()
2205
2206 if __name__ == "__main__":
2207     # call main function since this is being run as the start
2208     main()