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