7 #include "LifxLightBulb.hpp"
9 #include "IoTDeviceAddress.hpp"
14 // External functions to create, destroy and initialize this class object
15 extern "C" void* createLifxLightBulb(void** params) {
16 // Arguments: IoTSet<IoTDeviceAddress*>* _devAddress, string macAddress
17 return new LifxLightBulb((IoTSet<void*>*) params[0], *((string*) params[1]));
21 extern "C" void destroyLifxLightBulb(void* t) {
22 LifxLightBulb* llb = (LifxLightBulb*) t;
27 extern "C" void initLifxLightBulb(void* t) {
28 LifxLightBulb* llb = (LifxLightBulb*) t;
34 LifxLightBulb::LifxLightBulb() {
35 // LB1 macAddress: d0:73:d5:12:8e:30
36 // LB1 macAddress: d0:73:d5:02:41:da
37 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
38 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
39 /*bulbMacAddress[0] = 0xD0;
40 bulbMacAddress[1] = 0x73;
41 bulbMacAddress[2] = 0xD5;
42 bulbMacAddress[3] = 0x02;
43 bulbMacAddress[4] = 0x41;
44 bulbMacAddress[5] = 0xDA;
45 bulbMacAddress[6] = 0x00;
46 bulbMacAddress[7] = 0x00;*/
48 char tmpMacAddress[16];
49 strcpy(tmpMacAddress, macAddress.c_str());
50 for(int i=0; i<16; i=i+2) {
51 // Take 2 digits and then convert
53 tmpMacByte[0] = tmpMacAddress[i];
54 tmpMacByte[1] = tmpMacAddress[i+1];
55 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
60 // Driver constructor always gets a pointer to device address, trailed by class arguments of generic type
61 LifxLightBulb::LifxLightBulb(IoTSet<void*>* _devAddress, string macAddress) {
63 // Initialize macAddress
64 char tmpMacAddress[16];
65 strcpy(tmpMacAddress, macAddress.c_str());
66 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
67 for(int i=0; i<16; i=i+2) {
68 // Take 2 digits and then convert
70 tmpMacByte[0] = tmpMacAddress[i];
71 tmpMacByte[1] = tmpMacAddress[i+1];
72 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
74 //cout << "MAC address is set. Value: ";
76 // Initialize device address
77 lb_addresses = _devAddress;
78 //cout << "Device address is set! " << endl;
82 LifxLightBulb::~LifxLightBulb() {
85 if (communicationSocket != NULL) {
87 delete communicationSocket;
88 communicationSocket = NULL;
90 for(void* dev : *lb_addresses) {
91 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
95 if (lb_addresses != NULL) {
104 // Initialize the lightbulb
105 void LifxLightBulb::init() {
107 if (didAlreadyInit.exchange(true))
110 unordered_set<void*>::const_iterator itr = lb_addresses->begin();
111 IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
112 //cout << "Address: " << deviceAddress->getAddress() << endl;
114 // Create IoTUDP socket
115 communicationSocket = new IoTUDP(deviceAddress);
117 //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
118 //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
119 //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
121 // Launch the worker function in a separate thread.
122 // NOTE: "this" pointer is passed into the detached thread because it does not belong
123 // to this object anymore so if it executes certain methods of "this" object, then it needs
124 // the correct references to stuff
125 thread th1 (&LifxLightBulb::workerFunction, this, this);
128 //cout << "Initialized LifxLightBulb!" << endl;
132 void LifxLightBulb::turnOff() {
134 //lock_guard<mutex> guard(bulbStateMutex);
135 bulbStateMutex.lock();
137 sendSetLightPowerPacket(0, 0);
138 stateDidChange = true;
139 bulbStateMutex.unlock();
143 void LifxLightBulb::turnOn() {
145 //lock_guard<mutex> guard(bulbStateMutex);
146 bulbStateMutex.lock();
148 sendSetLightPowerPacket(65535, 0);
149 stateDidChange = true;
150 bulbStateMutex.unlock();
154 double LifxLightBulb::getHue() {
156 settingBulbColorMutex.lock();
157 tmp = ((double)currentHue / 65535.0) * 360.0;
158 settingBulbColorMutex.unlock();
164 double LifxLightBulb::getSaturation() {
166 settingBulbColorMutex.lock();
167 tmp = ((double)currentSaturation / 65535.0) * 360.0;
168 settingBulbColorMutex.unlock();
174 double LifxLightBulb::getBrightness() {
176 settingBulbColorMutex.lock();
177 tmp = ((double)currentBrightness / 65535.0) * 360.0;
178 settingBulbColorMutex.unlock();
184 int LifxLightBulb::getTemperature() {
187 settingBulbTemperatureMutex.lock();
188 tmp = currentTemperature;
189 settingBulbTemperatureMutex.unlock();
195 double LifxLightBulb::getHueRangeLowerBound() {
196 if (!didGetBulbVersion) {
199 return ((double)hueLowerBound / 65535.0) * 360.0;
203 double LifxLightBulb::getHueRangeUpperBound() {
204 if (!didGetBulbVersion) {
207 return ((double)hueUpperBound / 65535.0) * 360.0;
211 double LifxLightBulb::getSaturationRangeLowerBound() {
212 if (!didGetBulbVersion) {
215 return ((double)saturationLowerBound / 65535.0) * 100.0;
219 double LifxLightBulb::getSaturationRangeUpperBound() {
220 if (!didGetBulbVersion) {
223 return ((double)saturationUpperBound / 65535.0) * 100.0;
227 double LifxLightBulb::getBrightnessRangeLowerBound() {
228 if (!didGetBulbVersion) {
231 return ((double)brightnessLowerBound / 65535.0) * 100.0;
235 double LifxLightBulb::getBrightnessRangeUpperBound() {
236 if (!didGetBulbVersion) {
239 return ((double)brightnessUpperBound / 65535.0) * 100.0;
243 int LifxLightBulb::getTemperatureRangeLowerBound() {
244 if (!didGetBulbVersion) {
247 return temperatureLowerBound;
251 int LifxLightBulb::getTemperatureRangeUpperBound() {
252 if (!didGetBulbVersion) {
255 return temperatureUpperBound;
259 void LifxLightBulb::setTemperature(int _temperature) {
261 settingBulbTemperatureMutex.lock();
263 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
264 sendSetLightColorPacket(newColor, 250);
266 currentTemperature = _temperature;
267 stateDidChange = true;
269 settingBulbTemperatureMutex.unlock();
273 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
275 settingBulbColorMutex.lock();
278 _saturation /= 100.0;
279 _brightness /= 100.0;
282 int newHue = (int)(_hue * 65535.0);
283 int newSaturation = (int)(_saturation * 65535.0);
284 int newBrightness = (int)(_brightness * 65535.0);
286 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
287 sendSetLightColorPacket(newColor, 250);
290 currentSaturation = newSaturation;
291 currentBrightness = newBrightness;
292 stateDidChange = true;
294 settingBulbColorMutex.unlock();
298 bool LifxLightBulb::getState() {
302 bulbStateMutex.lock();
304 bulbStateMutex.unlock();
311 // Communication helpers
312 void LifxLightBulb::receivedPacket(char* packetData) {
314 char headerBytes[36];
315 for (int i = 0; i < 36; i++) {
316 headerBytes[i] = packetData[i];
319 LifxHeader recHeader;
320 recHeader.setFromBytes(headerBytes);
322 // load the payload bytes (strip away the header)
323 char* payloadBytes = new char[recHeader.getSize()];
324 for (int i = 36; i < recHeader.getSize(); i++) {
325 payloadBytes[i - 36] = packetData[i];
328 int type = recHeader.getType();
329 //cout << "Received: " << type << endl;
331 DeviceStateService* dat = NULL;
335 dat = parseDeviceStateServiceMessage(payloadBytes);
336 //cout << "Service: " << dat->getService();
337 //cout << "Port : " << dat->getPort();
338 // Avoid memory leak - delete this object
343 handleStateVersionMessageReceived(payloadBytes);
347 parseDeviceStateInfoMessage(payloadBytes);
352 handleLightStateMessageReceived(payloadBytes);
357 //cout << "unknown packet Type" << endl;
359 // Avoid memory leaks
364 void LifxLightBulb::sendPacket(char* packetData, int len) {
365 //cout << "sendPacket: About to send" << endl;
366 lock_guard<mutex> guard(socketMutex);
367 sendSocketFlag = true;
368 communicationSocket->sendData(packetData, len);
369 sendSocketFlag = false;
373 // Worker function which runs the while loop for receiving data from the bulb.
375 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
377 // Need timeout on receives since we are not sure if a packet will be available
378 // for processing so don't block waiting
379 llb->communicationSocket->setTimeOut(50000); // In milliseconds
382 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
386 // Check if we got the bulb version yet
387 // could have requested it but message could have gotten lost (UDP)
388 if (!llb->didGetBulbVersion) {
389 int64_t currentTime = (int64_t) time(NULL);
390 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
391 // Get the bulb version so we know what type of bulb this is.
392 //cout << "Sending version packet! " << endl;
393 llb->sendGetVersionPacket();
394 lastSentGetBulbVersionRequest = currentTime;
398 // Communication resource is busy so try again later
399 if (llb->sendSocketFlag) {
403 llb->socketMutex.lock();
404 int ret = llb->communicationSocket->receiveData(dat, 1024);
405 // Never forget to release!
406 llb->socketMutex.unlock();
410 llb->receivedPacket(dat);
413 // If a state change occurred then request the bulb state to ensure that the
414 // bulb did indeed change its state to the correct state
415 if (llb->stateDidChange) {
416 llb->sendGetLightStatePacket();
419 // Wait a bit as to not tie up system resources
420 this_thread::sleep_for (chrono::milliseconds(100));
421 //cout << endl << "Sleep and wake up!" << endl;
428 void LifxLightBulb::sendGetServicePacket() {
431 header.setTagged(true);
432 header.setMacAddress(bulbMacAddress);
433 header.setSource(0); // randomly picked
434 header.setAck_required(false);
435 header.setRes_required(false);
436 header.setSequence(0);
440 header.getHeaderBytes(dataBytes);
442 sendPacket(dataBytes, 36);
446 void LifxLightBulb::sendGetHostInfoPacket() {
449 header.setTagged(false);
450 header.setMacAddress(bulbMacAddress);
451 header.setSource(10); // randomly picked
452 header.setAck_required(false);
453 header.setRes_required(false);
454 header.setSequence(0);
458 header.getHeaderBytes(dataBytes);
460 sendPacket(dataBytes, 36);
464 void LifxLightBulb::sendGetHostFirmwarePacket() {
467 header.setTagged(false);
468 header.setMacAddress(bulbMacAddress);
469 header.setSource(10); // randomly picked
470 header.setAck_required(false);
471 header.setRes_required(false);
472 header.setSequence(0);
476 header.getHeaderBytes(dataBytes);
478 sendPacket(dataBytes, 36);
482 void LifxLightBulb::sendGetWifiInfoPacket() {
485 header.setTagged(false);
486 header.setMacAddress(bulbMacAddress);
487 header.setSource(10); // randomly picked
488 header.setAck_required(false);
489 header.setRes_required(false);
490 header.setSequence(0);
494 header.getHeaderBytes(dataBytes);
496 sendPacket(dataBytes, 36);
500 void LifxLightBulb::sendGetWifiFirmwarePacket() {
503 header.setTagged(false);
504 header.setMacAddress(bulbMacAddress);
505 header.setSource(10); // randomly picked
506 header.setAck_required(false);
507 header.setRes_required(false);
508 header.setSequence(0);
512 header.getHeaderBytes(dataBytes);
514 sendPacket(dataBytes, 36);
518 void LifxLightBulb::sendGetPowerPacket() {
521 header.setTagged(false);
522 header.setMacAddress(bulbMacAddress);
523 header.setSource(10); // randomly picked
524 header.setAck_required(false);
525 header.setRes_required(false);
526 header.setSequence(0);
530 header.getHeaderBytes(dataBytes);
532 sendPacket(dataBytes, 36);
536 void LifxLightBulb::sendSetPowerPacket(int level) {
537 // Currently only 0 and 65535 are supported
538 // This is a fix for now
539 if ((level != 65535) && (level != 0)) {
540 cerr << "Invalid parameter values" << endl;
544 if ((level > 65535) || (level < 0)) {
545 cerr << "Invalid parameter values" << endl;
549 char packetBytes[38];
553 header.setTagged(false);
554 header.setMacAddress(bulbMacAddress);
555 header.setSource(10); // randomly picked
556 header.setAck_required(false);
557 header.setRes_required(false);
558 header.setSequence(0);
560 char headerBytes[36];
561 header.getHeaderBytes(headerBytes);
563 for (int i = 0; i < 36; i++) {
564 packetBytes[i] = headerBytes[i];
567 packetBytes[36] = (char)(level & 0xFF);
568 packetBytes[37] = (char)((level >> 8) & 0xFF);
570 sendPacket(packetBytes, 38);
574 void LifxLightBulb::sendGetLabelPacket() {
577 header.setTagged(false);
578 header.setMacAddress(bulbMacAddress);
579 header.setSource(10); // randomly picked
580 header.setAck_required(false);
581 header.setRes_required(false);
582 header.setSequence(0);
586 header.getHeaderBytes(dataBytes);
588 sendPacket(dataBytes, 36);
592 void LifxLightBulb::sendSetLabelPacket(string label) {
593 // Currently only 0 and 65535 are supported
594 // This is a fix for now
595 if (label.length() != 32) {
596 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
600 char packetBytes[68];
604 header.setTagged(false);
605 header.setMacAddress(bulbMacAddress);
606 header.setSource(10); // randomly picked
607 header.setAck_required(false);
608 header.setRes_required(false);
609 header.setSequence(0);
611 char headerBytes[36];
612 header.getHeaderBytes(headerBytes);
614 for (int i = 0; i < 36; i++) {
615 packetBytes[i] = headerBytes[i];
618 for (int i = 0; i < 32; i++) {
619 packetBytes[i + 36] = label.c_str()[i];
622 sendPacket(packetBytes, 68);
626 void LifxLightBulb::sendGetVersionPacket() {
629 header.setTagged(false);
630 header.setMacAddress(bulbMacAddress);
631 header.setSource(10); // randomly picked
632 header.setAck_required(false);
633 header.setRes_required(false);
634 header.setSequence(0);
638 header.getHeaderBytes(dataBytes);
640 sendPacket(dataBytes, 36);
644 void LifxLightBulb::sendGetInfoPacket() {
647 header.setTagged(false);
648 header.setMacAddress(bulbMacAddress);
649 header.setSource(10); // randomly picked
650 header.setAck_required(false);
651 header.setRes_required(false);
652 header.setSequence(0);
656 header.getHeaderBytes(dataBytes);
658 sendPacket(dataBytes, 36);
662 void LifxLightBulb::sendGetLocationPacket() {
665 header.setTagged(false);
666 header.setMacAddress(bulbMacAddress);
667 header.setSource(10); // randomly picked
668 header.setAck_required(false);
669 header.setRes_required(false);
670 header.setSequence(0);
674 header.getHeaderBytes(dataBytes);
676 sendPacket(dataBytes, 36);
680 void LifxLightBulb::sendGetGroupPacket() {
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);
692 header.getHeaderBytes(dataBytes);
694 sendPacket(dataBytes, 36);
700 void LifxLightBulb::sendGetLightStatePacket() {
703 header.setTagged(false);
704 header.setMacAddress(bulbMacAddress);
705 header.setSource(10); // randomly picked
706 header.setAck_required(false);
707 header.setRes_required(false);
708 header.setSequence(0);
712 header.getHeaderBytes(dataBytes);
714 sendPacket(dataBytes, 36);
718 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
720 if ((duration > 4294967295l) || (duration < 0)) {
721 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
725 char packetBytes[49];
729 header.setTagged(false);
730 header.setMacAddress(bulbMacAddress);
731 header.setSource(10); // randomly picked
732 header.setAck_required(false);
733 header.setRes_required(false);
734 header.setSequence(0);
736 char headerBytes[36];
737 header.getHeaderBytes(headerBytes);
739 for (int i = 0; i < 36; i++) {
740 packetBytes[i] = headerBytes[i];
744 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
745 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
747 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
748 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
750 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
751 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
753 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
754 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
756 packetBytes[45] = (char)((duration >> 0) & 0xFF);
757 packetBytes[46] = (char)((duration >> 8) & 0xFF);
758 packetBytes[47] = (char)((duration >> 16) & 0xFF);
759 packetBytes[48] = (char)((duration >> 24) & 0xFF);
761 sendPacket(packetBytes, 49);
762 // Avoid memory leak - delete object
767 void LifxLightBulb::sendGetLightPowerPacket() {
770 header.setTagged(false);
771 header.setMacAddress(bulbMacAddress);
772 header.setSource(10); // randomly picked
773 header.setAck_required(false);
774 header.setRes_required(false);
775 header.setSequence(0);
779 header.getHeaderBytes(dataBytes);
781 sendPacket(dataBytes, 36);
785 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
787 if ((level > 65535) || (duration > 4294967295l)
788 || (level < 0) || (duration < 0)) {
789 cerr << "Invalid parameter values" << endl;
792 char packetBytes[42];
796 header.setTagged(false);
797 header.setMacAddress(bulbMacAddress);
798 header.setSource(10); // randomly picked
799 header.setAck_required(false);
800 header.setRes_required(false);
801 header.setSequence(0);
803 char headerBytes[36];
804 header.getHeaderBytes(headerBytes);
806 for (int i = 0; i < 36; i++) {
807 packetBytes[i] = headerBytes[i];
810 packetBytes[36] = (char)(level & 0xFF);
811 packetBytes[37] = (char)((level >> 8) & 0xFF);
813 packetBytes[38] = (char)((duration >> 0) & 0xFF);
814 packetBytes[39] = (char)((duration >> 8) & 0xFF);
815 packetBytes[40] = (char)((duration >> 16) & 0xFF);
816 packetBytes[41] = (char)((duration >> 24) & 0xFF);
818 sendPacket(packetBytes, 42);
822 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
824 char packetBytes[100];
828 header.setTagged(false);
829 header.setMacAddress(bulbMacAddress);
830 header.setSource(10); // randomly picked
831 header.setAck_required(false);
832 header.setRes_required(false);
833 header.setSequence(0);
835 char headerBytes[36];
836 header.getHeaderBytes(headerBytes);
838 for (int i = 0; i < 36; i++) {
839 packetBytes[i] = headerBytes[i];
842 for (int i = 0; i < 64; i++) {
843 packetBytes[i + 36] = data[i];
846 sendPacket(packetBytes, 100);
852 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
853 int service = payloadData[0];
854 int64_t port = ((payloadData[3] & 0xFF) << 24);
855 port |= ((payloadData[2] & 0xFF) << 16);
856 port |= ((payloadData[1] & 0xFF) << 8);
857 port |= (payloadData[0] & 0xFF);
859 return new DeviceStateService(service, port);
863 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
864 long signal = ((payloadData[3] & 0xFF) << 24);
865 signal |= ((payloadData[2] & 0xFF) << 16);
866 signal |= ((payloadData[1] & 0xFF) << 8);
867 signal |= (payloadData[0] & 0xFF);
869 long tx = ((payloadData[7] & 0xFF) << 24);
870 tx |= ((payloadData[6] & 0xFF) << 16);
871 tx |= ((payloadData[5] & 0xFF) << 8);
872 tx |= (payloadData[4] & 0xFF);
874 long rx = ((payloadData[11] & 0xFF) << 24);
875 rx |= ((payloadData[10] & 0xFF) << 16);
876 rx |= ((payloadData[9] & 0xFF) << 8);
877 rx |= (payloadData[8] & 0xFF);
879 return new DeviceStateHostInfo(signal, tx, rx);
883 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
885 for (int i = 0; i < 8; i++) {
886 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
891 int64_t version = ((payloadData[19] & 0xFF) << 24);
892 version |= ((payloadData[18] & 0xFF) << 16);
893 version |= ((payloadData[17] & 0xFF) << 8);
894 version |= (payloadData[16] & 0xFF);
896 return new DeviceStateHostFirmware(build, version);
900 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
901 int64_t signal = ((payloadData[3] & 0xFF) << 24);
902 signal |= ((payloadData[2] & 0xFF) << 16);
903 signal |= ((payloadData[1] & 0xFF) << 8);
904 signal |= (payloadData[0] & 0xFF);
906 int64_t tx = ((payloadData[7] & 0xFF) << 24);
907 tx |= ((payloadData[6] & 0xFF) << 16);
908 tx |= ((payloadData[5] & 0xFF) << 8);
909 tx |= (payloadData[4] & 0xFF);
911 int64_t rx = ((payloadData[11] & 0xFF) << 24);
912 rx |= ((payloadData[10] & 0xFF) << 16);
913 rx |= ((payloadData[9] & 0xFF) << 8);
914 rx |= (payloadData[8] & 0xFF);
916 return new DeviceStateWifiInfo(signal, tx, rx);
920 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
922 for (int i = 0; i < 8; i++) {
923 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
928 int64_t version = ((payloadData[19] & 0xFF) << 24);
929 version |= ((payloadData[18] & 0xFF) << 16);
930 version |= ((payloadData[17] & 0xFF) << 8);
931 version |= (payloadData[16] & 0xFF);
933 return new DeviceStateWifiFirmware(build, version);
937 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
938 int level = ((payloadData[1] & 0xFF) << 8);
939 level |= (payloadData[0] & 0xFF);
944 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
945 int64_t vender = ((payloadData[3] & 0xFF) << 24);
946 vender |= ((payloadData[2] & 0xFF) << 16);
947 vender |= ((payloadData[1] & 0xFF) << 8);
948 vender |= (payloadData[0] & 0xFF);
950 int64_t product = ((payloadData[7] & 0xFF) << 24);
951 product |= ((payloadData[6] & 0xFF) << 16);
952 product |= ((payloadData[5] & 0xFF) << 8);
953 product |= (payloadData[4] & 0xFF);
955 int64_t version = ((payloadData[11] & 0xFF) << 24);
956 version |= ((payloadData[10] & 0xFF) << 16);
957 version |= ((payloadData[9] & 0xFF) << 8);
958 version |= (payloadData[8] & 0xFF);
960 return new DeviceStateVersion(vender, product, version);
964 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
967 int64_t downTime = 0;
968 for (int i = 0; i < 8; i++) {
969 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
970 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
971 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
974 return new DeviceStateInfo(time, upTime, downTime);
978 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
980 for (int i = 0; i < 16; i++) {
981 location[i] = payloadData[i];
985 for (int i = 0; i < 32; i++) {
986 labelBytes[i] = payloadData[i + 16];
989 int64_t updatedAt = 0;
990 for (int i = 0; i < 8; i++) {
991 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
994 string str(labelBytes);
995 return new DeviceStateLocation(location, str, updatedAt);
999 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1001 for (int i = 0; i < 16; i++) {
1002 group[i] = payloadData[i];
1005 char labelBytes[32];
1006 for (int i = 0; i < 32; i++) {
1007 labelBytes[i] = payloadData[i + 16];
1010 int64_t updatedAt = 0;
1011 for (int i = 0; i < 8; i++) {
1012 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1015 string str(labelBytes);
1016 return new DeviceStateGroup(group, str, updatedAt);
1022 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1025 for (int i = 0; i < 8; i++) {
1026 colorData[i] = payloadData[i];
1028 //BulbColor color(colorData);
1029 BulbColor* color = new BulbColor(colorData);
1031 int power = ((payloadData[11] & 0xFF) << 8);
1032 power |= (payloadData[10] & 0xFF);
1034 string label(payloadData);
1036 char labelArray[32];
1037 for (int i = 0; i < 32; i++) {
1038 labelArray[i] = payloadData[12 + i];
1041 return new LightState(color, power, label);
1045 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1046 int level = ((payloadData[1] & 0xFF) << 8);
1047 level |= (payloadData[0] & 0xFF);
1053 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1055 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1056 int productNumber = (int)deviceState->getProduct();
1058 bool isColor = false;
1060 if (productNumber == 1) {// Original 1000
1062 } else if (productNumber == 3) {//Color 650
1064 } else if (productNumber == 10) {// White 800 (Low Voltage)
1066 } else if (productNumber == 11) {// White 800 (High Voltage)
1068 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1070 } else if (productNumber == 20) {// Color 1000 BR30
1072 } else if (productNumber == 22) {// Color 1000
1078 hueUpperBound = 65535;
1079 saturationLowerBound = 0;
1080 saturationUpperBound = 65535;
1081 brightnessLowerBound = 0;
1082 brightnessUpperBound = 65535;
1083 temperatureLowerBound = 2500;
1084 temperatureUpperBound = 9000;
1088 saturationLowerBound = 0;
1089 saturationUpperBound = 0;
1090 brightnessLowerBound = 0;
1091 brightnessUpperBound = 65535;// still can dim bulb
1092 temperatureLowerBound = 2500;
1093 temperatureUpperBound = 9000;
1096 didGetBulbVersion.exchange(true);
1097 // Avoid memory leak - delete this object
1102 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1103 LightState* lightState = parseLightStateMessage(payloadData);
1105 BulbColor* color = lightState->getColor();
1106 int power = lightState->getPower();
1108 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1109 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1110 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1111 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1113 bool bulbWrongColor = false;
1114 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1115 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1116 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1117 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1120 // gets set to true if any of the below if statements are taken
1121 stateDidChange = false;
1123 if (bulbWrongColor) {
1124 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1125 sendSetLightColorPacket(newColor, 250);
1126 //cout << "Failed Check 1" << endl;
1129 bulbStateMutex.lock();
1130 bool bulbIsOnTmp = bulbIsOn;
1131 bulbStateMutex.unlock();
1133 if ((!bulbIsOnTmp) && (power != 0)) {
1135 //cout << "Failed Check 2: " << endl;
1139 if (bulbIsOnTmp && (power < 65530)) {
1141 //cout << "Failed Check 3: " << endl;
1144 // Avoid memory leak - delete object