1 #ifndef _LIFXLIGHTBULB_HPP__
2 #define _LIFXLIGHTBULB_HPP__
12 #include "LightBulb.hpp"
14 #include "IoTRMIUtil.hpp"
17 #include "IoTDeviceAddress.hpp"
18 #include "Iterator.hpp"
20 // Helper classes for LifxLightBulb
21 #include "LifxHeader.hpp"
22 #include "BulbColor.hpp"
23 #include "DeviceStateGroup.hpp"
24 #include "DeviceStateHostFirmware.hpp"
25 #include "DeviceStateHostInfo.hpp"
26 #include "DeviceStateInfo.hpp"
27 #include "DeviceStateLocation.hpp"
28 #include "DeviceStateService.hpp"
29 #include "DeviceStateVersion.hpp"
30 #include "DeviceStateWifiFirmware.hpp"
31 #include "DeviceStateWifiInfo.hpp"
32 #include "LightState.hpp"
37 // Driver LifxLightBulb
38 // Implemented based on LightBulb virtual class (interface)
41 std::atomic<bool> didAlreadyInit(false);
42 std::atomic<bool> didGetBulbVersion(false);
44 class LifxLightBulb //: public LightBulb
48 const static int64_t GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
51 IoTUDP *communicationSocket;
52 char bulbMacAddress[8];
54 //static Semaphore socketMutex = new Semaphore(1);
55 bool sendSocketFlag = false;
56 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
58 // Current Bulb Values
60 int currentSaturation = 0;
61 int currentBrightness = 65535;
62 int currentTemperature = 9000;
63 bool bulbIsOn = false;
66 atomic<bool> didAlreadyInit;
67 atomic<bool> didGetBulbVersion;
71 mutex settingBulbColorMutex;
72 mutex settingBulbTemperatureMutex;
75 // color and temperature ranges for the bulbs
76 int hueLowerBound = 0;
77 int hueUpperBound = 0;
78 int saturationLowerBound = 0;
79 int saturationUpperBound = 0;
80 int brightnessLowerBound = 0;
81 int brightnessUpperBound = 0;
82 int temperatureLowerBound = 2500;
83 int temperatureUpperBound = 9000;
85 // Check if a state change was requested, used to poll the bulb for if the bulb did
86 // preform the requested state change
87 bool stateDidChange = false;
90 IoTSet<IoTDeviceAddress> lb_addresses;
96 // LB1 macAddress: d0:73:d5:12:8e:30
97 // LB1 macAddress: d0:73:d5:02:41:da
98 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
99 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
100 /*bulbMacAddress[0] = 0xD0;
101 bulbMacAddress[1] = 0x73;
102 bulbMacAddress[2] = 0xD5;
103 bulbMacAddress[3] = 0x02;
104 bulbMacAddress[4] = 0x41;
105 bulbMacAddress[5] = 0xDA;
106 bulbMacAddress[6] = 0x00;
107 bulbMacAddress[7] = 0x00;*/
109 char tmpMacAddress[16];
110 strcpy(tmpMacAddress, macAddress.c_str());
111 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
112 for(int i=0; i<16; i=i+2) {
113 // Take 2 digits and then convert
115 tmpMacByte[0] = tmpMacAddress[i];
116 tmpMacByte[1] = tmpMacAddress[i+1];
117 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
119 //IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
123 LifxLightBulb(IoTSet<IoTDeviceAddress> _devAddress, string macAddress) {
125 // Initialize macAddress
126 char tmpMacAddress[16];
127 strcpy(tmpMacAddress, macAddress.c_str());
128 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
129 for(int i=0; i<16; i=i+2) {
130 // Take 2 digits and then convert
132 tmpMacByte[0] = tmpMacAddress[i];
133 tmpMacByte[1] = tmpMacAddress[i+1];
134 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
136 cout << "MAC address is set. Value: ";
137 IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
139 // Initialize device address
140 lb_addresses = _devAddress;
141 cout << "Device address is set! " << endl;
148 if (communicationSocket != NULL) {
150 delete communicationSocket;
151 communicationSocket = NULL;
156 // Initialize the lightbulb
159 if (didAlreadyInit.exchange(true))
162 unordered_set<IoTDeviceAddress>::const_iterator itr = lb_addresses.begin();
163 IoTDeviceAddress deviceAddress = *itr;
164 cout << "Address: " << deviceAddress.getAddress() << endl;
166 // Create IoTUDP socket
167 communicationSocket = new IoTUDP(deviceAddress);
169 // Launch the worker function in a separate thread.
170 thread th1 (&LifxLightBulb::workerFunction, this);
177 lock_guard<mutex> guard(bulbStateMutex);
179 sendSetLightPowerPacket(0, 0);
180 stateDidChange = true;
181 cout << "Turning off lightbulb!" << endl;
187 lock_guard<mutex> guard(bulbStateMutex);
189 sendSetLightPowerPacket(65535, 0);
190 stateDidChange = true;
196 settingBulbColorMutex.lock();
197 tmp = ((double)currentHue / 65535.0) * 360.0;
198 settingBulbColorMutex.unlock();
204 double getSaturation() {
206 settingBulbColorMutex.lock();
207 tmp = ((double)currentSaturation / 65535.0) * 360.0;
208 settingBulbColorMutex.unlock();
214 double getBrightness() {
216 settingBulbColorMutex.lock();
217 tmp = ((double)currentBrightness / 65535.0) * 360.0;
218 settingBulbColorMutex.unlock();
224 int getTemperature() {
227 settingBulbTemperatureMutex.lock();
228 tmp = currentTemperature;
229 settingBulbTemperatureMutex.unlock();
235 double getHueRangeLowerBound() {
236 if (!didGetBulbVersion) {
239 return ((double)hueLowerBound / 65535.0) * 360.0;
243 double getHueRangeUpperBound() {
244 if (!didGetBulbVersion) {
247 return ((double)hueUpperBound / 65535.0) * 360.0;
251 double getSaturationRangeLowerBound() {
252 if (!didGetBulbVersion) {
255 return ((double)saturationLowerBound / 65535.0) * 100.0;
259 double getSaturationRangeUpperBound() {
260 if (!didGetBulbVersion) {
263 return ((double)saturationUpperBound / 65535.0) * 100.0;
267 double getBrightnessRangeLowerBound() {
268 if (!didGetBulbVersion) {
271 return ((double)brightnessLowerBound / 65535.0) * 100.0;
275 double getBrightnessRangeUpperBound() {
276 if (!didGetBulbVersion) {
279 return ((double)brightnessUpperBound / 65535.0) * 100.0;
283 int getTemperatureRangeLowerBound() {
284 if (!didGetBulbVersion) {
287 return temperatureLowerBound;
291 int getTemperatureRangeUpperBound() {
292 if (!didGetBulbVersion) {
295 return temperatureUpperBound;
299 void setTemperature(int _temperature) {
301 settingBulbTemperatureMutex.lock();
303 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
304 sendSetLightColorPacket(newColor, 250);
306 currentTemperature = _temperature;
307 stateDidChange = true;
309 settingBulbTemperatureMutex.unlock();
313 void setColor(double _hue, double _saturation, double _brightness) {
315 settingBulbColorMutex.lock();
318 _saturation /= 100.0;
319 _brightness /= 100.0;
322 int newHue = (int)(_hue * 65535.0);
323 int newSaturation = (int)(_saturation * 65535.0);
324 int newBrightness = (int)(_brightness * 65535.0);
326 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
327 sendSetLightColorPacket(newColor, 250);
330 currentSaturation = newSaturation;
331 currentBrightness = newBrightness;
332 stateDidChange = true;
334 settingBulbColorMutex.unlock();
342 bulbStateMutex.lock();
344 bulbStateMutex.unlock();
352 // Communication helpers
353 void receivedPacket(char* packetData) {
355 char headerBytes[36];
356 for (int i = 0; i < 36; i++) {
357 headerBytes[i] = packetData[i];
360 LifxHeader recHeader;
361 recHeader.setFromBytes(headerBytes);
363 // load the payload bytes (strip away the header)
364 char payloadBytes[recHeader.getSize()];
365 for (int i = 36; i < recHeader.getSize(); i++) {
366 payloadBytes[i - 36] = packetData[i];
369 int type = recHeader.getType();
370 cout << "Received: " << type;
372 DeviceStateService* dat = NULL;
376 dat = parseDeviceStateServiceMessage(payloadBytes);
377 cout << "Service: " << dat->getService();
378 cout << "Port : " << dat->getPort();
379 // Avoid memory leak - delete this object
384 handleStateVersionMessageReceived(payloadBytes);
388 parseDeviceStateInfoMessage(payloadBytes);
393 handleLightStateMessageReceived(payloadBytes);
397 cout << "unknown packet Type" << endl;
403 void sendPacket(char* packetData, int len) {
404 //cout << "sendPacket: About to send" << endl;
405 lock_guard<mutex> guard(socketMutex);
406 sendSocketFlag = true;
407 communicationSocket->sendData(packetData, len);
408 sendSocketFlag = false;
412 // Worker function which runs the while loop for receiving data from the bulb.
414 void workerFunction() {
416 // Need timeout on receives since we are not sure if a packet will be available
417 // for processing so don't block waiting
418 // TODO: Check if we can do this here!
419 //communicationSocket.setSoTimeout(50);
425 // Check if we got the bulb version yet
426 // could have requested it but message could have gotten lost (UDP)
427 if (!didGetBulbVersion) {
428 int64_t currentTime = (int64_t) time(NULL);
429 if ((currentTime - lastSentGetBulbVersionRequest) > GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
430 // Get the bulb version so we know what type of bulb this is.
431 sendGetVersionPacket();
432 lastSentGetBulbVersionRequest = currentTime;
436 // Communication resource is busy so try again later
437 if (sendSocketFlag) {
441 /*socketMutex.lock();
444 dat = communicationSocket.receiveData(1024);
446 // Never forget to release!
447 socketMutex.unlock();
454 // If a state change occurred then request the bulb state to ensure that the
455 // bulb did indeed change its state to the correct state
456 if (stateDidChange) {
457 sendGetLightStatePacket();
460 // Wait a bit as to not tie up system resources
461 this_thread::sleep_for (chrono::milliseconds(100));
462 } catch (Exception e) {
473 void sendGetServicePacket() {
476 header.setTagged(true);
477 header.setMacAddress(bulbMacAddress);
478 header.setSource(0); // randomly picked
479 header.setAck_required(false);
480 header.setRes_required(false);
481 header.setSequence(0);
485 header.getHeaderBytes(dataBytes);
487 sendPacket(dataBytes, 36);
491 void sendGetHostInfoPacket() {
494 header.setTagged(false);
495 header.setMacAddress(bulbMacAddress);
496 header.setSource(10); // randomly picked
497 header.setAck_required(false);
498 header.setRes_required(false);
499 header.setSequence(0);
503 header.getHeaderBytes(dataBytes);
505 sendPacket(dataBytes, 36);
509 void sendGetHostFirmwarePacket() {
512 header.setTagged(false);
513 header.setMacAddress(bulbMacAddress);
514 header.setSource(10); // randomly picked
515 header.setAck_required(false);
516 header.setRes_required(false);
517 header.setSequence(0);
521 header.getHeaderBytes(dataBytes);
523 sendPacket(dataBytes, 36);
527 void sendGetWifiInfoPacket() {
530 header.setTagged(false);
531 header.setMacAddress(bulbMacAddress);
532 header.setSource(10); // randomly picked
533 header.setAck_required(false);
534 header.setRes_required(false);
535 header.setSequence(0);
539 header.getHeaderBytes(dataBytes);
541 sendPacket(dataBytes, 36);
545 void sendGetWifiFirmwarePacket() {
548 header.setTagged(false);
549 header.setMacAddress(bulbMacAddress);
550 header.setSource(10); // randomly picked
551 header.setAck_required(false);
552 header.setRes_required(false);
553 header.setSequence(0);
557 header.getHeaderBytes(dataBytes);
559 sendPacket(dataBytes, 36);
563 void sendGetPowerPacket() {
566 header.setTagged(false);
567 header.setMacAddress(bulbMacAddress);
568 header.setSource(10); // randomly picked
569 header.setAck_required(false);
570 header.setRes_required(false);
571 header.setSequence(0);
575 header.getHeaderBytes(dataBytes);
577 sendPacket(dataBytes, 36);
581 void sendSetPowerPacket(int level) {
582 // Currently only 0 and 65535 are supported
583 // This is a fix for now
584 if ((level != 65535) && (level != 0)) {
585 cerr << "Invalid parameter values" << endl;
589 if ((level > 65535) || (level < 0)) {
590 cerr << "Invalid parameter values" << endl;
594 char packetBytes[38];
598 header.setTagged(false);
599 header.setMacAddress(bulbMacAddress);
600 header.setSource(10); // randomly picked
601 header.setAck_required(false);
602 header.setRes_required(false);
603 header.setSequence(0);
605 char headerBytes[36];
606 header.getHeaderBytes(headerBytes);
608 for (int i = 0; i < 36; i++) {
609 packetBytes[i] = headerBytes[i];
612 packetBytes[36] = (char)(level & 0xFF);
613 packetBytes[37] = (char)((level >> 8) & 0xFF);
615 sendPacket(packetBytes, 38);
619 void sendGetLabelPacket() {
622 header.setTagged(false);
623 header.setMacAddress(bulbMacAddress);
624 header.setSource(10); // randomly picked
625 header.setAck_required(false);
626 header.setRes_required(false);
627 header.setSequence(0);
631 header.getHeaderBytes(dataBytes);
633 sendPacket(dataBytes, 36);
637 void sendSetLabelPacket(string label) {
638 // Currently only 0 and 65535 are supported
639 // This is a fix for now
640 if (label.length() != 32) {
641 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
645 char packetBytes[68];
649 header.setTagged(false);
650 header.setMacAddress(bulbMacAddress);
651 header.setSource(10); // randomly picked
652 header.setAck_required(false);
653 header.setRes_required(false);
654 header.setSequence(0);
656 char headerBytes[36];
657 header.getHeaderBytes(headerBytes);
659 for (int i = 0; i < 36; i++) {
660 packetBytes[i] = headerBytes[i];
663 for (int i = 0; i < 32; i++) {
664 packetBytes[i + 36] = label.c_str()[i];
667 sendPacket(packetBytes, 68);
671 void sendGetVersionPacket() {
674 header.setTagged(false);
675 header.setMacAddress(bulbMacAddress);
676 header.setSource(10); // randomly picked
677 header.setAck_required(false);
678 header.setRes_required(false);
679 header.setSequence(0);
683 header.getHeaderBytes(dataBytes);
685 sendPacket(dataBytes, 36);
689 void sendGetInfoPacket() {
692 header.setTagged(false);
693 header.setMacAddress(bulbMacAddress);
694 header.setSource(10); // randomly picked
695 header.setAck_required(false);
696 header.setRes_required(false);
697 header.setSequence(0);
701 header.getHeaderBytes(dataBytes);
703 sendPacket(dataBytes, 36);
707 void sendGetLocationPacket() {
710 header.setTagged(false);
711 header.setMacAddress(bulbMacAddress);
712 header.setSource(10); // randomly picked
713 header.setAck_required(false);
714 header.setRes_required(false);
715 header.setSequence(0);
719 header.getHeaderBytes(dataBytes);
721 sendPacket(dataBytes, 36);
725 void sendGetGroupPacket() {
728 header.setTagged(false);
729 header.setMacAddress(bulbMacAddress);
730 header.setSource(10); // randomly picked
731 header.setAck_required(false);
732 header.setRes_required(false);
733 header.setSequence(0);
737 header.getHeaderBytes(dataBytes);
739 sendPacket(dataBytes, 36);
745 void sendGetLightStatePacket() {
748 header.setTagged(false);
749 header.setMacAddress(bulbMacAddress);
750 header.setSource(10); // randomly picked
751 header.setAck_required(false);
752 header.setRes_required(false);
753 header.setSequence(0);
757 header.getHeaderBytes(dataBytes);
759 sendPacket(dataBytes, 36);
763 void sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
765 if ((duration > 4294967295l) || (duration < 0)) {
766 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
770 char packetBytes[49];
774 header.setTagged(false);
775 header.setMacAddress(bulbMacAddress);
776 header.setSource(10); // randomly picked
777 header.setAck_required(false);
778 header.setRes_required(false);
779 header.setSequence(0);
781 char headerBytes[36];
782 header.getHeaderBytes(headerBytes);
784 for (int i = 0; i < 36; i++) {
785 packetBytes[i] = headerBytes[i];
789 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
790 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
792 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
793 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
795 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
796 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
798 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
799 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
801 packetBytes[45] = (char)((duration >> 0) & 0xFF);
802 packetBytes[46] = (char)((duration >> 8) & 0xFF);
803 packetBytes[47] = (char)((duration >> 16) & 0xFF);
804 packetBytes[48] = (char)((duration >> 24) & 0xFF);
806 sendPacket(packetBytes, 49);
807 // Avoid memory leak - delete object
812 void sendGetLightPowerPacket() {
815 header.setTagged(false);
816 header.setMacAddress(bulbMacAddress);
817 header.setSource(10); // randomly picked
818 header.setAck_required(false);
819 header.setRes_required(false);
820 header.setSequence(0);
824 header.getHeaderBytes(dataBytes);
826 sendPacket(dataBytes, 36);
830 void sendSetLightPowerPacket(int level, long duration) {
832 if ((level > 65535) || (duration > 4294967295l)
833 || (level < 0) || (duration < 0)) {
834 cerr << "Invalid parameter values" << endl;
838 char packetBytes[42];
843 header.setTagged(false);
844 header.setMacAddress(bulbMacAddress);
845 header.setSource(10); // randomly picked
846 header.setAck_required(false);
847 header.setRes_required(false);
848 header.setSequence(0);
850 char headerBytes[36];
851 header.getHeaderBytes(headerBytes);
853 for (int i = 0; i < 36; i++) {
854 packetBytes[i] = headerBytes[i];
857 packetBytes[36] = (char)(level & 0xFF);
858 packetBytes[37] = (char)((level >> 8) & 0xFF);
860 packetBytes[38] = (char)((duration >> 0) & 0xFF);
861 packetBytes[39] = (char)((duration >> 8) & 0xFF);
862 packetBytes[40] = (char)((duration >> 16) & 0xFF);
863 packetBytes[41] = (char)((duration >> 24) & 0xFF);
865 sendPacket(packetBytes, 42);
869 void sendEchoRequestPacket(char data[64]) {
871 char packetBytes[100];
875 header.setTagged(false);
876 header.setMacAddress(bulbMacAddress);
877 header.setSource(10); // randomly picked
878 header.setAck_required(false);
879 header.setRes_required(false);
880 header.setSequence(0);
882 char headerBytes[36];
883 header.getHeaderBytes(headerBytes);
885 for (int i = 0; i < 36; i++) {
886 packetBytes[i] = headerBytes[i];
889 for (int i = 0; i < 64; i++) {
890 packetBytes[i + 36] = data[i];
893 sendPacket(packetBytes, 100);
899 DeviceStateService* parseDeviceStateServiceMessage(char* payloadData) {
900 int service = payloadData[0];
901 int64_t port = ((payloadData[3] & 0xFF) << 24);
902 port |= ((payloadData[2] & 0xFF) << 16);
903 port |= ((payloadData[1] & 0xFF) << 8);
904 port |= (payloadData[0] & 0xFF);
906 return new DeviceStateService(service, port);
910 DeviceStateHostInfo* parseDeviceStateHostInfoMessage(char* payloadData) {
911 long signal = ((payloadData[3] & 0xFF) << 24);
912 signal |= ((payloadData[2] & 0xFF) << 16);
913 signal |= ((payloadData[1] & 0xFF) << 8);
914 signal |= (payloadData[0] & 0xFF);
916 long tx = ((payloadData[7] & 0xFF) << 24);
917 tx |= ((payloadData[6] & 0xFF) << 16);
918 tx |= ((payloadData[5] & 0xFF) << 8);
919 tx |= (payloadData[4] & 0xFF);
921 long rx = ((payloadData[11] & 0xFF) << 24);
922 rx |= ((payloadData[10] & 0xFF) << 16);
923 rx |= ((payloadData[9] & 0xFF) << 8);
924 rx |= (payloadData[8] & 0xFF);
926 return new DeviceStateHostInfo(signal, tx, rx);
930 DeviceStateHostFirmware* parseDeviceStateHostFirmwareMessage(char* payloadData) {
932 for (int i = 0; i < 8; i++) {
933 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
938 int64_t version = ((payloadData[19] & 0xFF) << 24);
939 version |= ((payloadData[18] & 0xFF) << 16);
940 version |= ((payloadData[17] & 0xFF) << 8);
941 version |= (payloadData[16] & 0xFF);
943 return new DeviceStateHostFirmware(build, version);
947 DeviceStateWifiInfo* parseDeviceStateWifiInfoMessage(char* payloadData) {
948 int64_t signal = ((payloadData[3] & 0xFF) << 24);
949 signal |= ((payloadData[2] & 0xFF) << 16);
950 signal |= ((payloadData[1] & 0xFF) << 8);
951 signal |= (payloadData[0] & 0xFF);
953 int64_t tx = ((payloadData[7] & 0xFF) << 24);
954 tx |= ((payloadData[6] & 0xFF) << 16);
955 tx |= ((payloadData[5] & 0xFF) << 8);
956 tx |= (payloadData[4] & 0xFF);
958 int64_t rx = ((payloadData[11] & 0xFF) << 24);
959 rx |= ((payloadData[10] & 0xFF) << 16);
960 rx |= ((payloadData[9] & 0xFF) << 8);
961 rx |= (payloadData[8] & 0xFF);
963 return new DeviceStateWifiInfo(signal, tx, rx);
967 DeviceStateWifiFirmware* parseDeviceStateWifiFirmwareMessage(char* payloadData) {
969 for (int i = 0; i < 8; i++) {
970 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
975 int64_t version = ((payloadData[19] & 0xFF) << 24);
976 version |= ((payloadData[18] & 0xFF) << 16);
977 version |= ((payloadData[17] & 0xFF) << 8);
978 version |= (payloadData[16] & 0xFF);
980 return new DeviceStateWifiFirmware(build, version);
984 int parseStatePowerMessage(char* payloadData) {
985 int level = ((payloadData[1] & 0xFF) << 8);
986 level |= (payloadData[0] & 0xFF);
991 DeviceStateVersion* parseDeviceStateVersionMessage(char* payloadData) {
992 int64_t vender = ((payloadData[3] & 0xFF) << 24);
993 vender |= ((payloadData[2] & 0xFF) << 16);
994 vender |= ((payloadData[1] & 0xFF) << 8);
995 vender |= (payloadData[0] & 0xFF);
997 int64_t product = ((payloadData[7] & 0xFF) << 24);
998 product |= ((payloadData[6] & 0xFF) << 16);
999 product |= ((payloadData[5] & 0xFF) << 8);
1000 product |= (payloadData[4] & 0xFF);
1002 int64_t version = ((payloadData[11] & 0xFF) << 24);
1003 version |= ((payloadData[10] & 0xFF) << 16);
1004 version |= ((payloadData[9] & 0xFF) << 8);
1005 version |= (payloadData[8] & 0xFF);
1007 return new DeviceStateVersion(vender, product, version);
1011 DeviceStateInfo* parseDeviceStateInfoMessage(char* payloadData) {
1014 int64_t downTime = 0;
1015 for (int i = 0; i < 8; i++) {
1016 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
1017 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
1018 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
1021 return new DeviceStateInfo(time, upTime, downTime);
1025 DeviceStateLocation* parseDeviceStateLocationMessage(char* payloadData) {
1027 for (int i = 0; i < 16; i++) {
1028 location[i] = payloadData[i];
1031 char labelBytes[32];
1032 for (int i = 0; i < 32; i++) {
1033 labelBytes[i] = payloadData[i + 16];
1036 int64_t updatedAt = 0;
1037 for (int i = 0; i < 8; i++) {
1038 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1041 string str(labelBytes);
1042 return new DeviceStateLocation(location, str, updatedAt);
1046 DeviceStateGroup* parseDeviceStateGroupMessage(char* payloadData) {
1048 for (int i = 0; i < 16; i++) {
1049 group[i] = payloadData[i];
1052 char labelBytes[32];
1053 for (int i = 0; i < 32; i++) {
1054 labelBytes[i] = payloadData[i + 16];
1057 int64_t updatedAt = 0;
1058 for (int i = 0; i < 8; i++) {
1059 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1062 string str(labelBytes);
1063 return new DeviceStateGroup(group, str, updatedAt);
1069 LightState* parseLightStateMessage(char* payloadData) {
1072 for (int i = 0; i < 8; i++) {
1073 colorData[i] = payloadData[i];
1075 BulbColor color(colorData);
1077 int power = ((payloadData[11] & 0xFF) << 8);
1078 power |= (payloadData[10] & 0xFF);
1080 string label(payloadData);
1082 char labelArray[32];
1083 for (int i = 0; i < 32; i++) {
1084 labelArray[i] = payloadData[12 + i];
1087 return new LightState(&color, power, label);
1091 int parseLightStatePowerMessage(char* payloadData) {
1092 int level = ((payloadData[1] & 0xFF) << 8);
1093 level |= (payloadData[0] & 0xFF);
1099 void handleStateVersionMessageReceived(char* payloadData) {
1101 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1102 int productNumber = (int)deviceState->getProduct();
1104 bool isColor = false;
1106 if (productNumber == 1) {// Original 1000
1108 } else if (productNumber == 3) {//Color 650
1110 } else if (productNumber == 10) {// White 800 (Low Voltage)
1112 } else if (productNumber == 11) {// White 800 (High Voltage)
1114 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1116 } else if (productNumber == 20) {// Color 1000 BR30
1118 } else if (productNumber == 22) {// Color 1000
1124 hueUpperBound = 65535;
1125 saturationLowerBound = 0;
1126 saturationUpperBound = 65535;
1127 brightnessLowerBound = 0;
1128 brightnessUpperBound = 65535;
1129 temperatureLowerBound = 2500;
1130 temperatureUpperBound = 9000;
1134 saturationLowerBound = 0;
1135 saturationUpperBound = 0;
1136 brightnessLowerBound = 0;
1137 brightnessUpperBound = 65535;// still can dim bulb
1138 temperatureLowerBound = 2500;
1139 temperatureUpperBound = 9000;
1142 didGetBulbVersion.exchange(true);
1143 // Avoid memory leak - delete this object
1148 void handleLightStateMessageReceived(char* payloadData) {
1149 LightState* lightState = parseLightStateMessage(payloadData);
1151 BulbColor* color = lightState->getColor();
1152 int power = lightState->getPower();
1154 bool bulbWrongColor = false;
1155 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1156 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1157 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1158 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1161 // gets set to true if any of the below if statements are taken
1162 stateDidChange = false;
1164 if (bulbWrongColor) {
1165 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1166 sendSetLightColorPacket(newColor, 250);
1167 // System.out.println("Failed Check 1");
1170 bulbStateMutex.lock();
1171 bool bulbIsOnTmp = bulbIsOn;
1172 bulbStateMutex.unlock();
1174 if ((!bulbIsOnTmp) && (power != 0)) {
1176 // System.out.println("Failed Check 2: " + Integer.toString(power));
1180 if (bulbIsOnTmp && (power < 65530)) {
1182 // System.out.println("Failed Check 3: " + Integer.toString(power));
1185 // Avoid memory leak - delete object