Completing Lifx driver that uses Particle cloud; Particle phone app provides a nice...
[iotcloud.git] / version2 / src / RPi / LifxLightBulb.cpp
1 #include <iostream>
2 #include <string>
3 #include <thread>
4
5 #include <pthread.h>
6
7 #include "LifxLightBulb.h"
8 #include "IoTSet.h"
9 #include "IoTDeviceAddress.h"
10 #include "application.h"
11
12 using namespace std;
13
14
15 // Default constructor
16 LifxLightBulb::LifxLightBulb() { 
17
18 }
19
20
21 // Constructor
22 LifxLightBulb::LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort) { 
23
24         memcpy(bulbMacAddress, macAddress, 8);
25         
26         // Initialize device address
27         // Port 56700 is the default port for Lifx
28         IoTDeviceAddress* devAddress = new IoTDeviceAddress(ipAddress, srcPort, 56700, false, false);
29         unordered_set<void*>* myset1 = new unordered_set<void*>();
30         myset1->insert(devAddress);
31         IoTSet<void*>* setDevAddress = new IoTSet<void*>(myset1);
32         lb_addresses = setDevAddress;
33 }
34
35
36 LifxLightBulb::~LifxLightBulb() {
37
38         // Clean up
39         if (communicationSocket != NULL) {
40
41                 delete communicationSocket;
42                 communicationSocket = NULL;             
43         }
44         for(void* dev : *lb_addresses) {
45                 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
46                 delete dv;
47                 dv = NULL;
48         }
49         if (lb_addresses != NULL) {
50
51                 delete lb_addresses;
52                 lb_addresses = NULL;            
53         }
54 }
55
56
57 // PUBLIC METHODS
58 // Initialize the lightbulb
59 void LifxLightBulb::init() {
60
61         if (didAlreadyInit)
62                 return;
63         // Set to true if not yet
64         didAlreadyInit = true;
65
66         unordered_set<void*>::const_iterator itr = lb_addresses->begin();
67         IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
68
69         // Create IoTUDP socket
70         communicationSocket = new IoTUDP(deviceAddress);
71
72         //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
73         //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
74         //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
75
76         // Launch the worker function in a separate thread.
77         //              NOTE: "this" pointer is passed into the detached thread because it does not belong
78         //                      to this object anymore so if it executes certain methods of "this" object, then it needs
79         //                      the correct references to stuff
80         thread th1 (&LifxLightBulb::workerFunction, this, this);
81         th1.detach();
82 }
83
84
85 void LifxLightBulb::turnOff() {
86
87         //lock_guard<mutex> guard(bulbStateMutex);
88         bulbStateMutex.lock();
89         bulbIsOn = false;
90         sendSetLightPowerPacket(0, 0);
91         stateDidChange = true;
92         bulbStateMutex.unlock();
93 }
94
95
96 void LifxLightBulb::turnOn() {
97
98         //lock_guard<mutex> guard(bulbStateMutex);
99         bulbStateMutex.lock();
100         bulbIsOn = true;
101         sendSetLightPowerPacket(65535, 0);
102         stateDidChange = true;
103         bulbStateMutex.unlock();
104 }
105
106
107 double LifxLightBulb::getHue() {
108         double tmp = 0;
109         settingBulbColorMutex.lock();
110         tmp = ((double)currentHue / 65535.0) * 360.0;
111         settingBulbColorMutex.unlock();
112
113         return tmp;
114 }
115
116
117 double LifxLightBulb::getSaturation() {
118         double tmp = 0;
119         settingBulbColorMutex.lock();
120         tmp = ((double)currentSaturation / 65535.0) * 360.0;
121         settingBulbColorMutex.unlock();
122
123         return tmp;
124 }
125
126
127 double LifxLightBulb::getBrightness() {
128         double tmp = 0;
129         settingBulbColorMutex.lock();
130         tmp = ((double)currentBrightness / 65535.0) * 360.0;
131         settingBulbColorMutex.unlock();
132
133         return tmp;
134 }
135
136
137 int LifxLightBulb::getTemperature() {
138
139         int tmp = 0;
140         settingBulbTemperatureMutex.lock();
141         tmp = currentTemperature;
142         settingBulbTemperatureMutex.unlock();
143
144         return tmp;
145 }
146
147
148 double LifxLightBulb::getHueRangeLowerBound() {
149         if (!didGetBulbVersion) {
150                 return -1;
151         }
152         return ((double)hueLowerBound / 65535.0) * 360.0;
153 }
154
155
156 double LifxLightBulb::getHueRangeUpperBound() {
157         if (!didGetBulbVersion) {
158                 return -1;
159         }
160         return ((double)hueUpperBound / 65535.0) * 360.0;
161 }
162
163
164 double LifxLightBulb::getSaturationRangeLowerBound() {
165         if (!didGetBulbVersion) {
166                 return -1;
167         }
168         return ((double)saturationLowerBound / 65535.0) * 100.0;
169 }
170
171
172 double LifxLightBulb::getSaturationRangeUpperBound() {
173         if (!didGetBulbVersion) {
174                 return -1;
175         }
176         return ((double)saturationUpperBound / 65535.0) * 100.0;
177 }
178
179
180 double LifxLightBulb::getBrightnessRangeLowerBound() {
181         if (!didGetBulbVersion) {
182                 return -1;
183         }
184         return ((double)brightnessLowerBound / 65535.0) * 100.0;
185 }
186
187
188 double LifxLightBulb::getBrightnessRangeUpperBound() {
189         if (!didGetBulbVersion) {
190                 return -1;
191         }
192         return ((double)brightnessUpperBound / 65535.0) * 100.0;
193 }
194
195
196 int LifxLightBulb::getTemperatureRangeLowerBound() {
197         if (!didGetBulbVersion) {
198                 return -1;
199         }
200         return temperatureLowerBound;
201 }
202
203
204 int LifxLightBulb::getTemperatureRangeUpperBound() {
205         if (!didGetBulbVersion) {
206                 return -1;
207         }
208         return temperatureUpperBound;
209 }
210
211
212 void LifxLightBulb::setTemperature(int _temperature) {
213
214         settingBulbTemperatureMutex.lock();
215
216         BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
217         sendSetLightColorPacket(newColor, 250);
218
219         currentTemperature = _temperature;
220         stateDidChange = true;
221
222         settingBulbTemperatureMutex.unlock();
223 }
224
225
226 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
227
228         settingBulbColorMutex.lock();
229
230         _hue /= 360.0;
231         _saturation /= 100.0;
232         _brightness /= 100.0;
233
234
235         int newHue = (int)(_hue * 65535.0);
236         int newSaturation = (int)(_saturation * 65535.0);
237         int newBrightness = (int)(_brightness * 65535.0);
238
239         BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
240         sendSetLightColorPacket(newColor, 250);
241
242         currentHue = newHue;
243         currentSaturation = newSaturation;
244         currentBrightness = newBrightness;
245         stateDidChange = true;
246
247         settingBulbColorMutex.unlock();
248 }
249
250
251 bool LifxLightBulb::getState() {
252
253         bool tmp = false;
254
255         bulbStateMutex.lock();
256         tmp = bulbIsOn;
257         bulbStateMutex.unlock();
258
259         return tmp;
260 }
261
262
263 // PRIVATE METHODS
264 // Communication helpers
265 void LifxLightBulb::receivedPacket(char* packetData) {
266
267         char headerBytes[36];
268         for (int i = 0; i < 36; i++) {
269                 headerBytes[i] = packetData[i];
270         }
271
272         LifxHeader recHeader;
273         recHeader.setFromBytes(headerBytes);
274
275         // load the payload bytes (strip away the header)
276         char* payloadBytes = new char[recHeader.getSize()];
277         for (int i = 36; i < recHeader.getSize(); i++) {
278                 payloadBytes[i - 36] = packetData[i];
279         }
280
281         int type = recHeader.getType();
282         //cout << "Received: " << type << endl;
283
284         DeviceStateService* dat = NULL;
285         switch (type) {
286
287                 case 3:
288                         dat = parseDeviceStateServiceMessage(payloadBytes);
289                         //cout << "Service: " << dat->getService();
290                         //cout << "Port   : " << dat->getPort();
291                         // Avoid memory leak - delete this object
292                         delete dat;     
293                         break;
294
295                 case 33:
296                         handleStateVersionMessageReceived(payloadBytes);
297                         break;
298
299                 case 35:
300                         parseDeviceStateInfoMessage(payloadBytes);
301                         break;
302
303
304                 case 107:
305                         handleLightStateMessageReceived(payloadBytes);
306                         break;
307
308                 default:
309                         break;
310                         //cout << "unknown packet Type" << endl;
311         }
312         // Avoid memory leaks
313         delete payloadBytes;
314 }
315
316
317 void LifxLightBulb::sendPacket(char* packetData, int len) {
318         //cout << "sendPacket: About to send" << endl;
319         lock_guard<mutex> guard(socketMutex);
320         sendSocketFlag = true;
321         communicationSocket->sendData(packetData, len);
322         sendSocketFlag = false;
323 }
324
325
326 // Worker function which runs the while loop for receiving data from the bulb.
327 // Is blocking.
328 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
329
330         // Need timeout on receives since we are not sure if a packet will be available
331         // for processing so don't block waiting
332         llb->communicationSocket->setTimeOut(50000);    // In milliseconds
333         llb->turnOff();
334
335         int64_t lastSentGetBulbVersionRequest = 0;      // time last request sent
336         char dat[1024];
337
338         while (true) {
339                 // Check if we got the bulb version yet
340                 // could have requested it but message could have gotten lost (UDP)
341                 if (!llb->didGetBulbVersion) {
342                         int64_t currentTime = (int64_t) time(NULL);
343                         if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
344                                 // Get the bulb version so we know what type of bulb this is.
345                                 //cout << "Sending version packet! " << endl;
346                                 llb->sendGetVersionPacket();
347                                 lastSentGetBulbVersionRequest = currentTime;
348                         }
349                 }
350
351                 // Communication resource is busy so try again later
352                 if (llb->sendSocketFlag) {
353                         continue;
354                 }
355
356                 llb->socketMutex.lock();
357                 int ret = llb->communicationSocket->receiveData(dat, 1024);
358                 // Never forget to release!
359                 llb->socketMutex.unlock();
360
361                 // A packed arrived
362                 if (ret != -1) {
363                         llb->receivedPacket(dat);
364                 }
365
366                 // If a state change occurred then request the bulb state to ensure that the
367                 // bulb did indeed change its state to the correct state
368                 if (llb->stateDidChange) {
369                         llb->sendGetLightStatePacket();
370                 }
371
372                 // Wait a bit as to not tie up system resources
373                 //this_thread::sleep_for (chrono::milliseconds(100));
374                 delay(100);
375                 //cout << endl << "Sleep and wake up!" << endl;
376         }
377 }
378
379
380 //  Sending
381 //  Device Messages
382 void LifxLightBulb::sendGetServicePacket() {
383         LifxHeader header;
384         header.setSize(36);
385         header.setTagged(true);
386         header.setMacAddress(bulbMacAddress);
387         header.setSource(0);    // randomly picked
388         header.setAck_required(false);
389         header.setRes_required(false);
390         header.setSequence(0);
391         header.setType(2);
392
393         char dataBytes[36];
394         header.getHeaderBytes(dataBytes);
395
396         sendPacket(dataBytes, 36);
397 }
398
399
400 void LifxLightBulb::sendGetHostInfoPacket() {
401         LifxHeader header;
402         header.setSize(36);
403         header.setTagged(false);
404         header.setMacAddress(bulbMacAddress);
405         header.setSource(10);   // randomly picked
406         header.setAck_required(false);
407         header.setRes_required(false);
408         header.setSequence(0);
409         header.setType(12);
410
411         char dataBytes[36];
412         header.getHeaderBytes(dataBytes);
413
414         sendPacket(dataBytes, 36);
415 }
416
417
418 void LifxLightBulb::sendGetHostFirmwarePacket() {
419         LifxHeader header;
420         header.setSize(36);
421         header.setTagged(false);
422         header.setMacAddress(bulbMacAddress);
423         header.setSource(10);   // randomly picked
424         header.setAck_required(false);
425         header.setRes_required(false);
426         header.setSequence(0);
427         header.setType(14);
428
429         char dataBytes[36];
430         header.getHeaderBytes(dataBytes);
431
432         sendPacket(dataBytes, 36);
433 }
434
435
436 void LifxLightBulb::sendGetWifiInfoPacket() {
437         LifxHeader header;
438         header.setSize(36);
439         header.setTagged(false);
440         header.setMacAddress(bulbMacAddress);
441         header.setSource(10);   // randomly picked
442         header.setAck_required(false);
443         header.setRes_required(false);
444         header.setSequence(0);
445         header.setType(16);
446
447         char dataBytes[36];
448         header.getHeaderBytes(dataBytes);
449
450         sendPacket(dataBytes, 36);
451 }
452
453
454 void LifxLightBulb::sendGetWifiFirmwarePacket() {
455         LifxHeader header;
456         header.setSize(36);
457         header.setTagged(false);
458         header.setMacAddress(bulbMacAddress);
459         header.setSource(10);   // randomly picked
460         header.setAck_required(false);
461         header.setRes_required(false);
462         header.setSequence(0);
463         header.setType(18);
464
465         char dataBytes[36];
466         header.getHeaderBytes(dataBytes);
467
468         sendPacket(dataBytes, 36);
469 }
470
471
472 void LifxLightBulb::sendGetPowerPacket() {
473         LifxHeader header;
474         header.setSize(36);
475         header.setTagged(false);
476         header.setMacAddress(bulbMacAddress);
477         header.setSource(10);   // randomly picked
478         header.setAck_required(false);
479         header.setRes_required(false);
480         header.setSequence(0);
481         header.setType(20);
482
483         char dataBytes[36];
484         header.getHeaderBytes(dataBytes);
485
486         sendPacket(dataBytes, 36);
487 }
488
489
490 void LifxLightBulb::sendSetPowerPacket(int level) {
491         // Currently only 0 and 65535 are supported
492         // This is a fix for now
493         if ((level != 65535) && (level != 0)) {
494                 cerr << "Invalid parameter values" << endl;
495                 exit(1);
496         }
497
498         if ((level > 65535) || (level < 0)) {
499                 cerr << "Invalid parameter values" << endl;
500                 exit(1);
501         }
502
503         char packetBytes[38];
504
505         LifxHeader header;
506         header.setSize(38);
507         header.setTagged(false);
508         header.setMacAddress(bulbMacAddress);
509         header.setSource(10);   // randomly picked
510         header.setAck_required(false);
511         header.setRes_required(false);
512         header.setSequence(0);
513         header.setType(21);
514         char headerBytes[36];
515         header.getHeaderBytes(headerBytes);
516
517         for (int i = 0; i < 36; i++) {
518                 packetBytes[i] = headerBytes[i];
519         }
520
521         packetBytes[36] = (char)(level & 0xFF);
522         packetBytes[37] = (char)((level >> 8) & 0xFF);
523
524         sendPacket(packetBytes, 38);
525 }
526
527
528 void LifxLightBulb::sendGetLabelPacket() {
529         LifxHeader header;
530         header.setSize(36);
531         header.setTagged(false);
532         header.setMacAddress(bulbMacAddress);
533         header.setSource(10); // randomly picked
534         header.setAck_required(false);
535         header.setRes_required(false);
536         header.setSequence(0);
537         header.setType(23);
538
539         char dataBytes[36];
540         header.getHeaderBytes(dataBytes);
541
542         sendPacket(dataBytes, 36);
543 }
544
545
546 void LifxLightBulb::sendSetLabelPacket(string label) {
547         // Currently only 0 and 65535 are supported
548         // This is a fix for now
549         if (label.length() != 32) {
550                 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
551                 exit(1);
552         }
553
554         char packetBytes[68];
555
556         LifxHeader header;
557         header.setSize(68);
558         header.setTagged(false);
559         header.setMacAddress(bulbMacAddress);
560         header.setSource(10); // randomly picked
561         header.setAck_required(false);
562         header.setRes_required(false);
563         header.setSequence(0);
564         header.setType(24);
565         char headerBytes[36];
566         header.getHeaderBytes(headerBytes);
567
568         for (int i = 0; i < 36; i++) {
569                 packetBytes[i] = headerBytes[i];
570         }
571
572         for (int i = 0; i < 32; i++) {
573                 packetBytes[i + 36] = label.c_str()[i];
574         }
575
576         sendPacket(packetBytes, 68);
577 }
578
579
580 void LifxLightBulb::sendGetVersionPacket() {
581         LifxHeader header;
582         header.setSize(36);
583         header.setTagged(false);
584         header.setMacAddress(bulbMacAddress);
585         header.setSource(10); // randomly picked
586         header.setAck_required(false);
587         header.setRes_required(false);
588         header.setSequence(0);
589         header.setType(32);
590
591         char dataBytes[36];
592         header.getHeaderBytes(dataBytes);
593
594         sendPacket(dataBytes, 36);
595 }
596
597
598 void LifxLightBulb::sendGetInfoPacket() {
599         LifxHeader header;
600         header.setSize(36);
601         header.setTagged(false);
602         header.setMacAddress(bulbMacAddress);
603         header.setSource(10); // randomly picked
604         header.setAck_required(false);
605         header.setRes_required(false);
606         header.setSequence(0);
607         header.setType(34);
608
609         char dataBytes[36];
610         header.getHeaderBytes(dataBytes);
611
612         sendPacket(dataBytes, 36);
613 }
614
615
616 void LifxLightBulb::sendGetLocationPacket() {
617         LifxHeader header;
618         header.setSize(36);
619         header.setTagged(false);
620         header.setMacAddress(bulbMacAddress);
621         header.setSource(10); // randomly picked
622         header.setAck_required(false);
623         header.setRes_required(false);
624         header.setSequence(0);
625         header.setType(34);
626
627         char dataBytes[36];
628         header.getHeaderBytes(dataBytes);
629
630         sendPacket(dataBytes, 36);
631 }
632
633
634 void LifxLightBulb::sendGetGroupPacket() {
635         LifxHeader header;
636         header.setSize(36);
637         header.setTagged(false);
638         header.setMacAddress(bulbMacAddress);
639         header.setSource(10); // randomly picked
640         header.setAck_required(false);
641         header.setRes_required(false);
642         header.setSequence(0);
643         header.setType(51);
644
645         char dataBytes[36];
646         header.getHeaderBytes(dataBytes);
647
648         sendPacket(dataBytes, 36);
649 }
650
651
652 //  Sending
653 //  Light Messages
654 void LifxLightBulb::sendGetLightStatePacket() {
655         LifxHeader header;
656         header.setSize(36);
657         header.setTagged(false);
658         header.setMacAddress(bulbMacAddress);
659         header.setSource(10); // randomly picked
660         header.setAck_required(false);
661         header.setRes_required(false);
662         header.setSequence(0);
663         header.setType(101);
664
665         char dataBytes[36];
666         header.getHeaderBytes(dataBytes);
667
668         sendPacket(dataBytes, 36);
669 }
670
671
672 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
673
674         if ((duration > 4294967295l) || (duration < 0)) {
675                 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
676                 exit(1);
677         }
678
679         char packetBytes[49];
680
681         LifxHeader header;
682         header.setSize(49);
683         header.setTagged(false);
684         header.setMacAddress(bulbMacAddress);
685         header.setSource(10); // randomly picked
686         header.setAck_required(false);
687         header.setRes_required(false);
688         header.setSequence(0);
689         header.setType(102);
690         char headerBytes[36];
691         header.getHeaderBytes(headerBytes);
692
693         for (int i = 0; i < 36; i++) {
694                 packetBytes[i] = headerBytes[i];
695         }
696
697         // 1 reserved packet
698         packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
699         packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
700
701         packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
702         packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
703
704         packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
705         packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
706
707         packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
708         packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
709
710         packetBytes[45] = (char)((duration >> 0) & 0xFF);
711         packetBytes[46] = (char)((duration >> 8) & 0xFF);
712         packetBytes[47] = (char)((duration >> 16) & 0xFF);
713         packetBytes[48] = (char)((duration >> 24) & 0xFF);
714
715         sendPacket(packetBytes, 49);
716         // Avoid memory leak - delete object
717         delete bulbColor;
718 }
719
720
721 void LifxLightBulb::sendGetLightPowerPacket() {
722         LifxHeader header;
723         header.setSize(36);
724         header.setTagged(false);
725         header.setMacAddress(bulbMacAddress);
726         header.setSource(10); // randomly picked
727         header.setAck_required(false);
728         header.setRes_required(false);
729         header.setSequence(0);
730         header.setType(116);
731
732         char dataBytes[36];
733         header.getHeaderBytes(dataBytes);
734
735         sendPacket(dataBytes, 36);
736 }
737
738
739 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
740
741         if ((level > 65535) || (duration > 4294967295l)
742                     || (level < 0) || (duration < 0)) {
743                 cerr << "Invalid parameter values" << endl;
744                 exit(1);
745         }
746         char packetBytes[42];
747
748         LifxHeader header;
749         header.setSize(42);
750         header.setTagged(false);
751         header.setMacAddress(bulbMacAddress);
752         header.setSource(10);   // randomly picked
753         header.setAck_required(false);
754         header.setRes_required(false);
755         header.setSequence(0);
756         header.setType(117);
757         char headerBytes[36];
758         header.getHeaderBytes(headerBytes);
759
760         for (int i = 0; i < 36; i++) {
761                 packetBytes[i] = headerBytes[i];
762         }
763
764         packetBytes[36] = (char)(level & 0xFF);
765         packetBytes[37] = (char)((level >> 8) & 0xFF);
766
767         packetBytes[38] = (char)((duration >> 0) & 0xFF);
768         packetBytes[39] = (char)((duration >> 8) & 0xFF);
769         packetBytes[40] = (char)((duration >> 16) & 0xFF);
770         packetBytes[41] = (char)((duration >> 24) & 0xFF);
771
772         sendPacket(packetBytes, 42);
773 }
774
775
776 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
777
778         char packetBytes[100];
779
780         LifxHeader header;
781         header.setSize(100);
782         header.setTagged(false);
783         header.setMacAddress(bulbMacAddress);
784         header.setSource(10); // randomly picked
785         header.setAck_required(false);
786         header.setRes_required(false);
787         header.setSequence(0);
788         header.setType(58);
789         char headerBytes[36];
790         header.getHeaderBytes(headerBytes);
791
792         for (int i = 0; i < 36; i++) {
793                 packetBytes[i] = headerBytes[i];
794         }
795
796         for (int i = 0; i < 64; i++) {
797                 packetBytes[i + 36] = data[i];
798         }
799
800         sendPacket(packetBytes, 100);
801 }
802
803
804 // Receiving
805 // Device Messages
806 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
807         int service = payloadData[0];
808         int64_t port = ((payloadData[3] & 0xFF) << 24);
809         port |= ((payloadData[2] & 0xFF) << 16);
810         port |= ((payloadData[1] & 0xFF) << 8);
811         port |= (payloadData[0] & 0xFF);
812
813         return new DeviceStateService(service, port);
814 }
815
816
817 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
818         long signal = ((payloadData[3] & 0xFF) << 24);
819         signal |= ((payloadData[2] & 0xFF) << 16);
820         signal |= ((payloadData[1] & 0xFF) << 8);
821         signal |= (payloadData[0] & 0xFF);
822
823         long tx = ((payloadData[7] & 0xFF) << 24);
824         tx |= ((payloadData[6] & 0xFF) << 16);
825         tx |= ((payloadData[5] & 0xFF) << 8);
826         tx |= (payloadData[4] & 0xFF);
827
828         long rx = ((payloadData[11] & 0xFF) << 24);
829         rx |= ((payloadData[10] & 0xFF) << 16);
830         rx |= ((payloadData[9] & 0xFF) << 8);
831         rx |= (payloadData[8] & 0xFF);
832
833         return new DeviceStateHostInfo(signal, tx, rx);
834 }
835
836
837 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
838         long build = 0;
839         for (int i = 0; i < 8; i++) {
840                 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
841         }
842
843         // 8 reserved bytes
844
845         int64_t version = ((payloadData[19] & 0xFF) << 24);
846         version |= ((payloadData[18] & 0xFF) << 16);
847         version |= ((payloadData[17] & 0xFF) << 8);
848         version |= (payloadData[16] & 0xFF);
849
850         return new DeviceStateHostFirmware(build, version);
851 }
852
853
854 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
855         int64_t signal = ((payloadData[3] & 0xFF) << 24);
856         signal |= ((payloadData[2] & 0xFF) << 16);
857         signal |= ((payloadData[1] & 0xFF) << 8);
858         signal |= (payloadData[0] & 0xFF);
859
860         int64_t tx = ((payloadData[7] & 0xFF) << 24);
861         tx |= ((payloadData[6] & 0xFF) << 16);
862         tx |= ((payloadData[5] & 0xFF) << 8);
863         tx |= (payloadData[4] & 0xFF);
864
865         int64_t rx = ((payloadData[11] & 0xFF) << 24);
866         rx |= ((payloadData[10] & 0xFF) << 16);
867         rx |= ((payloadData[9] & 0xFF) << 8);
868         rx |= (payloadData[8] & 0xFF);
869
870         return new DeviceStateWifiInfo(signal, tx, rx);
871 }
872
873
874 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
875         long build = 0;
876         for (int i = 0; i < 8; i++) {
877                 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
878         }
879
880         // 8 reserved bytes
881
882         int64_t version = ((payloadData[19] & 0xFF) << 24);
883         version |= ((payloadData[18] & 0xFF) << 16);
884         version |= ((payloadData[17] & 0xFF) << 8);
885         version |= (payloadData[16] & 0xFF);
886
887         return new DeviceStateWifiFirmware(build, version);
888 }
889
890
891 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
892         int level = ((payloadData[1] & 0xFF) << 8);
893         level |= (payloadData[0] & 0xFF);
894         return level;
895 }
896
897
898 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
899         int64_t vender = ((payloadData[3] & 0xFF) << 24);
900         vender |= ((payloadData[2] & 0xFF) << 16);
901         vender |= ((payloadData[1] & 0xFF) << 8);
902         vender |= (payloadData[0] & 0xFF);
903
904         int64_t product = ((payloadData[7] & 0xFF) << 24);
905         product |= ((payloadData[6] & 0xFF) << 16);
906         product |= ((payloadData[5] & 0xFF) << 8);
907         product |= (payloadData[4] & 0xFF);
908
909         int64_t version = ((payloadData[11] & 0xFF) << 24);
910         version |= ((payloadData[10] & 0xFF) << 16);
911         version |= ((payloadData[9] & 0xFF) << 8);
912         version |= (payloadData[8] & 0xFF);
913
914         return new DeviceStateVersion(vender, product, version);
915 }
916
917
918 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
919         int64_t time = 0;
920         int64_t upTime = 0;
921         int64_t downTime = 0;
922         for (int i = 0; i < 8; i++) {
923                 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
924                 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
925                 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
926         }
927
928         return new DeviceStateInfo(time, upTime, downTime);
929 }
930
931
932 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
933         char location[16];
934         for (int i = 0; i < 16; i++) {
935                 location[i] = payloadData[i];
936         }
937
938         char labelBytes[32];
939         for (int i = 0; i < 32; i++) {
940                 labelBytes[i] = payloadData[i + 16];
941         }
942
943         int64_t updatedAt = 0;
944         for (int i = 0; i < 8; i++) {
945                 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
946         }
947
948         string str(labelBytes);
949         return new DeviceStateLocation(location, str, updatedAt);
950 }
951
952
953 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
954         char group[16];
955         for (int i = 0; i < 16; i++) {
956                 group[i] = payloadData[i];
957         }
958
959         char labelBytes[32];
960         for (int i = 0; i < 32; i++) {
961                 labelBytes[i] = payloadData[i + 16];
962         }
963
964         int64_t updatedAt = 0;
965         for (int i = 0; i < 8; i++) {
966                 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
967         }
968
969         string str(labelBytes);
970         return new DeviceStateGroup(group, str, updatedAt);
971 }
972
973
974 // Receiving
975 // Light Messages
976 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
977
978         char colorData[8];
979         for (int i = 0; i < 8; i++) {
980                 colorData[i] = payloadData[i];
981         }
982         //BulbColor color(colorData);
983         BulbColor* color = new BulbColor(colorData);
984
985         int power = ((payloadData[11] & 0xFF) << 8);
986         power |= (payloadData[10] & 0xFF);
987
988         string label(payloadData);
989
990         char labelArray[32];
991         for (int i = 0; i < 32; i++) {
992                 labelArray[i] = payloadData[12 + i];
993         }
994
995         return new LightState(color, power, label);
996 }
997
998
999 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1000         int level = ((payloadData[1] & 0xFF) << 8);
1001         level |= (payloadData[0] & 0xFF);
1002         return level;
1003 }
1004
1005
1006 // Private Handlers
1007 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1008
1009         DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1010         int productNumber = (int)deviceState->getProduct();
1011
1012         bool isColor = false;
1013
1014         if (productNumber == 1) {// Original 1000
1015                 isColor = true;
1016         } else if (productNumber == 3) {//Color 650
1017                 isColor = true;
1018         } else if (productNumber == 10) {// White 800 (Low Voltage)
1019                 isColor = false;
1020         } else if (productNumber == 11) {// White 800 (High Voltage)
1021                 isColor = false;
1022         } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1023                 isColor = false;
1024         } else if (productNumber == 20) {// Color 1000 BR30
1025                 isColor = true;
1026         } else if (productNumber == 22) {// Color 1000
1027                 isColor = true;
1028         }
1029
1030         if (isColor) {
1031                 hueLowerBound = 0;
1032                 hueUpperBound = 65535;
1033                 saturationLowerBound = 0;
1034                 saturationUpperBound = 65535;
1035                 brightnessLowerBound = 0;
1036                 brightnessUpperBound = 65535;
1037                 temperatureLowerBound = 2500;
1038                 temperatureUpperBound = 9000;
1039         } else {
1040                 hueLowerBound = 0;
1041                 hueUpperBound = 0;
1042                 saturationLowerBound = 0;
1043                 saturationUpperBound = 0;
1044                 brightnessLowerBound = 0;
1045                 brightnessUpperBound = 65535;// still can dim bulb
1046                 temperatureLowerBound = 2500;
1047                 temperatureUpperBound = 9000;
1048         }
1049
1050         //didGetBulbVersion.exchange(true);
1051         didGetBulbVersion = true;
1052         // Avoid memory leak - delete this object
1053         delete deviceState;
1054 }
1055
1056
1057 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1058         LightState* lightState = parseLightStateMessage(payloadData);
1059
1060         BulbColor* color = lightState->getColor();
1061         int power = lightState->getPower();
1062
1063         //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1064         //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1065         //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1066         //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1067
1068         bool bulbWrongColor = false;
1069         bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1070         bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1071         bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1072         bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1073
1074
1075         // gets set to true if any of the below if statements are taken
1076         stateDidChange = false;
1077
1078         if (bulbWrongColor) {
1079                 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1080                 sendSetLightColorPacket(newColor, 250);
1081                 //cout << "Failed Check 1" << endl;
1082         }
1083
1084         bulbStateMutex.lock();
1085         bool bulbIsOnTmp = bulbIsOn;
1086         bulbStateMutex.unlock();
1087
1088         if ((!bulbIsOnTmp) && (power != 0)) {
1089                 turnOff();
1090                 //cout << "Failed Check 2:  " << endl;
1091
1092         }
1093
1094         if (bulbIsOnTmp && (power < 65530)) {
1095                 turnOn();
1096                 //cout << "Failed Check 3:  " << endl;
1097
1098         }
1099         // Avoid memory leak - delete object
1100         delete lightState;
1101         delete color;
1102 }
1103