7 #include "LifxLightBulb.hpp"
9 #include "IoTDeviceAddress.hpp"
15 LifxLightBulb::LifxLightBulb() {
16 // LB1 macAddress: d0:73:d5:12:8e:30
17 // LB1 macAddress: d0:73:d5:02:41:da
18 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
19 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
20 /*bulbMacAddress[0] = 0xD0;
21 bulbMacAddress[1] = 0x73;
22 bulbMacAddress[2] = 0xD5;
23 bulbMacAddress[3] = 0x02;
24 bulbMacAddress[4] = 0x41;
25 bulbMacAddress[5] = 0xDA;
26 bulbMacAddress[6] = 0x00;
27 bulbMacAddress[7] = 0x00;*/
29 char tmpMacAddress[16];
30 strcpy(tmpMacAddress, macAddress.c_str());
31 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
32 for(int i=0; i<16; i=i+2) {
33 // Take 2 digits and then convert
35 tmpMacByte[0] = tmpMacAddress[i];
36 tmpMacByte[1] = tmpMacAddress[i+1];
37 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
39 //IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
43 LifxLightBulb::LifxLightBulb(IoTSet<IoTDeviceAddress*>* _devAddress, string macAddress) {
45 // Initialize macAddress
46 char tmpMacAddress[16];
47 strcpy(tmpMacAddress, macAddress.c_str());
48 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
49 for(int i=0; i<16; i=i+2) {
50 // Take 2 digits and then convert
52 tmpMacByte[0] = tmpMacAddress[i];
53 tmpMacByte[1] = tmpMacAddress[i+1];
54 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
56 cout << "MAC address is set. Value: ";
57 IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
59 // Initialize device address
60 lb_addresses = _devAddress;
61 cout << "Device address is set! " << endl;
65 LifxLightBulb::~LifxLightBulb() {
68 if (communicationSocket != NULL) {
70 delete communicationSocket;
71 communicationSocket = NULL;
73 for(IoTDeviceAddress* dev : *lb_addresses) {
77 if (lb_addresses != NULL) {
86 // Initialize the lightbulb
87 void LifxLightBulb::init() {
89 if (didAlreadyInit.exchange(true))
92 unordered_set<IoTDeviceAddress*>::const_iterator itr = lb_addresses->begin();
93 IoTDeviceAddress* deviceAddress = *itr;
94 cout << "Address: " << deviceAddress->getAddress() << endl;
96 // Create IoTUDP socket
97 communicationSocket = new IoTUDP(deviceAddress);
99 cout << "Host address: " << communicationSocket->getHostAddress() << endl;
100 cout << "Source port: " << communicationSocket->getSourcePort() << endl;
101 cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
103 // Launch the worker function in a separate thread.
104 // NOTE: "this" pointer is passed into the detached thread because it does not belong
105 // to this object anymore so if it executes certain methods of "this" object, then it needs
106 // the correct references to stuff
107 thread th1 (&LifxLightBulb::workerFunction, this, this);
110 cout << "Initialized LifxLightBulb!" << endl;
114 void LifxLightBulb::turnOff() {
116 //lock_guard<mutex> guard(bulbStateMutex);
117 bulbStateMutex.lock();
119 sendSetLightPowerPacket(0, 0);
120 stateDidChange = true;
121 bulbStateMutex.unlock();
125 void LifxLightBulb::turnOn() {
127 //lock_guard<mutex> guard(bulbStateMutex);
128 bulbStateMutex.lock();
130 sendSetLightPowerPacket(65535, 0);
131 stateDidChange = true;
132 bulbStateMutex.unlock();
136 double LifxLightBulb::getHue() {
138 settingBulbColorMutex.lock();
139 tmp = ((double)currentHue / 65535.0) * 360.0;
140 settingBulbColorMutex.unlock();
146 double LifxLightBulb::getSaturation() {
148 settingBulbColorMutex.lock();
149 tmp = ((double)currentSaturation / 65535.0) * 360.0;
150 settingBulbColorMutex.unlock();
156 double LifxLightBulb::getBrightness() {
158 settingBulbColorMutex.lock();
159 tmp = ((double)currentBrightness / 65535.0) * 360.0;
160 settingBulbColorMutex.unlock();
166 int LifxLightBulb::getTemperature() {
169 settingBulbTemperatureMutex.lock();
170 tmp = currentTemperature;
171 settingBulbTemperatureMutex.unlock();
177 double LifxLightBulb::getHueRangeLowerBound() {
178 if (!didGetBulbVersion) {
181 return ((double)hueLowerBound / 65535.0) * 360.0;
185 double LifxLightBulb::getHueRangeUpperBound() {
186 if (!didGetBulbVersion) {
189 return ((double)hueUpperBound / 65535.0) * 360.0;
193 double LifxLightBulb::getSaturationRangeLowerBound() {
194 if (!didGetBulbVersion) {
197 return ((double)saturationLowerBound / 65535.0) * 100.0;
201 double LifxLightBulb::getSaturationRangeUpperBound() {
202 if (!didGetBulbVersion) {
205 return ((double)saturationUpperBound / 65535.0) * 100.0;
209 double LifxLightBulb::getBrightnessRangeLowerBound() {
210 if (!didGetBulbVersion) {
213 return ((double)brightnessLowerBound / 65535.0) * 100.0;
217 double LifxLightBulb::getBrightnessRangeUpperBound() {
218 if (!didGetBulbVersion) {
221 return ((double)brightnessUpperBound / 65535.0) * 100.0;
225 int LifxLightBulb::getTemperatureRangeLowerBound() {
226 if (!didGetBulbVersion) {
229 return temperatureLowerBound;
233 int LifxLightBulb::getTemperatureRangeUpperBound() {
234 if (!didGetBulbVersion) {
237 return temperatureUpperBound;
241 void LifxLightBulb::setTemperature(int _temperature) {
243 settingBulbTemperatureMutex.lock();
245 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
246 sendSetLightColorPacket(newColor, 250);
248 currentTemperature = _temperature;
249 stateDidChange = true;
251 settingBulbTemperatureMutex.unlock();
255 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
257 settingBulbColorMutex.lock();
260 _saturation /= 100.0;
261 _brightness /= 100.0;
264 int newHue = (int)(_hue * 65535.0);
265 int newSaturation = (int)(_saturation * 65535.0);
266 int newBrightness = (int)(_brightness * 65535.0);
268 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
269 sendSetLightColorPacket(newColor, 250);
272 currentSaturation = newSaturation;
273 currentBrightness = newBrightness;
274 stateDidChange = true;
276 settingBulbColorMutex.unlock();
280 bool LifxLightBulb::getState() {
284 bulbStateMutex.lock();
286 bulbStateMutex.unlock();
293 // Communication helpers
294 void LifxLightBulb::receivedPacket(char* packetData) {
296 char headerBytes[36];
297 for (int i = 0; i < 36; i++) {
298 headerBytes[i] = packetData[i];
301 LifxHeader recHeader;
302 recHeader.setFromBytes(headerBytes);
304 // load the payload bytes (strip away the header)
305 //char payloadBytes[recHeader.getSize()];
306 char* payloadBytes = new char[recHeader.getSize()];
307 for (int i = 36; i < recHeader.getSize(); i++) {
308 payloadBytes[i - 36] = packetData[i];
311 int type = recHeader.getType();
312 cout << "Received: " << type << endl;
314 DeviceStateService* dat = NULL;
318 dat = parseDeviceStateServiceMessage(payloadBytes);
319 cout << "Service: " << dat->getService();
320 cout << "Port : " << dat->getPort();
321 // Avoid memory leak - delete this object
326 handleStateVersionMessageReceived(payloadBytes);
330 parseDeviceStateInfoMessage(payloadBytes);
335 handleLightStateMessageReceived(payloadBytes);
339 cout << "unknown packet Type" << endl;
341 // Avoid memory leaks
346 void LifxLightBulb::sendPacket(char* packetData, int len) {
347 //cout << "sendPacket: About to send" << endl;
348 lock_guard<mutex> guard(socketMutex);
349 sendSocketFlag = true;
350 communicationSocket->sendData(packetData, len);
351 sendSocketFlag = false;
355 // Worker function which runs the while loop for receiving data from the bulb.
357 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
359 // Need timeout on receives since we are not sure if a packet will be available
360 // for processing so don't block waiting
361 llb->communicationSocket->setTimeOut(50000); // In milliseconds
365 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
369 // Check if we got the bulb version yet
370 // could have requested it but message could have gotten lost (UDP)
371 if (!llb->didGetBulbVersion) {
372 int64_t currentTime = (int64_t) time(NULL);
373 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
374 // Get the bulb version so we know what type of bulb this is.
375 cout << "Sending version packet! " << endl;
376 llb->sendGetVersionPacket();
377 lastSentGetBulbVersionRequest = currentTime;
381 // Communication resource is busy so try again later
382 if (llb->sendSocketFlag) {
386 llb->socketMutex.lock();
387 int ret = llb->communicationSocket->receiveData(dat, 1024);
388 // Never forget to release!
389 llb->socketMutex.unlock();
393 llb->receivedPacket(dat);
396 // If a state change occurred then request the bulb state to ensure that the
397 // bulb did indeed change its state to the correct state
398 if (llb->stateDidChange) {
399 llb->sendGetLightStatePacket();
402 // Wait a bit as to not tie up system resources
403 this_thread::sleep_for (chrono::milliseconds(100));
404 //cout << endl << "Sleep and wake up!" << endl;
411 void LifxLightBulb::sendGetServicePacket() {
414 header.setTagged(true);
415 header.setMacAddress(bulbMacAddress);
416 header.setSource(0); // randomly picked
417 header.setAck_required(false);
418 header.setRes_required(false);
419 header.setSequence(0);
423 header.getHeaderBytes(dataBytes);
425 sendPacket(dataBytes, 36);
429 void LifxLightBulb::sendGetHostInfoPacket() {
432 header.setTagged(false);
433 header.setMacAddress(bulbMacAddress);
434 header.setSource(10); // randomly picked
435 header.setAck_required(false);
436 header.setRes_required(false);
437 header.setSequence(0);
441 header.getHeaderBytes(dataBytes);
443 sendPacket(dataBytes, 36);
447 void LifxLightBulb::sendGetHostFirmwarePacket() {
450 header.setTagged(false);
451 header.setMacAddress(bulbMacAddress);
452 header.setSource(10); // randomly picked
453 header.setAck_required(false);
454 header.setRes_required(false);
455 header.setSequence(0);
459 header.getHeaderBytes(dataBytes);
461 sendPacket(dataBytes, 36);
465 void LifxLightBulb::sendGetWifiInfoPacket() {
468 header.setTagged(false);
469 header.setMacAddress(bulbMacAddress);
470 header.setSource(10); // randomly picked
471 header.setAck_required(false);
472 header.setRes_required(false);
473 header.setSequence(0);
477 header.getHeaderBytes(dataBytes);
479 sendPacket(dataBytes, 36);
483 void LifxLightBulb::sendGetWifiFirmwarePacket() {
486 header.setTagged(false);
487 header.setMacAddress(bulbMacAddress);
488 header.setSource(10); // 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 LifxLightBulb::sendGetPowerPacket() {
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 LifxLightBulb::sendSetPowerPacket(int level) {
520 // Currently only 0 and 65535 are supported
521 // This is a fix for now
522 if ((level != 65535) && (level != 0)) {
523 cerr << "Invalid parameter values" << endl;
527 if ((level > 65535) || (level < 0)) {
528 cerr << "Invalid parameter values" << endl;
532 char packetBytes[38];
536 header.setTagged(false);
537 header.setMacAddress(bulbMacAddress);
538 header.setSource(10); // randomly picked
539 header.setAck_required(false);
540 header.setRes_required(false);
541 header.setSequence(0);
543 char headerBytes[36];
544 header.getHeaderBytes(headerBytes);
546 for (int i = 0; i < 36; i++) {
547 packetBytes[i] = headerBytes[i];
550 packetBytes[36] = (char)(level & 0xFF);
551 packetBytes[37] = (char)((level >> 8) & 0xFF);
553 sendPacket(packetBytes, 38);
557 void LifxLightBulb::sendGetLabelPacket() {
560 header.setTagged(false);
561 header.setMacAddress(bulbMacAddress);
562 header.setSource(10); // randomly picked
563 header.setAck_required(false);
564 header.setRes_required(false);
565 header.setSequence(0);
569 header.getHeaderBytes(dataBytes);
571 sendPacket(dataBytes, 36);
575 void LifxLightBulb::sendSetLabelPacket(string label) {
576 // Currently only 0 and 65535 are supported
577 // This is a fix for now
578 if (label.length() != 32) {
579 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
583 char packetBytes[68];
587 header.setTagged(false);
588 header.setMacAddress(bulbMacAddress);
589 header.setSource(10); // randomly picked
590 header.setAck_required(false);
591 header.setRes_required(false);
592 header.setSequence(0);
594 char headerBytes[36];
595 header.getHeaderBytes(headerBytes);
597 for (int i = 0; i < 36; i++) {
598 packetBytes[i] = headerBytes[i];
601 for (int i = 0; i < 32; i++) {
602 packetBytes[i + 36] = label.c_str()[i];
605 sendPacket(packetBytes, 68);
609 void LifxLightBulb::sendGetVersionPacket() {
612 header.setTagged(false);
613 header.setMacAddress(bulbMacAddress);
614 header.setSource(10); // randomly picked
615 header.setAck_required(false);
616 header.setRes_required(false);
617 header.setSequence(0);
621 header.getHeaderBytes(dataBytes);
623 sendPacket(dataBytes, 36);
627 void LifxLightBulb::sendGetInfoPacket() {
630 header.setTagged(false);
631 header.setMacAddress(bulbMacAddress);
632 header.setSource(10); // randomly picked
633 header.setAck_required(false);
634 header.setRes_required(false);
635 header.setSequence(0);
639 header.getHeaderBytes(dataBytes);
641 sendPacket(dataBytes, 36);
645 void LifxLightBulb::sendGetLocationPacket() {
648 header.setTagged(false);
649 header.setMacAddress(bulbMacAddress);
650 header.setSource(10); // randomly picked
651 header.setAck_required(false);
652 header.setRes_required(false);
653 header.setSequence(0);
657 header.getHeaderBytes(dataBytes);
659 sendPacket(dataBytes, 36);
663 void LifxLightBulb::sendGetGroupPacket() {
666 header.setTagged(false);
667 header.setMacAddress(bulbMacAddress);
668 header.setSource(10); // randomly picked
669 header.setAck_required(false);
670 header.setRes_required(false);
671 header.setSequence(0);
675 header.getHeaderBytes(dataBytes);
677 sendPacket(dataBytes, 36);
683 void LifxLightBulb::sendGetLightStatePacket() {
686 header.setTagged(false);
687 header.setMacAddress(bulbMacAddress);
688 header.setSource(10); // randomly picked
689 header.setAck_required(false);
690 header.setRes_required(false);
691 header.setSequence(0);
695 header.getHeaderBytes(dataBytes);
697 sendPacket(dataBytes, 36);
701 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
703 if ((duration > 4294967295l) || (duration < 0)) {
704 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
708 char packetBytes[49];
712 header.setTagged(false);
713 header.setMacAddress(bulbMacAddress);
714 header.setSource(10); // randomly picked
715 header.setAck_required(false);
716 header.setRes_required(false);
717 header.setSequence(0);
719 char headerBytes[36];
720 header.getHeaderBytes(headerBytes);
722 for (int i = 0; i < 36; i++) {
723 packetBytes[i] = headerBytes[i];
727 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
728 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
730 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
731 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
733 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
734 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
736 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
737 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
739 packetBytes[45] = (char)((duration >> 0) & 0xFF);
740 packetBytes[46] = (char)((duration >> 8) & 0xFF);
741 packetBytes[47] = (char)((duration >> 16) & 0xFF);
742 packetBytes[48] = (char)((duration >> 24) & 0xFF);
744 sendPacket(packetBytes, 49);
745 // Avoid memory leak - delete object
750 void LifxLightBulb::sendGetLightPowerPacket() {
753 header.setTagged(false);
754 header.setMacAddress(bulbMacAddress);
755 header.setSource(10); // randomly picked
756 header.setAck_required(false);
757 header.setRes_required(false);
758 header.setSequence(0);
762 header.getHeaderBytes(dataBytes);
764 sendPacket(dataBytes, 36);
768 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
770 if ((level > 65535) || (duration > 4294967295l)
771 || (level < 0) || (duration < 0)) {
772 cerr << "Invalid parameter values" << endl;
776 char packetBytes[42];
781 header.setTagged(false);
782 header.setMacAddress(bulbMacAddress);
783 header.setSource(10); // randomly picked
784 header.setAck_required(false);
785 header.setRes_required(false);
786 header.setSequence(0);
788 char headerBytes[36];
789 header.getHeaderBytes(headerBytes);
791 for (int i = 0; i < 36; i++) {
792 packetBytes[i] = headerBytes[i];
795 packetBytes[36] = (char)(level & 0xFF);
796 packetBytes[37] = (char)((level >> 8) & 0xFF);
798 packetBytes[38] = (char)((duration >> 0) & 0xFF);
799 packetBytes[39] = (char)((duration >> 8) & 0xFF);
800 packetBytes[40] = (char)((duration >> 16) & 0xFF);
801 packetBytes[41] = (char)((duration >> 24) & 0xFF);
803 sendPacket(packetBytes, 42);
807 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
809 char packetBytes[100];
813 header.setTagged(false);
814 header.setMacAddress(bulbMacAddress);
815 header.setSource(10); // randomly picked
816 header.setAck_required(false);
817 header.setRes_required(false);
818 header.setSequence(0);
820 char headerBytes[36];
821 header.getHeaderBytes(headerBytes);
823 for (int i = 0; i < 36; i++) {
824 packetBytes[i] = headerBytes[i];
827 for (int i = 0; i < 64; i++) {
828 packetBytes[i + 36] = data[i];
831 sendPacket(packetBytes, 100);
837 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
838 int service = payloadData[0];
839 int64_t port = ((payloadData[3] & 0xFF) << 24);
840 port |= ((payloadData[2] & 0xFF) << 16);
841 port |= ((payloadData[1] & 0xFF) << 8);
842 port |= (payloadData[0] & 0xFF);
844 return new DeviceStateService(service, port);
848 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
849 long signal = ((payloadData[3] & 0xFF) << 24);
850 signal |= ((payloadData[2] & 0xFF) << 16);
851 signal |= ((payloadData[1] & 0xFF) << 8);
852 signal |= (payloadData[0] & 0xFF);
854 long tx = ((payloadData[7] & 0xFF) << 24);
855 tx |= ((payloadData[6] & 0xFF) << 16);
856 tx |= ((payloadData[5] & 0xFF) << 8);
857 tx |= (payloadData[4] & 0xFF);
859 long rx = ((payloadData[11] & 0xFF) << 24);
860 rx |= ((payloadData[10] & 0xFF) << 16);
861 rx |= ((payloadData[9] & 0xFF) << 8);
862 rx |= (payloadData[8] & 0xFF);
864 return new DeviceStateHostInfo(signal, tx, rx);
868 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
870 for (int i = 0; i < 8; i++) {
871 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
876 int64_t version = ((payloadData[19] & 0xFF) << 24);
877 version |= ((payloadData[18] & 0xFF) << 16);
878 version |= ((payloadData[17] & 0xFF) << 8);
879 version |= (payloadData[16] & 0xFF);
881 return new DeviceStateHostFirmware(build, version);
885 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
886 int64_t signal = ((payloadData[3] & 0xFF) << 24);
887 signal |= ((payloadData[2] & 0xFF) << 16);
888 signal |= ((payloadData[1] & 0xFF) << 8);
889 signal |= (payloadData[0] & 0xFF);
891 int64_t tx = ((payloadData[7] & 0xFF) << 24);
892 tx |= ((payloadData[6] & 0xFF) << 16);
893 tx |= ((payloadData[5] & 0xFF) << 8);
894 tx |= (payloadData[4] & 0xFF);
896 int64_t rx = ((payloadData[11] & 0xFF) << 24);
897 rx |= ((payloadData[10] & 0xFF) << 16);
898 rx |= ((payloadData[9] & 0xFF) << 8);
899 rx |= (payloadData[8] & 0xFF);
901 return new DeviceStateWifiInfo(signal, tx, rx);
905 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
907 for (int i = 0; i < 8; i++) {
908 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
913 int64_t version = ((payloadData[19] & 0xFF) << 24);
914 version |= ((payloadData[18] & 0xFF) << 16);
915 version |= ((payloadData[17] & 0xFF) << 8);
916 version |= (payloadData[16] & 0xFF);
918 return new DeviceStateWifiFirmware(build, version);
922 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
923 int level = ((payloadData[1] & 0xFF) << 8);
924 level |= (payloadData[0] & 0xFF);
929 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
930 int64_t vender = ((payloadData[3] & 0xFF) << 24);
931 vender |= ((payloadData[2] & 0xFF) << 16);
932 vender |= ((payloadData[1] & 0xFF) << 8);
933 vender |= (payloadData[0] & 0xFF);
935 int64_t product = ((payloadData[7] & 0xFF) << 24);
936 product |= ((payloadData[6] & 0xFF) << 16);
937 product |= ((payloadData[5] & 0xFF) << 8);
938 product |= (payloadData[4] & 0xFF);
940 int64_t version = ((payloadData[11] & 0xFF) << 24);
941 version |= ((payloadData[10] & 0xFF) << 16);
942 version |= ((payloadData[9] & 0xFF) << 8);
943 version |= (payloadData[8] & 0xFF);
945 return new DeviceStateVersion(vender, product, version);
949 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
952 int64_t downTime = 0;
953 for (int i = 0; i < 8; i++) {
954 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
955 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
956 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
959 return new DeviceStateInfo(time, upTime, downTime);
963 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
965 for (int i = 0; i < 16; i++) {
966 location[i] = payloadData[i];
970 for (int i = 0; i < 32; i++) {
971 labelBytes[i] = payloadData[i + 16];
974 int64_t updatedAt = 0;
975 for (int i = 0; i < 8; i++) {
976 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
979 string str(labelBytes);
980 return new DeviceStateLocation(location, str, updatedAt);
984 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
986 for (int i = 0; i < 16; i++) {
987 group[i] = payloadData[i];
991 for (int i = 0; i < 32; i++) {
992 labelBytes[i] = payloadData[i + 16];
995 int64_t updatedAt = 0;
996 for (int i = 0; i < 8; i++) {
997 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1000 string str(labelBytes);
1001 return new DeviceStateGroup(group, str, updatedAt);
1007 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1010 for (int i = 0; i < 8; i++) {
1011 colorData[i] = payloadData[i];
1013 //BulbColor color(colorData);
1014 BulbColor* color = new BulbColor(colorData);
1016 int power = ((payloadData[11] & 0xFF) << 8);
1017 power |= (payloadData[10] & 0xFF);
1019 string label(payloadData);
1021 char labelArray[32];
1022 for (int i = 0; i < 32; i++) {
1023 labelArray[i] = payloadData[12 + i];
1026 return new LightState(color, power, label);
1030 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1031 int level = ((payloadData[1] & 0xFF) << 8);
1032 level |= (payloadData[0] & 0xFF);
1038 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1040 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1041 int productNumber = (int)deviceState->getProduct();
1043 bool isColor = false;
1045 if (productNumber == 1) {// Original 1000
1047 } else if (productNumber == 3) {//Color 650
1049 } else if (productNumber == 10) {// White 800 (Low Voltage)
1051 } else if (productNumber == 11) {// White 800 (High Voltage)
1053 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1055 } else if (productNumber == 20) {// Color 1000 BR30
1057 } else if (productNumber == 22) {// Color 1000
1063 hueUpperBound = 65535;
1064 saturationLowerBound = 0;
1065 saturationUpperBound = 65535;
1066 brightnessLowerBound = 0;
1067 brightnessUpperBound = 65535;
1068 temperatureLowerBound = 2500;
1069 temperatureUpperBound = 9000;
1073 saturationLowerBound = 0;
1074 saturationUpperBound = 0;
1075 brightnessLowerBound = 0;
1076 brightnessUpperBound = 65535;// still can dim bulb
1077 temperatureLowerBound = 2500;
1078 temperatureUpperBound = 9000;
1081 didGetBulbVersion.exchange(true);
1082 // Avoid memory leak - delete this object
1087 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1088 LightState* lightState = parseLightStateMessage(payloadData);
1090 BulbColor* color = lightState->getColor();
1091 int power = lightState->getPower();
1093 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1094 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1095 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1096 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1098 bool bulbWrongColor = false;
1099 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1100 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1101 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1102 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1105 // gets set to true if any of the below if statements are taken
1106 stateDidChange = false;
1108 if (bulbWrongColor) {
1109 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1110 sendSetLightColorPacket(newColor, 250);
1111 //cout << "Failed Check 1" << endl;
1114 bulbStateMutex.lock();
1115 bool bulbIsOnTmp = bulbIsOn;
1116 bulbStateMutex.unlock();
1118 if ((!bulbIsOnTmp) && (power != 0)) {
1120 //cout << "Failed Check 2: " << endl;
1124 if (bulbIsOnTmp && (power < 65530)) {
1126 //cout << "Failed Check 3: " << endl;
1129 // Avoid memory leak - delete object
1135 // Functions for the main function
1136 void onOff(LifxLightBulb *llb) {
1138 for (int i = 0; i < 2; i++) {
1140 cout << "Turning off!" << endl;
1141 this_thread::sleep_for (chrono::milliseconds(1000));
1143 cout << "Turning on!" << endl;
1144 this_thread::sleep_for (chrono::milliseconds(1000));
1149 void adjustTemp(LifxLightBulb *llb) {
1151 for (int i = 2500; i < 9000; i += 100) {
1152 cout << "Adjusting Temp: " << i << endl;
1153 llb->setTemperature(i);
1154 this_thread::sleep_for (chrono::milliseconds(100));
1156 cout << "Adjusted temperature to 9000!" << endl;
1157 for (int i = 9000; i > 2500; i -= 100) {
1158 cout << "Adjusting Temp: " << i << endl;
1159 llb->setTemperature(i);
1160 this_thread::sleep_for (chrono::milliseconds(100));
1162 cout << "Adjusted temperature to 2500!" << endl;
1166 void adjustBright(LifxLightBulb *llb) {
1167 for (int i = 100; i > 0; i -= 10) {
1168 cout << "Adjusting Brightness: " << i << endl;
1169 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1170 this_thread::sleep_for (chrono::milliseconds(100));
1172 cout << "Adjusted brightness to 0!" << endl;
1173 for (int i = 0; i < 100; i += 10) {
1174 cout << "Adjusting Brightness: " << i << endl;
1175 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1176 this_thread::sleep_for (chrono::milliseconds(100));
1178 cout << "Adjusting brightness to 100!" << endl;
1182 /*int main(int argc, char *argv[])
1184 string macAddress = "D073D5128E300000";
1185 //string macAddress = "D073D50241DA0000";
1186 string devIPAddress = "192.168.2.126";
1187 //string devIPAddress = "192.168.2.232";
1188 //IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false);
1189 IoTDeviceAddress* devAddress = new IoTDeviceAddress(devIPAddress, 12345, 56700, false, false);
1190 unordered_set<IoTDeviceAddress*> myset = { devAddress };
1192 IoTSet<IoTDeviceAddress*> setDevAddress(myset);
1193 LifxLightBulb *llb = new LifxLightBulb(setDevAddress, macAddress);
1194 cout << "Generated LifxLightBulb object!" << endl;