7 #include "LifxLightBulb.h"
9 #include "IoTDeviceAddress.h"
13 /* TODO: Uncomment this to do normal C++ (g++)
14 int main(int argc, char *argv[])
16 string macAddress1 = "D073D5128E300000";
17 //string macAddress1 = "D073D50241DA0000";
18 string devIPAddress1 = "192.168.1.126";
19 //string devIPAddress1 = "192.168.1.232";
20 LifxLightBulb *llb1 = new LifxLightBulb(devIPAddress1, macAddress1, 12345);
23 for(int i=0; i < 1; i++) {
25 this_thread::sleep_for (chrono::milliseconds(1000));
26 cout << "Turn off" << endl;
28 this_thread::sleep_for (chrono::milliseconds(1000));
29 cout << "Turn on" << endl;
33 //delete setDevAddress1;
41 LifxLightBulb::LifxLightBulb() {
42 // LB1 macAddress: d0:73:d5:12:8e:30
43 // LB2 macAddress: d0:73:d5:02:41:da
44 string macAddress = "D073D5128E300000";
45 //string macAddress = "D073D50241DA0000";
46 /*bulbMacAddress[0] = 0xD0;
47 bulbMacAddress[1] = 0x73;
48 bulbMacAddress[2] = 0xD5;
49 bulbMacAddress[3] = 0x02;
50 bulbMacAddress[4] = 0x41;
51 bulbMacAddress[5] = 0xDA;
52 bulbMacAddress[6] = 0x00;
53 bulbMacAddress[7] = 0x00;*/
55 char tmpMacAddress[16];
56 strcpy(tmpMacAddress, macAddress.c_str());
57 for(int i=0; i<16; i=i+2) {
58 // Take 2 digits and then convert
60 tmpMacByte[0] = tmpMacAddress[i];
61 tmpMacByte[1] = tmpMacAddress[i+1];
62 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
68 LifxLightBulb::LifxLightBulb(uint8_t* ipAddress, string macAddress, int srcPort) {
70 // Initialize macAddress
71 char tmpMacAddress[16];
72 strcpy(tmpMacAddress, macAddress.c_str());
73 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
74 for(int i=0; i<16; i=i+2) {
75 // Take 2 digits and then convert
77 tmpMacByte[0] = tmpMacAddress[i];
78 tmpMacByte[1] = tmpMacAddress[i+1];
79 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
81 //cout << "MAC address is set. Value: ";
83 // Initialize device address
84 // Port 56700 is the default port for Lifx
85 IoTDeviceAddress* devAddress = new IoTDeviceAddress(ipAddress, srcPort, 56700, false, false);
86 unordered_set<void*>* myset1 = new unordered_set<void*>();
87 myset1->insert(devAddress);
88 IoTSet<void*>* setDevAddress = new IoTSet<void*>(myset1);
89 lb_addresses = setDevAddress;
90 //cout << "Device address is set! " << endl;
95 // Driver constructor always gets a pointer to device address, trailed by class arguments of generic type
96 LifxLightBulb::LifxLightBulb(IoTSet<void*>* _devAddress, string macAddress) {
98 // Initialize macAddress
99 char tmpMacAddress[16];
100 strcpy(tmpMacAddress, macAddress.c_str());
101 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
102 for(int i=0; i<16; i=i+2) {
103 // Take 2 digits and then convert
105 tmpMacByte[0] = tmpMacAddress[i];
106 tmpMacByte[1] = tmpMacAddress[i+1];
107 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
109 //cout << "MAC address is set. Value: ";
111 // Initialize device address
112 lb_addresses = _devAddress;
113 //cout << "Device address is set! " << endl;
117 LifxLightBulb::~LifxLightBulb() {
120 if (communicationSocket != NULL) {
122 delete communicationSocket;
123 communicationSocket = NULL;
125 for(void* dev : *lb_addresses) {
126 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
130 if (lb_addresses != NULL) {
139 // Initialize the lightbulb
140 void LifxLightBulb::init() {
142 //if (didAlreadyInit.exchange(true))
145 // Set to true if not yet
146 didAlreadyInit = true;
148 unordered_set<void*>::const_iterator itr = lb_addresses->begin();
149 IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
150 //cout << "Address: " << deviceAddress->getAddress() << endl;
152 // Create IoTUDP socket
153 communicationSocket = new IoTUDP(deviceAddress);
155 //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
156 //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
157 //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
159 // Launch the worker function in a separate thread.
160 // NOTE: "this" pointer is passed into the detached thread because it does not belong
161 // to this object anymore so if it executes certain methods of "this" object, then it needs
162 // the correct references to stuff
163 thread th1 (&LifxLightBulb::workerFunction, this, this);
166 //cout << "Initialized LifxLightBulb!" << endl;
170 void LifxLightBulb::turnOff() {
172 //lock_guard<mutex> guard(bulbStateMutex);
173 bulbStateMutex.lock();
175 sendSetLightPowerPacket(0, 0);
176 stateDidChange = true;
177 bulbStateMutex.unlock();
181 void LifxLightBulb::turnOn() {
183 //lock_guard<mutex> guard(bulbStateMutex);
184 bulbStateMutex.lock();
186 sendSetLightPowerPacket(65535, 0);
187 stateDidChange = true;
188 bulbStateMutex.unlock();
192 double LifxLightBulb::getHue() {
194 settingBulbColorMutex.lock();
195 tmp = ((double)currentHue / 65535.0) * 360.0;
196 settingBulbColorMutex.unlock();
202 double LifxLightBulb::getSaturation() {
204 settingBulbColorMutex.lock();
205 tmp = ((double)currentSaturation / 65535.0) * 360.0;
206 settingBulbColorMutex.unlock();
212 double LifxLightBulb::getBrightness() {
214 settingBulbColorMutex.lock();
215 tmp = ((double)currentBrightness / 65535.0) * 360.0;
216 settingBulbColorMutex.unlock();
222 int LifxLightBulb::getTemperature() {
225 settingBulbTemperatureMutex.lock();
226 tmp = currentTemperature;
227 settingBulbTemperatureMutex.unlock();
233 double LifxLightBulb::getHueRangeLowerBound() {
234 if (!didGetBulbVersion) {
237 return ((double)hueLowerBound / 65535.0) * 360.0;
241 double LifxLightBulb::getHueRangeUpperBound() {
242 if (!didGetBulbVersion) {
245 return ((double)hueUpperBound / 65535.0) * 360.0;
249 double LifxLightBulb::getSaturationRangeLowerBound() {
250 if (!didGetBulbVersion) {
253 return ((double)saturationLowerBound / 65535.0) * 100.0;
257 double LifxLightBulb::getSaturationRangeUpperBound() {
258 if (!didGetBulbVersion) {
261 return ((double)saturationUpperBound / 65535.0) * 100.0;
265 double LifxLightBulb::getBrightnessRangeLowerBound() {
266 if (!didGetBulbVersion) {
269 return ((double)brightnessLowerBound / 65535.0) * 100.0;
273 double LifxLightBulb::getBrightnessRangeUpperBound() {
274 if (!didGetBulbVersion) {
277 return ((double)brightnessUpperBound / 65535.0) * 100.0;
281 int LifxLightBulb::getTemperatureRangeLowerBound() {
282 if (!didGetBulbVersion) {
285 return temperatureLowerBound;
289 int LifxLightBulb::getTemperatureRangeUpperBound() {
290 if (!didGetBulbVersion) {
293 return temperatureUpperBound;
297 void LifxLightBulb::setTemperature(int _temperature) {
299 settingBulbTemperatureMutex.lock();
301 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
302 sendSetLightColorPacket(newColor, 250);
304 currentTemperature = _temperature;
305 stateDidChange = true;
307 settingBulbTemperatureMutex.unlock();
311 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
313 settingBulbColorMutex.lock();
316 _saturation /= 100.0;
317 _brightness /= 100.0;
320 int newHue = (int)(_hue * 65535.0);
321 int newSaturation = (int)(_saturation * 65535.0);
322 int newBrightness = (int)(_brightness * 65535.0);
324 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
325 sendSetLightColorPacket(newColor, 250);
328 currentSaturation = newSaturation;
329 currentBrightness = newBrightness;
330 stateDidChange = true;
332 settingBulbColorMutex.unlock();
336 bool LifxLightBulb::getState() {
340 bulbStateMutex.lock();
342 bulbStateMutex.unlock();
349 // Communication helpers
350 void LifxLightBulb::receivedPacket(char* packetData) {
352 char headerBytes[36];
353 for (int i = 0; i < 36; i++) {
354 headerBytes[i] = packetData[i];
357 LifxHeader recHeader;
358 recHeader.setFromBytes(headerBytes);
360 // load the payload bytes (strip away the header)
361 char* payloadBytes = new char[recHeader.getSize()];
362 for (int i = 36; i < recHeader.getSize(); i++) {
363 payloadBytes[i - 36] = packetData[i];
366 int type = recHeader.getType();
367 //cout << "Received: " << type << endl;
369 DeviceStateService* dat = NULL;
373 dat = parseDeviceStateServiceMessage(payloadBytes);
374 //cout << "Service: " << dat->getService();
375 //cout << "Port : " << dat->getPort();
376 // Avoid memory leak - delete this object
381 handleStateVersionMessageReceived(payloadBytes);
385 parseDeviceStateInfoMessage(payloadBytes);
390 handleLightStateMessageReceived(payloadBytes);
395 //cout << "unknown packet Type" << endl;
397 // Avoid memory leaks
402 void LifxLightBulb::sendPacket(char* packetData, int len) {
403 //cout << "sendPacket: About to send" << endl;
404 lock_guard<mutex> guard(socketMutex);
405 sendSocketFlag = true;
406 communicationSocket->sendData(packetData, len);
407 sendSocketFlag = false;
411 // Worker function which runs the while loop for receiving data from the bulb.
413 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
415 // Need timeout on receives since we are not sure if a packet will be available
416 // for processing so don't block waiting
417 llb->communicationSocket->setTimeOut(50000); // In milliseconds
420 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
424 // Check if we got the bulb version yet
425 // could have requested it but message could have gotten lost (UDP)
426 if (!llb->didGetBulbVersion) {
427 int64_t currentTime = (int64_t) time(NULL);
428 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
429 // Get the bulb version so we know what type of bulb this is.
430 //cout << "Sending version packet! " << endl;
431 llb->sendGetVersionPacket();
432 lastSentGetBulbVersionRequest = currentTime;
436 // Communication resource is busy so try again later
437 if (llb->sendSocketFlag) {
441 llb->socketMutex.lock();
442 int ret = llb->communicationSocket->receiveData(dat, 1024);
443 // Never forget to release!
444 llb->socketMutex.unlock();
448 llb->receivedPacket(dat);
451 // If a state change occurred then request the bulb state to ensure that the
452 // bulb did indeed change its state to the correct state
453 if (llb->stateDidChange) {
454 llb->sendGetLightStatePacket();
457 // Wait a bit as to not tie up system resources
458 this_thread::sleep_for (chrono::milliseconds(100));
459 //cout << endl << "Sleep and wake up!" << endl;
466 void LifxLightBulb::sendGetServicePacket() {
469 header.setTagged(true);
470 header.setMacAddress(bulbMacAddress);
471 header.setSource(0); // randomly picked
472 header.setAck_required(false);
473 header.setRes_required(false);
474 header.setSequence(0);
478 header.getHeaderBytes(dataBytes);
480 sendPacket(dataBytes, 36);
484 void LifxLightBulb::sendGetHostInfoPacket() {
487 header.setTagged(false);
488 header.setMacAddress(bulbMacAddress);
489 header.setSource(10); // randomly picked
490 header.setAck_required(false);
491 header.setRes_required(false);
492 header.setSequence(0);
496 header.getHeaderBytes(dataBytes);
498 sendPacket(dataBytes, 36);
502 void LifxLightBulb::sendGetHostFirmwarePacket() {
505 header.setTagged(false);
506 header.setMacAddress(bulbMacAddress);
507 header.setSource(10); // randomly picked
508 header.setAck_required(false);
509 header.setRes_required(false);
510 header.setSequence(0);
514 header.getHeaderBytes(dataBytes);
516 sendPacket(dataBytes, 36);
520 void LifxLightBulb::sendGetWifiInfoPacket() {
523 header.setTagged(false);
524 header.setMacAddress(bulbMacAddress);
525 header.setSource(10); // randomly picked
526 header.setAck_required(false);
527 header.setRes_required(false);
528 header.setSequence(0);
532 header.getHeaderBytes(dataBytes);
534 sendPacket(dataBytes, 36);
538 void LifxLightBulb::sendGetWifiFirmwarePacket() {
541 header.setTagged(false);
542 header.setMacAddress(bulbMacAddress);
543 header.setSource(10); // randomly picked
544 header.setAck_required(false);
545 header.setRes_required(false);
546 header.setSequence(0);
550 header.getHeaderBytes(dataBytes);
552 sendPacket(dataBytes, 36);
556 void LifxLightBulb::sendGetPowerPacket() {
559 header.setTagged(false);
560 header.setMacAddress(bulbMacAddress);
561 header.setSource(10); // randomly picked
562 header.setAck_required(false);
563 header.setRes_required(false);
564 header.setSequence(0);
568 header.getHeaderBytes(dataBytes);
570 sendPacket(dataBytes, 36);
574 void LifxLightBulb::sendSetPowerPacket(int level) {
575 // Currently only 0 and 65535 are supported
576 // This is a fix for now
577 if ((level != 65535) && (level != 0)) {
578 cerr << "Invalid parameter values" << endl;
582 if ((level > 65535) || (level < 0)) {
583 cerr << "Invalid parameter values" << endl;
587 char packetBytes[38];
591 header.setTagged(false);
592 header.setMacAddress(bulbMacAddress);
593 header.setSource(10); // randomly picked
594 header.setAck_required(false);
595 header.setRes_required(false);
596 header.setSequence(0);
598 char headerBytes[36];
599 header.getHeaderBytes(headerBytes);
601 for (int i = 0; i < 36; i++) {
602 packetBytes[i] = headerBytes[i];
605 packetBytes[36] = (char)(level & 0xFF);
606 packetBytes[37] = (char)((level >> 8) & 0xFF);
608 sendPacket(packetBytes, 38);
612 void LifxLightBulb::sendGetLabelPacket() {
615 header.setTagged(false);
616 header.setMacAddress(bulbMacAddress);
617 header.setSource(10); // randomly picked
618 header.setAck_required(false);
619 header.setRes_required(false);
620 header.setSequence(0);
624 header.getHeaderBytes(dataBytes);
626 sendPacket(dataBytes, 36);
630 void LifxLightBulb::sendSetLabelPacket(string label) {
631 // Currently only 0 and 65535 are supported
632 // This is a fix for now
633 if (label.length() != 32) {
634 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
638 char packetBytes[68];
642 header.setTagged(false);
643 header.setMacAddress(bulbMacAddress);
644 header.setSource(10); // randomly picked
645 header.setAck_required(false);
646 header.setRes_required(false);
647 header.setSequence(0);
649 char headerBytes[36];
650 header.getHeaderBytes(headerBytes);
652 for (int i = 0; i < 36; i++) {
653 packetBytes[i] = headerBytes[i];
656 for (int i = 0; i < 32; i++) {
657 packetBytes[i + 36] = label.c_str()[i];
660 sendPacket(packetBytes, 68);
664 void LifxLightBulb::sendGetVersionPacket() {
667 header.setTagged(false);
668 header.setMacAddress(bulbMacAddress);
669 header.setSource(10); // randomly picked
670 header.setAck_required(false);
671 header.setRes_required(false);
672 header.setSequence(0);
676 header.getHeaderBytes(dataBytes);
678 sendPacket(dataBytes, 36);
682 void LifxLightBulb::sendGetInfoPacket() {
685 header.setTagged(false);
686 header.setMacAddress(bulbMacAddress);
687 header.setSource(10); // randomly picked
688 header.setAck_required(false);
689 header.setRes_required(false);
690 header.setSequence(0);
694 header.getHeaderBytes(dataBytes);
696 sendPacket(dataBytes, 36);
700 void LifxLightBulb::sendGetLocationPacket() {
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::sendGetGroupPacket() {
721 header.setTagged(false);
722 header.setMacAddress(bulbMacAddress);
723 header.setSource(10); // randomly picked
724 header.setAck_required(false);
725 header.setRes_required(false);
726 header.setSequence(0);
730 header.getHeaderBytes(dataBytes);
732 sendPacket(dataBytes, 36);
738 void LifxLightBulb::sendGetLightStatePacket() {
741 header.setTagged(false);
742 header.setMacAddress(bulbMacAddress);
743 header.setSource(10); // randomly picked
744 header.setAck_required(false);
745 header.setRes_required(false);
746 header.setSequence(0);
750 header.getHeaderBytes(dataBytes);
752 sendPacket(dataBytes, 36);
756 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
758 if ((duration > 4294967295l) || (duration < 0)) {
759 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
763 char packetBytes[49];
767 header.setTagged(false);
768 header.setMacAddress(bulbMacAddress);
769 header.setSource(10); // randomly picked
770 header.setAck_required(false);
771 header.setRes_required(false);
772 header.setSequence(0);
774 char headerBytes[36];
775 header.getHeaderBytes(headerBytes);
777 for (int i = 0; i < 36; i++) {
778 packetBytes[i] = headerBytes[i];
782 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
783 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
785 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
786 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
788 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
789 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
791 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
792 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
794 packetBytes[45] = (char)((duration >> 0) & 0xFF);
795 packetBytes[46] = (char)((duration >> 8) & 0xFF);
796 packetBytes[47] = (char)((duration >> 16) & 0xFF);
797 packetBytes[48] = (char)((duration >> 24) & 0xFF);
799 sendPacket(packetBytes, 49);
800 // Avoid memory leak - delete object
805 void LifxLightBulb::sendGetLightPowerPacket() {
808 header.setTagged(false);
809 header.setMacAddress(bulbMacAddress);
810 header.setSource(10); // randomly picked
811 header.setAck_required(false);
812 header.setRes_required(false);
813 header.setSequence(0);
817 header.getHeaderBytes(dataBytes);
819 sendPacket(dataBytes, 36);
823 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
825 if ((level > 65535) || (duration > 4294967295l)
826 || (level < 0) || (duration < 0)) {
827 cerr << "Invalid parameter values" << endl;
830 char packetBytes[42];
834 header.setTagged(false);
835 header.setMacAddress(bulbMacAddress);
836 header.setSource(10); // randomly picked
837 header.setAck_required(false);
838 header.setRes_required(false);
839 header.setSequence(0);
841 char headerBytes[36];
842 header.getHeaderBytes(headerBytes);
844 for (int i = 0; i < 36; i++) {
845 packetBytes[i] = headerBytes[i];
848 packetBytes[36] = (char)(level & 0xFF);
849 packetBytes[37] = (char)((level >> 8) & 0xFF);
851 packetBytes[38] = (char)((duration >> 0) & 0xFF);
852 packetBytes[39] = (char)((duration >> 8) & 0xFF);
853 packetBytes[40] = (char)((duration >> 16) & 0xFF);
854 packetBytes[41] = (char)((duration >> 24) & 0xFF);
856 sendPacket(packetBytes, 42);
860 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
862 char packetBytes[100];
866 header.setTagged(false);
867 header.setMacAddress(bulbMacAddress);
868 header.setSource(10); // randomly picked
869 header.setAck_required(false);
870 header.setRes_required(false);
871 header.setSequence(0);
873 char headerBytes[36];
874 header.getHeaderBytes(headerBytes);
876 for (int i = 0; i < 36; i++) {
877 packetBytes[i] = headerBytes[i];
880 for (int i = 0; i < 64; i++) {
881 packetBytes[i + 36] = data[i];
884 sendPacket(packetBytes, 100);
890 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
891 int service = payloadData[0];
892 int64_t port = ((payloadData[3] & 0xFF) << 24);
893 port |= ((payloadData[2] & 0xFF) << 16);
894 port |= ((payloadData[1] & 0xFF) << 8);
895 port |= (payloadData[0] & 0xFF);
897 return new DeviceStateService(service, port);
901 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
902 long signal = ((payloadData[3] & 0xFF) << 24);
903 signal |= ((payloadData[2] & 0xFF) << 16);
904 signal |= ((payloadData[1] & 0xFF) << 8);
905 signal |= (payloadData[0] & 0xFF);
907 long tx = ((payloadData[7] & 0xFF) << 24);
908 tx |= ((payloadData[6] & 0xFF) << 16);
909 tx |= ((payloadData[5] & 0xFF) << 8);
910 tx |= (payloadData[4] & 0xFF);
912 long rx = ((payloadData[11] & 0xFF) << 24);
913 rx |= ((payloadData[10] & 0xFF) << 16);
914 rx |= ((payloadData[9] & 0xFF) << 8);
915 rx |= (payloadData[8] & 0xFF);
917 return new DeviceStateHostInfo(signal, tx, rx);
921 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
923 for (int i = 0; i < 8; i++) {
924 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
929 int64_t version = ((payloadData[19] & 0xFF) << 24);
930 version |= ((payloadData[18] & 0xFF) << 16);
931 version |= ((payloadData[17] & 0xFF) << 8);
932 version |= (payloadData[16] & 0xFF);
934 return new DeviceStateHostFirmware(build, version);
938 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
939 int64_t signal = ((payloadData[3] & 0xFF) << 24);
940 signal |= ((payloadData[2] & 0xFF) << 16);
941 signal |= ((payloadData[1] & 0xFF) << 8);
942 signal |= (payloadData[0] & 0xFF);
944 int64_t tx = ((payloadData[7] & 0xFF) << 24);
945 tx |= ((payloadData[6] & 0xFF) << 16);
946 tx |= ((payloadData[5] & 0xFF) << 8);
947 tx |= (payloadData[4] & 0xFF);
949 int64_t rx = ((payloadData[11] & 0xFF) << 24);
950 rx |= ((payloadData[10] & 0xFF) << 16);
951 rx |= ((payloadData[9] & 0xFF) << 8);
952 rx |= (payloadData[8] & 0xFF);
954 return new DeviceStateWifiInfo(signal, tx, rx);
958 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
960 for (int i = 0; i < 8; i++) {
961 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
966 int64_t version = ((payloadData[19] & 0xFF) << 24);
967 version |= ((payloadData[18] & 0xFF) << 16);
968 version |= ((payloadData[17] & 0xFF) << 8);
969 version |= (payloadData[16] & 0xFF);
971 return new DeviceStateWifiFirmware(build, version);
975 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
976 int level = ((payloadData[1] & 0xFF) << 8);
977 level |= (payloadData[0] & 0xFF);
982 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
983 int64_t vender = ((payloadData[3] & 0xFF) << 24);
984 vender |= ((payloadData[2] & 0xFF) << 16);
985 vender |= ((payloadData[1] & 0xFF) << 8);
986 vender |= (payloadData[0] & 0xFF);
988 int64_t product = ((payloadData[7] & 0xFF) << 24);
989 product |= ((payloadData[6] & 0xFF) << 16);
990 product |= ((payloadData[5] & 0xFF) << 8);
991 product |= (payloadData[4] & 0xFF);
993 int64_t version = ((payloadData[11] & 0xFF) << 24);
994 version |= ((payloadData[10] & 0xFF) << 16);
995 version |= ((payloadData[9] & 0xFF) << 8);
996 version |= (payloadData[8] & 0xFF);
998 return new DeviceStateVersion(vender, product, version);
1002 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
1005 int64_t downTime = 0;
1006 for (int i = 0; i < 8; i++) {
1007 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
1008 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
1009 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
1012 return new DeviceStateInfo(time, upTime, downTime);
1016 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
1018 for (int i = 0; i < 16; i++) {
1019 location[i] = payloadData[i];
1022 char labelBytes[32];
1023 for (int i = 0; i < 32; i++) {
1024 labelBytes[i] = payloadData[i + 16];
1027 int64_t updatedAt = 0;
1028 for (int i = 0; i < 8; i++) {
1029 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1032 string str(labelBytes);
1033 return new DeviceStateLocation(location, str, updatedAt);
1037 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1039 for (int i = 0; i < 16; i++) {
1040 group[i] = payloadData[i];
1043 char labelBytes[32];
1044 for (int i = 0; i < 32; i++) {
1045 labelBytes[i] = payloadData[i + 16];
1048 int64_t updatedAt = 0;
1049 for (int i = 0; i < 8; i++) {
1050 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1053 string str(labelBytes);
1054 return new DeviceStateGroup(group, str, updatedAt);
1060 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1063 for (int i = 0; i < 8; i++) {
1064 colorData[i] = payloadData[i];
1066 //BulbColor color(colorData);
1067 BulbColor* color = new BulbColor(colorData);
1069 int power = ((payloadData[11] & 0xFF) << 8);
1070 power |= (payloadData[10] & 0xFF);
1072 string label(payloadData);
1074 char labelArray[32];
1075 for (int i = 0; i < 32; i++) {
1076 labelArray[i] = payloadData[12 + i];
1079 return new LightState(color, power, label);
1083 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1084 int level = ((payloadData[1] & 0xFF) << 8);
1085 level |= (payloadData[0] & 0xFF);
1091 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1093 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1094 int productNumber = (int)deviceState->getProduct();
1096 bool isColor = false;
1098 if (productNumber == 1) {// Original 1000
1100 } else if (productNumber == 3) {//Color 650
1102 } else if (productNumber == 10) {// White 800 (Low Voltage)
1104 } else if (productNumber == 11) {// White 800 (High Voltage)
1106 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1108 } else if (productNumber == 20) {// Color 1000 BR30
1110 } else if (productNumber == 22) {// Color 1000
1116 hueUpperBound = 65535;
1117 saturationLowerBound = 0;
1118 saturationUpperBound = 65535;
1119 brightnessLowerBound = 0;
1120 brightnessUpperBound = 65535;
1121 temperatureLowerBound = 2500;
1122 temperatureUpperBound = 9000;
1126 saturationLowerBound = 0;
1127 saturationUpperBound = 0;
1128 brightnessLowerBound = 0;
1129 brightnessUpperBound = 65535;// still can dim bulb
1130 temperatureLowerBound = 2500;
1131 temperatureUpperBound = 9000;
1134 //didGetBulbVersion.exchange(true);
1135 didGetBulbVersion = true;
1136 // Avoid memory leak - delete this object
1141 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1142 LightState* lightState = parseLightStateMessage(payloadData);
1144 BulbColor* color = lightState->getColor();
1145 int power = lightState->getPower();
1147 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1148 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1149 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1150 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1152 bool bulbWrongColor = false;
1153 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1154 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1155 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1156 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1159 // gets set to true if any of the below if statements are taken
1160 stateDidChange = false;
1162 if (bulbWrongColor) {
1163 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1164 sendSetLightColorPacket(newColor, 250);
1165 //cout << "Failed Check 1" << endl;
1168 bulbStateMutex.lock();
1169 bool bulbIsOnTmp = bulbIsOn;
1170 bulbStateMutex.unlock();
1172 if ((!bulbIsOnTmp) && (power != 0)) {
1174 //cout << "Failed Check 2: " << endl;
1178 if (bulbIsOnTmp && (power < 65530)) {
1180 //cout << "Failed Check 3: " << endl;
1183 // Avoid memory leak - delete object