1 #ifndef _LIFXLIGHTBULB_HPP__
2 #define _LIFXLIGHTBULB_HPP__
14 #include "LightBulb.hpp"
16 #include "IoTRMIUtil.hpp"
19 #include "IoTDeviceAddress.hpp"
20 #include "Iterator.hpp"
22 // Helper classes for LifxLightBulb
23 #include "LifxHeader.hpp"
24 #include "BulbColor.hpp"
25 #include "DeviceStateGroup.hpp"
26 #include "DeviceStateHostFirmware.hpp"
27 #include "DeviceStateHostInfo.hpp"
28 #include "DeviceStateInfo.hpp"
29 #include "DeviceStateLocation.hpp"
30 #include "DeviceStateService.hpp"
31 #include "DeviceStateVersion.hpp"
32 #include "DeviceStateWifiFirmware.hpp"
33 #include "DeviceStateWifiInfo.hpp"
34 #include "LightState.hpp"
39 // Driver LifxLightBulb
40 // Implemented based on LightBulb virtual class (interface)
43 std::atomic<bool> didAlreadyInit(false);
44 std::atomic<bool> didGetBulbVersion(false);
46 class LifxLightBulb //: public LightBulb
50 const static int64_t GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
53 IoTUDP *communicationSocket;
54 char bulbMacAddress[8];
56 //static Semaphore socketMutex = new Semaphore(1);
57 bool sendSocketFlag = false;
59 // Current Bulb Values
61 int currentSaturation = 0;
62 int currentBrightness = 65535;
63 int currentTemperature = 9000;
64 bool bulbIsOn = false;
67 atomic<bool> didAlreadyInit;
68 atomic<bool> didGetBulbVersion;
72 mutex settingBulbColorMutex;
73 mutex settingBulbTemperatureMutex;
76 // color and temperature ranges for the bulbs
77 int hueLowerBound = 0;
78 int hueUpperBound = 0;
79 int saturationLowerBound = 0;
80 int saturationUpperBound = 0;
81 int brightnessLowerBound = 0;
82 int brightnessUpperBound = 0;
83 int temperatureLowerBound = 2500;
84 int temperatureUpperBound = 9000;
86 // Check if a state change was requested, used to poll the bulb for if the bulb did
87 // preform the requested state change
88 bool stateDidChange = false;
91 IoTSet<IoTDeviceAddress*> lb_addresses;
97 // LB1 macAddress: d0:73:d5:12:8e:30
98 // LB1 macAddress: d0:73:d5:02:41:da
99 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
100 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
101 /*bulbMacAddress[0] = 0xD0;
102 bulbMacAddress[1] = 0x73;
103 bulbMacAddress[2] = 0xD5;
104 bulbMacAddress[3] = 0x02;
105 bulbMacAddress[4] = 0x41;
106 bulbMacAddress[5] = 0xDA;
107 bulbMacAddress[6] = 0x00;
108 bulbMacAddress[7] = 0x00;*/
110 char tmpMacAddress[16];
111 strcpy(tmpMacAddress, macAddress.c_str());
112 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
113 for(int i=0; i<16; i=i+2) {
114 // Take 2 digits and then convert
116 tmpMacByte[0] = tmpMacAddress[i];
117 tmpMacByte[1] = tmpMacAddress[i+1];
118 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
120 //IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
124 LifxLightBulb(IoTSet<IoTDeviceAddress*> _devAddress, string macAddress) {
126 // Initialize macAddress
127 char tmpMacAddress[16];
128 strcpy(tmpMacAddress, macAddress.c_str());
129 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
130 for(int i=0; i<16; i=i+2) {
131 // Take 2 digits and then convert
133 tmpMacByte[0] = tmpMacAddress[i];
134 tmpMacByte[1] = tmpMacAddress[i+1];
135 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
137 cout << "MAC address is set. Value: ";
138 IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
140 // Initialize device address
141 lb_addresses = _devAddress;
142 cout << "Device address is set! " << endl;
149 if (communicationSocket != NULL) {
151 delete communicationSocket;
152 communicationSocket = NULL;
157 // Initialize the lightbulb
160 if (didAlreadyInit.exchange(true))
163 unordered_set<IoTDeviceAddress*>::const_iterator itr = lb_addresses.begin();
164 IoTDeviceAddress* deviceAddress = *itr;
165 cout << "Address: " << deviceAddress->getAddress() << endl;
167 // Create IoTUDP socket
168 communicationSocket = new IoTUDP(deviceAddress);
170 cout << "Host address: " << communicationSocket->getHostAddress() << endl;
171 cout << "Source port: " << communicationSocket->getSourcePort() << endl;
172 cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
174 // Launch the worker function in a separate thread.
175 // NOTE: "this" pointer is passed into the detached thread because it does not belong
176 // to this object anymore so if it executes certain methods of "this" object, then it needs
177 // the correct references to stuff
178 thread th1 (&LifxLightBulb::workerFunction, this, this);
181 cout << "Initialized LifxLightBulb!" << endl;
187 //lock_guard<mutex> guard(bulbStateMutex);
188 bulbStateMutex.lock();
190 sendSetLightPowerPacket(0, 0);
191 stateDidChange = true;
192 bulbStateMutex.unlock();
198 //lock_guard<mutex> guard(bulbStateMutex);
199 bulbStateMutex.lock();
201 sendSetLightPowerPacket(65535, 0);
202 stateDidChange = true;
203 bulbStateMutex.unlock();
209 settingBulbColorMutex.lock();
210 tmp = ((double)currentHue / 65535.0) * 360.0;
211 settingBulbColorMutex.unlock();
217 double getSaturation() {
219 settingBulbColorMutex.lock();
220 tmp = ((double)currentSaturation / 65535.0) * 360.0;
221 settingBulbColorMutex.unlock();
227 double getBrightness() {
229 settingBulbColorMutex.lock();
230 tmp = ((double)currentBrightness / 65535.0) * 360.0;
231 settingBulbColorMutex.unlock();
237 int getTemperature() {
240 settingBulbTemperatureMutex.lock();
241 tmp = currentTemperature;
242 settingBulbTemperatureMutex.unlock();
248 double getHueRangeLowerBound() {
249 if (!didGetBulbVersion) {
252 return ((double)hueLowerBound / 65535.0) * 360.0;
256 double getHueRangeUpperBound() {
257 if (!didGetBulbVersion) {
260 return ((double)hueUpperBound / 65535.0) * 360.0;
264 double getSaturationRangeLowerBound() {
265 if (!didGetBulbVersion) {
268 return ((double)saturationLowerBound / 65535.0) * 100.0;
272 double getSaturationRangeUpperBound() {
273 if (!didGetBulbVersion) {
276 return ((double)saturationUpperBound / 65535.0) * 100.0;
280 double getBrightnessRangeLowerBound() {
281 if (!didGetBulbVersion) {
284 return ((double)brightnessLowerBound / 65535.0) * 100.0;
288 double getBrightnessRangeUpperBound() {
289 if (!didGetBulbVersion) {
292 return ((double)brightnessUpperBound / 65535.0) * 100.0;
296 int getTemperatureRangeLowerBound() {
297 if (!didGetBulbVersion) {
300 return temperatureLowerBound;
304 int getTemperatureRangeUpperBound() {
305 if (!didGetBulbVersion) {
308 return temperatureUpperBound;
312 void setTemperature(int _temperature) {
314 settingBulbTemperatureMutex.lock();
316 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
317 sendSetLightColorPacket(newColor, 250);
319 currentTemperature = _temperature;
320 stateDidChange = true;
322 settingBulbTemperatureMutex.unlock();
326 void setColor(double _hue, double _saturation, double _brightness) {
328 settingBulbColorMutex.lock();
331 _saturation /= 100.0;
332 _brightness /= 100.0;
335 int newHue = (int)(_hue * 65535.0);
336 int newSaturation = (int)(_saturation * 65535.0);
337 int newBrightness = (int)(_brightness * 65535.0);
339 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
340 sendSetLightColorPacket(newColor, 250);
343 currentSaturation = newSaturation;
344 currentBrightness = newBrightness;
345 stateDidChange = true;
347 settingBulbColorMutex.unlock();
355 bulbStateMutex.lock();
357 bulbStateMutex.unlock();
365 // Communication helpers
366 void receivedPacket(char* packetData) {
368 char headerBytes[36];
369 for (int i = 0; i < 36; i++) {
370 headerBytes[i] = packetData[i];
373 LifxHeader recHeader;
374 recHeader.setFromBytes(headerBytes);
376 // load the payload bytes (strip away the header)
377 //char payloadBytes[recHeader.getSize()];
378 char* payloadBytes = new char[recHeader.getSize()];
379 for (int i = 36; i < recHeader.getSize(); i++) {
380 payloadBytes[i - 36] = packetData[i];
383 int type = recHeader.getType();
384 cout << "Received: " << type << endl;
386 DeviceStateService* dat = NULL;
390 dat = parseDeviceStateServiceMessage(payloadBytes);
391 cout << "Service: " << dat->getService();
392 cout << "Port : " << dat->getPort();
393 // Avoid memory leak - delete this object
398 handleStateVersionMessageReceived(payloadBytes);
402 parseDeviceStateInfoMessage(payloadBytes);
407 handleLightStateMessageReceived(payloadBytes);
411 cout << "unknown packet Type" << endl;
413 // Avoid memory leaks
418 void sendPacket(char* packetData, int len) {
419 //cout << "sendPacket: About to send" << endl;
420 lock_guard<mutex> guard(socketMutex);
421 sendSocketFlag = true;
422 communicationSocket->sendData(packetData, len);
423 sendSocketFlag = false;
427 // Worker function which runs the while loop for receiving data from the bulb.
429 void workerFunction(LifxLightBulb* llb) {
431 // Need timeout on receives since we are not sure if a packet will be available
432 // for processing so don't block waiting
433 llb->communicationSocket->setTimeOut(50000); // In milliseconds
437 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
441 // Check if we got the bulb version yet
442 // could have requested it but message could have gotten lost (UDP)
443 if (!llb->didGetBulbVersion) {
444 int64_t currentTime = (int64_t) time(NULL);
445 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
446 // Get the bulb version so we know what type of bulb this is.
447 cout << "Sending version packet! " << endl;
448 llb->sendGetVersionPacket();
449 lastSentGetBulbVersionRequest = currentTime;
453 // Communication resource is busy so try again later
454 if (llb->sendSocketFlag) {
458 llb->socketMutex.lock();
459 int ret = llb->communicationSocket->receiveData(dat, 1024);
460 // Never forget to release!
461 llb->socketMutex.unlock();
465 llb->receivedPacket(dat);
468 // If a state change occurred then request the bulb state to ensure that the
469 // bulb did indeed change its state to the correct state
470 if (llb->stateDidChange) {
471 llb->sendGetLightStatePacket();
474 // Wait a bit as to not tie up system resources
475 this_thread::sleep_for (chrono::milliseconds(100));
476 //cout << endl << "Sleep and wake up!" << endl;
483 void sendGetServicePacket() {
486 header.setTagged(true);
487 header.setMacAddress(bulbMacAddress);
488 header.setSource(0); // randomly picked
489 header.setAck_required(false);
490 header.setRes_required(false);
491 header.setSequence(0);
495 header.getHeaderBytes(dataBytes);
497 sendPacket(dataBytes, 36);
501 void sendGetHostInfoPacket() {
504 header.setTagged(false);
505 header.setMacAddress(bulbMacAddress);
506 header.setSource(10); // randomly picked
507 header.setAck_required(false);
508 header.setRes_required(false);
509 header.setSequence(0);
513 header.getHeaderBytes(dataBytes);
515 sendPacket(dataBytes, 36);
519 void sendGetHostFirmwarePacket() {
522 header.setTagged(false);
523 header.setMacAddress(bulbMacAddress);
524 header.setSource(10); // randomly picked
525 header.setAck_required(false);
526 header.setRes_required(false);
527 header.setSequence(0);
531 header.getHeaderBytes(dataBytes);
533 sendPacket(dataBytes, 36);
537 void sendGetWifiInfoPacket() {
540 header.setTagged(false);
541 header.setMacAddress(bulbMacAddress);
542 header.setSource(10); // randomly picked
543 header.setAck_required(false);
544 header.setRes_required(false);
545 header.setSequence(0);
549 header.getHeaderBytes(dataBytes);
551 sendPacket(dataBytes, 36);
555 void sendGetWifiFirmwarePacket() {
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);
567 header.getHeaderBytes(dataBytes);
569 sendPacket(dataBytes, 36);
573 void sendGetPowerPacket() {
576 header.setTagged(false);
577 header.setMacAddress(bulbMacAddress);
578 header.setSource(10); // randomly picked
579 header.setAck_required(false);
580 header.setRes_required(false);
581 header.setSequence(0);
585 header.getHeaderBytes(dataBytes);
587 sendPacket(dataBytes, 36);
591 void sendSetPowerPacket(int level) {
592 // Currently only 0 and 65535 are supported
593 // This is a fix for now
594 if ((level != 65535) && (level != 0)) {
595 cerr << "Invalid parameter values" << endl;
599 if ((level > 65535) || (level < 0)) {
600 cerr << "Invalid parameter values" << endl;
604 char packetBytes[38];
608 header.setTagged(false);
609 header.setMacAddress(bulbMacAddress);
610 header.setSource(10); // randomly picked
611 header.setAck_required(false);
612 header.setRes_required(false);
613 header.setSequence(0);
615 char headerBytes[36];
616 header.getHeaderBytes(headerBytes);
618 for (int i = 0; i < 36; i++) {
619 packetBytes[i] = headerBytes[i];
622 packetBytes[36] = (char)(level & 0xFF);
623 packetBytes[37] = (char)((level >> 8) & 0xFF);
625 sendPacket(packetBytes, 38);
629 void sendGetLabelPacket() {
632 header.setTagged(false);
633 header.setMacAddress(bulbMacAddress);
634 header.setSource(10); // randomly picked
635 header.setAck_required(false);
636 header.setRes_required(false);
637 header.setSequence(0);
641 header.getHeaderBytes(dataBytes);
643 sendPacket(dataBytes, 36);
647 void sendSetLabelPacket(string label) {
648 // Currently only 0 and 65535 are supported
649 // This is a fix for now
650 if (label.length() != 32) {
651 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
655 char packetBytes[68];
659 header.setTagged(false);
660 header.setMacAddress(bulbMacAddress);
661 header.setSource(10); // randomly picked
662 header.setAck_required(false);
663 header.setRes_required(false);
664 header.setSequence(0);
666 char headerBytes[36];
667 header.getHeaderBytes(headerBytes);
669 for (int i = 0; i < 36; i++) {
670 packetBytes[i] = headerBytes[i];
673 for (int i = 0; i < 32; i++) {
674 packetBytes[i + 36] = label.c_str()[i];
677 sendPacket(packetBytes, 68);
681 void sendGetVersionPacket() {
684 header.setTagged(false);
685 header.setMacAddress(bulbMacAddress);
686 header.setSource(10); // randomly picked
687 header.setAck_required(false);
688 header.setRes_required(false);
689 header.setSequence(0);
693 header.getHeaderBytes(dataBytes);
695 sendPacket(dataBytes, 36);
699 void sendGetInfoPacket() {
702 header.setTagged(false);
703 header.setMacAddress(bulbMacAddress);
704 header.setSource(10); // randomly picked
705 header.setAck_required(false);
706 header.setRes_required(false);
707 header.setSequence(0);
711 header.getHeaderBytes(dataBytes);
713 sendPacket(dataBytes, 36);
717 void sendGetLocationPacket() {
720 header.setTagged(false);
721 header.setMacAddress(bulbMacAddress);
722 header.setSource(10); // randomly picked
723 header.setAck_required(false);
724 header.setRes_required(false);
725 header.setSequence(0);
729 header.getHeaderBytes(dataBytes);
731 sendPacket(dataBytes, 36);
735 void sendGetGroupPacket() {
738 header.setTagged(false);
739 header.setMacAddress(bulbMacAddress);
740 header.setSource(10); // randomly picked
741 header.setAck_required(false);
742 header.setRes_required(false);
743 header.setSequence(0);
747 header.getHeaderBytes(dataBytes);
749 sendPacket(dataBytes, 36);
755 void sendGetLightStatePacket() {
758 header.setTagged(false);
759 header.setMacAddress(bulbMacAddress);
760 header.setSource(10); // randomly picked
761 header.setAck_required(false);
762 header.setRes_required(false);
763 header.setSequence(0);
767 header.getHeaderBytes(dataBytes);
769 sendPacket(dataBytes, 36);
773 void sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
775 if ((duration > 4294967295l) || (duration < 0)) {
776 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
780 char packetBytes[49];
784 header.setTagged(false);
785 header.setMacAddress(bulbMacAddress);
786 header.setSource(10); // randomly picked
787 header.setAck_required(false);
788 header.setRes_required(false);
789 header.setSequence(0);
791 char headerBytes[36];
792 header.getHeaderBytes(headerBytes);
794 for (int i = 0; i < 36; i++) {
795 packetBytes[i] = headerBytes[i];
799 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
800 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
802 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
803 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
805 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
806 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
808 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
809 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
811 packetBytes[45] = (char)((duration >> 0) & 0xFF);
812 packetBytes[46] = (char)((duration >> 8) & 0xFF);
813 packetBytes[47] = (char)((duration >> 16) & 0xFF);
814 packetBytes[48] = (char)((duration >> 24) & 0xFF);
816 sendPacket(packetBytes, 49);
817 // Avoid memory leak - delete object
822 void sendGetLightPowerPacket() {
825 header.setTagged(false);
826 header.setMacAddress(bulbMacAddress);
827 header.setSource(10); // randomly picked
828 header.setAck_required(false);
829 header.setRes_required(false);
830 header.setSequence(0);
834 header.getHeaderBytes(dataBytes);
836 sendPacket(dataBytes, 36);
840 void sendSetLightPowerPacket(int level, long duration) {
842 if ((level > 65535) || (duration > 4294967295l)
843 || (level < 0) || (duration < 0)) {
844 cerr << "Invalid parameter values" << endl;
848 char packetBytes[42];
853 header.setTagged(false);
854 header.setMacAddress(bulbMacAddress);
855 header.setSource(10); // randomly picked
856 header.setAck_required(false);
857 header.setRes_required(false);
858 header.setSequence(0);
860 char headerBytes[36];
861 header.getHeaderBytes(headerBytes);
863 for (int i = 0; i < 36; i++) {
864 packetBytes[i] = headerBytes[i];
867 packetBytes[36] = (char)(level & 0xFF);
868 packetBytes[37] = (char)((level >> 8) & 0xFF);
870 packetBytes[38] = (char)((duration >> 0) & 0xFF);
871 packetBytes[39] = (char)((duration >> 8) & 0xFF);
872 packetBytes[40] = (char)((duration >> 16) & 0xFF);
873 packetBytes[41] = (char)((duration >> 24) & 0xFF);
875 sendPacket(packetBytes, 42);
879 void sendEchoRequestPacket(char data[64]) {
881 char packetBytes[100];
885 header.setTagged(false);
886 header.setMacAddress(bulbMacAddress);
887 header.setSource(10); // randomly picked
888 header.setAck_required(false);
889 header.setRes_required(false);
890 header.setSequence(0);
892 char headerBytes[36];
893 header.getHeaderBytes(headerBytes);
895 for (int i = 0; i < 36; i++) {
896 packetBytes[i] = headerBytes[i];
899 for (int i = 0; i < 64; i++) {
900 packetBytes[i + 36] = data[i];
903 sendPacket(packetBytes, 100);
909 DeviceStateService* parseDeviceStateServiceMessage(char* payloadData) {
910 int service = payloadData[0];
911 int64_t port = ((payloadData[3] & 0xFF) << 24);
912 port |= ((payloadData[2] & 0xFF) << 16);
913 port |= ((payloadData[1] & 0xFF) << 8);
914 port |= (payloadData[0] & 0xFF);
916 return new DeviceStateService(service, port);
920 DeviceStateHostInfo* parseDeviceStateHostInfoMessage(char* payloadData) {
921 long signal = ((payloadData[3] & 0xFF) << 24);
922 signal |= ((payloadData[2] & 0xFF) << 16);
923 signal |= ((payloadData[1] & 0xFF) << 8);
924 signal |= (payloadData[0] & 0xFF);
926 long tx = ((payloadData[7] & 0xFF) << 24);
927 tx |= ((payloadData[6] & 0xFF) << 16);
928 tx |= ((payloadData[5] & 0xFF) << 8);
929 tx |= (payloadData[4] & 0xFF);
931 long rx = ((payloadData[11] & 0xFF) << 24);
932 rx |= ((payloadData[10] & 0xFF) << 16);
933 rx |= ((payloadData[9] & 0xFF) << 8);
934 rx |= (payloadData[8] & 0xFF);
936 return new DeviceStateHostInfo(signal, tx, rx);
940 DeviceStateHostFirmware* parseDeviceStateHostFirmwareMessage(char* payloadData) {
942 for (int i = 0; i < 8; i++) {
943 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
948 int64_t version = ((payloadData[19] & 0xFF) << 24);
949 version |= ((payloadData[18] & 0xFF) << 16);
950 version |= ((payloadData[17] & 0xFF) << 8);
951 version |= (payloadData[16] & 0xFF);
953 return new DeviceStateHostFirmware(build, version);
957 DeviceStateWifiInfo* parseDeviceStateWifiInfoMessage(char* payloadData) {
958 int64_t signal = ((payloadData[3] & 0xFF) << 24);
959 signal |= ((payloadData[2] & 0xFF) << 16);
960 signal |= ((payloadData[1] & 0xFF) << 8);
961 signal |= (payloadData[0] & 0xFF);
963 int64_t tx = ((payloadData[7] & 0xFF) << 24);
964 tx |= ((payloadData[6] & 0xFF) << 16);
965 tx |= ((payloadData[5] & 0xFF) << 8);
966 tx |= (payloadData[4] & 0xFF);
968 int64_t rx = ((payloadData[11] & 0xFF) << 24);
969 rx |= ((payloadData[10] & 0xFF) << 16);
970 rx |= ((payloadData[9] & 0xFF) << 8);
971 rx |= (payloadData[8] & 0xFF);
973 return new DeviceStateWifiInfo(signal, tx, rx);
977 DeviceStateWifiFirmware* parseDeviceStateWifiFirmwareMessage(char* payloadData) {
979 for (int i = 0; i < 8; i++) {
980 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
985 int64_t version = ((payloadData[19] & 0xFF) << 24);
986 version |= ((payloadData[18] & 0xFF) << 16);
987 version |= ((payloadData[17] & 0xFF) << 8);
988 version |= (payloadData[16] & 0xFF);
990 return new DeviceStateWifiFirmware(build, version);
994 int parseStatePowerMessage(char* payloadData) {
995 int level = ((payloadData[1] & 0xFF) << 8);
996 level |= (payloadData[0] & 0xFF);
1001 DeviceStateVersion* parseDeviceStateVersionMessage(char* payloadData) {
1002 int64_t vender = ((payloadData[3] & 0xFF) << 24);
1003 vender |= ((payloadData[2] & 0xFF) << 16);
1004 vender |= ((payloadData[1] & 0xFF) << 8);
1005 vender |= (payloadData[0] & 0xFF);
1007 int64_t product = ((payloadData[7] & 0xFF) << 24);
1008 product |= ((payloadData[6] & 0xFF) << 16);
1009 product |= ((payloadData[5] & 0xFF) << 8);
1010 product |= (payloadData[4] & 0xFF);
1012 int64_t version = ((payloadData[11] & 0xFF) << 24);
1013 version |= ((payloadData[10] & 0xFF) << 16);
1014 version |= ((payloadData[9] & 0xFF) << 8);
1015 version |= (payloadData[8] & 0xFF);
1017 return new DeviceStateVersion(vender, product, version);
1021 DeviceStateInfo* parseDeviceStateInfoMessage(char* payloadData) {
1024 int64_t downTime = 0;
1025 for (int i = 0; i < 8; i++) {
1026 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
1027 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
1028 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
1031 return new DeviceStateInfo(time, upTime, downTime);
1035 DeviceStateLocation* parseDeviceStateLocationMessage(char* payloadData) {
1037 for (int i = 0; i < 16; i++) {
1038 location[i] = payloadData[i];
1041 char labelBytes[32];
1042 for (int i = 0; i < 32; i++) {
1043 labelBytes[i] = payloadData[i + 16];
1046 int64_t updatedAt = 0;
1047 for (int i = 0; i < 8; i++) {
1048 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1051 string str(labelBytes);
1052 return new DeviceStateLocation(location, str, updatedAt);
1056 DeviceStateGroup* parseDeviceStateGroupMessage(char* payloadData) {
1058 for (int i = 0; i < 16; i++) {
1059 group[i] = payloadData[i];
1062 char labelBytes[32];
1063 for (int i = 0; i < 32; i++) {
1064 labelBytes[i] = payloadData[i + 16];
1067 int64_t updatedAt = 0;
1068 for (int i = 0; i < 8; i++) {
1069 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1072 string str(labelBytes);
1073 return new DeviceStateGroup(group, str, updatedAt);
1079 LightState* parseLightStateMessage(char* payloadData) {
1082 for (int i = 0; i < 8; i++) {
1083 colorData[i] = payloadData[i];
1085 //BulbColor color(colorData);
1086 BulbColor* color = new BulbColor(colorData);
1088 int power = ((payloadData[11] & 0xFF) << 8);
1089 power |= (payloadData[10] & 0xFF);
1091 string label(payloadData);
1093 char labelArray[32];
1094 for (int i = 0; i < 32; i++) {
1095 labelArray[i] = payloadData[12 + i];
1098 return new LightState(color, power, label);
1102 int parseLightStatePowerMessage(char* payloadData) {
1103 int level = ((payloadData[1] & 0xFF) << 8);
1104 level |= (payloadData[0] & 0xFF);
1110 void handleStateVersionMessageReceived(char* payloadData) {
1112 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1113 int productNumber = (int)deviceState->getProduct();
1115 bool isColor = false;
1117 if (productNumber == 1) {// Original 1000
1119 } else if (productNumber == 3) {//Color 650
1121 } else if (productNumber == 10) {// White 800 (Low Voltage)
1123 } else if (productNumber == 11) {// White 800 (High Voltage)
1125 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1127 } else if (productNumber == 20) {// Color 1000 BR30
1129 } else if (productNumber == 22) {// Color 1000
1135 hueUpperBound = 65535;
1136 saturationLowerBound = 0;
1137 saturationUpperBound = 65535;
1138 brightnessLowerBound = 0;
1139 brightnessUpperBound = 65535;
1140 temperatureLowerBound = 2500;
1141 temperatureUpperBound = 9000;
1145 saturationLowerBound = 0;
1146 saturationUpperBound = 0;
1147 brightnessLowerBound = 0;
1148 brightnessUpperBound = 65535;// still can dim bulb
1149 temperatureLowerBound = 2500;
1150 temperatureUpperBound = 9000;
1153 didGetBulbVersion.exchange(true);
1154 // Avoid memory leak - delete this object
1159 void handleLightStateMessageReceived(char* payloadData) {
1160 LightState* lightState = parseLightStateMessage(payloadData);
1162 BulbColor* color = lightState->getColor();
1163 int power = lightState->getPower();
1165 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1166 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1167 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1168 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1170 bool bulbWrongColor = false;
1171 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1172 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1173 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1174 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1177 // gets set to true if any of the below if statements are taken
1178 stateDidChange = false;
1180 if (bulbWrongColor) {
1181 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1182 sendSetLightColorPacket(newColor, 250);
1183 //cout << "Failed Check 1" << endl;
1186 bulbStateMutex.lock();
1187 bool bulbIsOnTmp = bulbIsOn;
1188 bulbStateMutex.unlock();
1190 if ((!bulbIsOnTmp) && (power != 0)) {
1192 //cout << "Failed Check 2: " << endl;
1196 if (bulbIsOnTmp && (power < 65530)) {
1198 //cout << "Failed Check 3: " << endl;
1201 // Avoid memory leak - delete object