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) {
444 int ret = communicationSocket->receiveData(dat, 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));
468 void sendGetServicePacket() {
471 header.setTagged(true);
472 header.setMacAddress(bulbMacAddress);
473 header.setSource(0); // randomly picked
474 header.setAck_required(false);
475 header.setRes_required(false);
476 header.setSequence(0);
480 header.getHeaderBytes(dataBytes);
482 sendPacket(dataBytes, 36);
486 void sendGetHostInfoPacket() {
489 header.setTagged(false);
490 header.setMacAddress(bulbMacAddress);
491 header.setSource(10); // randomly picked
492 header.setAck_required(false);
493 header.setRes_required(false);
494 header.setSequence(0);
498 header.getHeaderBytes(dataBytes);
500 sendPacket(dataBytes, 36);
504 void sendGetHostFirmwarePacket() {
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);
516 header.getHeaderBytes(dataBytes);
518 sendPacket(dataBytes, 36);
522 void sendGetWifiInfoPacket() {
525 header.setTagged(false);
526 header.setMacAddress(bulbMacAddress);
527 header.setSource(10); // randomly picked
528 header.setAck_required(false);
529 header.setRes_required(false);
530 header.setSequence(0);
534 header.getHeaderBytes(dataBytes);
536 sendPacket(dataBytes, 36);
540 void sendGetWifiFirmwarePacket() {
543 header.setTagged(false);
544 header.setMacAddress(bulbMacAddress);
545 header.setSource(10); // randomly picked
546 header.setAck_required(false);
547 header.setRes_required(false);
548 header.setSequence(0);
552 header.getHeaderBytes(dataBytes);
554 sendPacket(dataBytes, 36);
558 void sendGetPowerPacket() {
561 header.setTagged(false);
562 header.setMacAddress(bulbMacAddress);
563 header.setSource(10); // randomly picked
564 header.setAck_required(false);
565 header.setRes_required(false);
566 header.setSequence(0);
570 header.getHeaderBytes(dataBytes);
572 sendPacket(dataBytes, 36);
576 void sendSetPowerPacket(int level) {
577 // Currently only 0 and 65535 are supported
578 // This is a fix for now
579 if ((level != 65535) && (level != 0)) {
580 cerr << "Invalid parameter values" << endl;
584 if ((level > 65535) || (level < 0)) {
585 cerr << "Invalid parameter values" << endl;
589 char packetBytes[38];
593 header.setTagged(false);
594 header.setMacAddress(bulbMacAddress);
595 header.setSource(10); // randomly picked
596 header.setAck_required(false);
597 header.setRes_required(false);
598 header.setSequence(0);
600 char headerBytes[36];
601 header.getHeaderBytes(headerBytes);
603 for (int i = 0; i < 36; i++) {
604 packetBytes[i] = headerBytes[i];
607 packetBytes[36] = (char)(level & 0xFF);
608 packetBytes[37] = (char)((level >> 8) & 0xFF);
610 sendPacket(packetBytes, 38);
614 void sendGetLabelPacket() {
617 header.setTagged(false);
618 header.setMacAddress(bulbMacAddress);
619 header.setSource(10); // randomly picked
620 header.setAck_required(false);
621 header.setRes_required(false);
622 header.setSequence(0);
626 header.getHeaderBytes(dataBytes);
628 sendPacket(dataBytes, 36);
632 void sendSetLabelPacket(string label) {
633 // Currently only 0 and 65535 are supported
634 // This is a fix for now
635 if (label.length() != 32) {
636 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
640 char packetBytes[68];
644 header.setTagged(false);
645 header.setMacAddress(bulbMacAddress);
646 header.setSource(10); // randomly picked
647 header.setAck_required(false);
648 header.setRes_required(false);
649 header.setSequence(0);
651 char headerBytes[36];
652 header.getHeaderBytes(headerBytes);
654 for (int i = 0; i < 36; i++) {
655 packetBytes[i] = headerBytes[i];
658 for (int i = 0; i < 32; i++) {
659 packetBytes[i + 36] = label.c_str()[i];
662 sendPacket(packetBytes, 68);
666 void sendGetVersionPacket() {
669 header.setTagged(false);
670 header.setMacAddress(bulbMacAddress);
671 header.setSource(10); // randomly picked
672 header.setAck_required(false);
673 header.setRes_required(false);
674 header.setSequence(0);
678 header.getHeaderBytes(dataBytes);
680 sendPacket(dataBytes, 36);
684 void sendGetInfoPacket() {
687 header.setTagged(false);
688 header.setMacAddress(bulbMacAddress);
689 header.setSource(10); // randomly picked
690 header.setAck_required(false);
691 header.setRes_required(false);
692 header.setSequence(0);
696 header.getHeaderBytes(dataBytes);
698 sendPacket(dataBytes, 36);
702 void sendGetLocationPacket() {
705 header.setTagged(false);
706 header.setMacAddress(bulbMacAddress);
707 header.setSource(10); // randomly picked
708 header.setAck_required(false);
709 header.setRes_required(false);
710 header.setSequence(0);
714 header.getHeaderBytes(dataBytes);
716 sendPacket(dataBytes, 36);
720 void sendGetGroupPacket() {
723 header.setTagged(false);
724 header.setMacAddress(bulbMacAddress);
725 header.setSource(10); // randomly picked
726 header.setAck_required(false);
727 header.setRes_required(false);
728 header.setSequence(0);
732 header.getHeaderBytes(dataBytes);
734 sendPacket(dataBytes, 36);
740 void sendGetLightStatePacket() {
743 header.setTagged(false);
744 header.setMacAddress(bulbMacAddress);
745 header.setSource(10); // randomly picked
746 header.setAck_required(false);
747 header.setRes_required(false);
748 header.setSequence(0);
752 header.getHeaderBytes(dataBytes);
754 sendPacket(dataBytes, 36);
758 void sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
760 if ((duration > 4294967295l) || (duration < 0)) {
761 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
765 char packetBytes[49];
769 header.setTagged(false);
770 header.setMacAddress(bulbMacAddress);
771 header.setSource(10); // randomly picked
772 header.setAck_required(false);
773 header.setRes_required(false);
774 header.setSequence(0);
776 char headerBytes[36];
777 header.getHeaderBytes(headerBytes);
779 for (int i = 0; i < 36; i++) {
780 packetBytes[i] = headerBytes[i];
784 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
785 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
787 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
788 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
790 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
791 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
793 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
794 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
796 packetBytes[45] = (char)((duration >> 0) & 0xFF);
797 packetBytes[46] = (char)((duration >> 8) & 0xFF);
798 packetBytes[47] = (char)((duration >> 16) & 0xFF);
799 packetBytes[48] = (char)((duration >> 24) & 0xFF);
801 sendPacket(packetBytes, 49);
802 // Avoid memory leak - delete object
807 void sendGetLightPowerPacket() {
810 header.setTagged(false);
811 header.setMacAddress(bulbMacAddress);
812 header.setSource(10); // randomly picked
813 header.setAck_required(false);
814 header.setRes_required(false);
815 header.setSequence(0);
819 header.getHeaderBytes(dataBytes);
821 sendPacket(dataBytes, 36);
825 void sendSetLightPowerPacket(int level, long duration) {
827 if ((level > 65535) || (duration > 4294967295l)
828 || (level < 0) || (duration < 0)) {
829 cerr << "Invalid parameter values" << endl;
833 char packetBytes[42];
838 header.setTagged(false);
839 header.setMacAddress(bulbMacAddress);
840 header.setSource(10); // randomly picked
841 header.setAck_required(false);
842 header.setRes_required(false);
843 header.setSequence(0);
845 char headerBytes[36];
846 header.getHeaderBytes(headerBytes);
848 for (int i = 0; i < 36; i++) {
849 packetBytes[i] = headerBytes[i];
852 packetBytes[36] = (char)(level & 0xFF);
853 packetBytes[37] = (char)((level >> 8) & 0xFF);
855 packetBytes[38] = (char)((duration >> 0) & 0xFF);
856 packetBytes[39] = (char)((duration >> 8) & 0xFF);
857 packetBytes[40] = (char)((duration >> 16) & 0xFF);
858 packetBytes[41] = (char)((duration >> 24) & 0xFF);
860 sendPacket(packetBytes, 42);
864 void sendEchoRequestPacket(char data[64]) {
866 char packetBytes[100];
870 header.setTagged(false);
871 header.setMacAddress(bulbMacAddress);
872 header.setSource(10); // randomly picked
873 header.setAck_required(false);
874 header.setRes_required(false);
875 header.setSequence(0);
877 char headerBytes[36];
878 header.getHeaderBytes(headerBytes);
880 for (int i = 0; i < 36; i++) {
881 packetBytes[i] = headerBytes[i];
884 for (int i = 0; i < 64; i++) {
885 packetBytes[i + 36] = data[i];
888 sendPacket(packetBytes, 100);
894 DeviceStateService* parseDeviceStateServiceMessage(char* payloadData) {
895 int service = payloadData[0];
896 int64_t port = ((payloadData[3] & 0xFF) << 24);
897 port |= ((payloadData[2] & 0xFF) << 16);
898 port |= ((payloadData[1] & 0xFF) << 8);
899 port |= (payloadData[0] & 0xFF);
901 return new DeviceStateService(service, port);
905 DeviceStateHostInfo* parseDeviceStateHostInfoMessage(char* payloadData) {
906 long signal = ((payloadData[3] & 0xFF) << 24);
907 signal |= ((payloadData[2] & 0xFF) << 16);
908 signal |= ((payloadData[1] & 0xFF) << 8);
909 signal |= (payloadData[0] & 0xFF);
911 long tx = ((payloadData[7] & 0xFF) << 24);
912 tx |= ((payloadData[6] & 0xFF) << 16);
913 tx |= ((payloadData[5] & 0xFF) << 8);
914 tx |= (payloadData[4] & 0xFF);
916 long rx = ((payloadData[11] & 0xFF) << 24);
917 rx |= ((payloadData[10] & 0xFF) << 16);
918 rx |= ((payloadData[9] & 0xFF) << 8);
919 rx |= (payloadData[8] & 0xFF);
921 return new DeviceStateHostInfo(signal, tx, rx);
925 DeviceStateHostFirmware* parseDeviceStateHostFirmwareMessage(char* payloadData) {
927 for (int i = 0; i < 8; i++) {
928 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
933 int64_t version = ((payloadData[19] & 0xFF) << 24);
934 version |= ((payloadData[18] & 0xFF) << 16);
935 version |= ((payloadData[17] & 0xFF) << 8);
936 version |= (payloadData[16] & 0xFF);
938 return new DeviceStateHostFirmware(build, version);
942 DeviceStateWifiInfo* parseDeviceStateWifiInfoMessage(char* payloadData) {
943 int64_t signal = ((payloadData[3] & 0xFF) << 24);
944 signal |= ((payloadData[2] & 0xFF) << 16);
945 signal |= ((payloadData[1] & 0xFF) << 8);
946 signal |= (payloadData[0] & 0xFF);
948 int64_t tx = ((payloadData[7] & 0xFF) << 24);
949 tx |= ((payloadData[6] & 0xFF) << 16);
950 tx |= ((payloadData[5] & 0xFF) << 8);
951 tx |= (payloadData[4] & 0xFF);
953 int64_t rx = ((payloadData[11] & 0xFF) << 24);
954 rx |= ((payloadData[10] & 0xFF) << 16);
955 rx |= ((payloadData[9] & 0xFF) << 8);
956 rx |= (payloadData[8] & 0xFF);
958 return new DeviceStateWifiInfo(signal, tx, rx);
962 DeviceStateWifiFirmware* parseDeviceStateWifiFirmwareMessage(char* payloadData) {
964 for (int i = 0; i < 8; i++) {
965 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
970 int64_t version = ((payloadData[19] & 0xFF) << 24);
971 version |= ((payloadData[18] & 0xFF) << 16);
972 version |= ((payloadData[17] & 0xFF) << 8);
973 version |= (payloadData[16] & 0xFF);
975 return new DeviceStateWifiFirmware(build, version);
979 int parseStatePowerMessage(char* payloadData) {
980 int level = ((payloadData[1] & 0xFF) << 8);
981 level |= (payloadData[0] & 0xFF);
986 DeviceStateVersion* parseDeviceStateVersionMessage(char* payloadData) {
987 int64_t vender = ((payloadData[3] & 0xFF) << 24);
988 vender |= ((payloadData[2] & 0xFF) << 16);
989 vender |= ((payloadData[1] & 0xFF) << 8);
990 vender |= (payloadData[0] & 0xFF);
992 int64_t product = ((payloadData[7] & 0xFF) << 24);
993 product |= ((payloadData[6] & 0xFF) << 16);
994 product |= ((payloadData[5] & 0xFF) << 8);
995 product |= (payloadData[4] & 0xFF);
997 int64_t version = ((payloadData[11] & 0xFF) << 24);
998 version |= ((payloadData[10] & 0xFF) << 16);
999 version |= ((payloadData[9] & 0xFF) << 8);
1000 version |= (payloadData[8] & 0xFF);
1002 return new DeviceStateVersion(vender, product, version);
1006 DeviceStateInfo* parseDeviceStateInfoMessage(char* payloadData) {
1009 int64_t downTime = 0;
1010 for (int i = 0; i < 8; i++) {
1011 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
1012 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
1013 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
1016 return new DeviceStateInfo(time, upTime, downTime);
1020 DeviceStateLocation* parseDeviceStateLocationMessage(char* payloadData) {
1022 for (int i = 0; i < 16; i++) {
1023 location[i] = payloadData[i];
1026 char labelBytes[32];
1027 for (int i = 0; i < 32; i++) {
1028 labelBytes[i] = payloadData[i + 16];
1031 int64_t updatedAt = 0;
1032 for (int i = 0; i < 8; i++) {
1033 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1036 string str(labelBytes);
1037 return new DeviceStateLocation(location, str, updatedAt);
1041 DeviceStateGroup* parseDeviceStateGroupMessage(char* payloadData) {
1043 for (int i = 0; i < 16; i++) {
1044 group[i] = payloadData[i];
1047 char labelBytes[32];
1048 for (int i = 0; i < 32; i++) {
1049 labelBytes[i] = payloadData[i + 16];
1052 int64_t updatedAt = 0;
1053 for (int i = 0; i < 8; i++) {
1054 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1057 string str(labelBytes);
1058 return new DeviceStateGroup(group, str, updatedAt);
1064 LightState* parseLightStateMessage(char* payloadData) {
1067 for (int i = 0; i < 8; i++) {
1068 colorData[i] = payloadData[i];
1070 BulbColor color(colorData);
1072 int power = ((payloadData[11] & 0xFF) << 8);
1073 power |= (payloadData[10] & 0xFF);
1075 string label(payloadData);
1077 char labelArray[32];
1078 for (int i = 0; i < 32; i++) {
1079 labelArray[i] = payloadData[12 + i];
1082 return new LightState(&color, power, label);
1086 int parseLightStatePowerMessage(char* payloadData) {
1087 int level = ((payloadData[1] & 0xFF) << 8);
1088 level |= (payloadData[0] & 0xFF);
1094 void handleStateVersionMessageReceived(char* payloadData) {
1096 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1097 int productNumber = (int)deviceState->getProduct();
1099 bool isColor = false;
1101 if (productNumber == 1) {// Original 1000
1103 } else if (productNumber == 3) {//Color 650
1105 } else if (productNumber == 10) {// White 800 (Low Voltage)
1107 } else if (productNumber == 11) {// White 800 (High Voltage)
1109 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1111 } else if (productNumber == 20) {// Color 1000 BR30
1113 } else if (productNumber == 22) {// Color 1000
1119 hueUpperBound = 65535;
1120 saturationLowerBound = 0;
1121 saturationUpperBound = 65535;
1122 brightnessLowerBound = 0;
1123 brightnessUpperBound = 65535;
1124 temperatureLowerBound = 2500;
1125 temperatureUpperBound = 9000;
1129 saturationLowerBound = 0;
1130 saturationUpperBound = 0;
1131 brightnessLowerBound = 0;
1132 brightnessUpperBound = 65535;// still can dim bulb
1133 temperatureLowerBound = 2500;
1134 temperatureUpperBound = 9000;
1137 didGetBulbVersion.exchange(true);
1138 // Avoid memory leak - delete this object
1143 void handleLightStateMessageReceived(char* payloadData) {
1144 LightState* lightState = parseLightStateMessage(payloadData);
1146 BulbColor* color = lightState->getColor();
1147 int power = lightState->getPower();
1149 bool bulbWrongColor = false;
1150 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1151 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1152 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1153 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1156 // gets set to true if any of the below if statements are taken
1157 stateDidChange = false;
1159 if (bulbWrongColor) {
1160 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1161 sendSetLightColorPacket(newColor, 250);
1162 // System.out.println("Failed Check 1");
1165 bulbStateMutex.lock();
1166 bool bulbIsOnTmp = bulbIsOn;
1167 bulbStateMutex.unlock();
1169 if ((!bulbIsOnTmp) && (power != 0)) {
1171 // System.out.println("Failed Check 2: " + Integer.toString(power));
1175 if (bulbIsOnTmp && (power < 65530)) {
1177 // System.out.println("Failed Check 3: " + Integer.toString(power));
1180 // Avoid memory leak - delete object