7 #include "LifxLightBulb.h"
9 #include "IoTDeviceAddress.h"
10 #include "application.h"
15 // Default constructor
16 LifxLightBulb::LifxLightBulb() {
22 LifxLightBulb::LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort) {
24 memcpy(bulbMacAddress, macAddress, 8);
26 // Initialize device address
27 // Port 56700 is the default port for Lifx
28 IoTDeviceAddress* devAddress = new IoTDeviceAddress(ipAddress, srcPort, 56700, false, false);
29 unordered_set<void*>* myset1 = new unordered_set<void*>();
30 myset1->insert(devAddress);
31 IoTSet<void*>* setDevAddress = new IoTSet<void*>(myset1);
32 lb_addresses = setDevAddress;
36 LifxLightBulb::~LifxLightBulb() {
39 if (communicationSocket != NULL) {
41 delete communicationSocket;
42 communicationSocket = NULL;
44 for(void* dev : *lb_addresses) {
45 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
49 if (lb_addresses != NULL) {
58 // Initialize the lightbulb
59 void LifxLightBulb::init() {
63 // Set to true if not yet
64 didAlreadyInit = true;
66 unordered_set<void*>::const_iterator itr = lb_addresses->begin();
67 IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
69 // Create IoTUDP socket
70 communicationSocket = new IoTUDP(deviceAddress);
72 //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
73 //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
74 //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
76 // Launch the worker function in a separate thread.
77 // NOTE: "this" pointer is passed into the detached thread because it does not belong
78 // to this object anymore so if it executes certain methods of "this" object, then it needs
79 // the correct references to stuff
80 thread th1 (&LifxLightBulb::workerFunction, this, this);
85 void LifxLightBulb::turnOff() {
87 //lock_guard<mutex> guard(bulbStateMutex);
88 bulbStateMutex.lock();
90 sendSetLightPowerPacket(0, 0);
91 stateDidChange = true;
92 bulbStateMutex.unlock();
96 void LifxLightBulb::turnOn() {
98 //lock_guard<mutex> guard(bulbStateMutex);
99 bulbStateMutex.lock();
101 sendSetLightPowerPacket(65535, 0);
102 stateDidChange = true;
103 bulbStateMutex.unlock();
107 double LifxLightBulb::getHue() {
109 settingBulbColorMutex.lock();
110 tmp = ((double)currentHue / 65535.0) * 360.0;
111 settingBulbColorMutex.unlock();
117 double LifxLightBulb::getSaturation() {
119 settingBulbColorMutex.lock();
120 tmp = ((double)currentSaturation / 65535.0) * 360.0;
121 settingBulbColorMutex.unlock();
127 double LifxLightBulb::getBrightness() {
129 settingBulbColorMutex.lock();
130 tmp = ((double)currentBrightness / 65535.0) * 360.0;
131 settingBulbColorMutex.unlock();
137 int LifxLightBulb::getTemperature() {
140 settingBulbTemperatureMutex.lock();
141 tmp = currentTemperature;
142 settingBulbTemperatureMutex.unlock();
148 double LifxLightBulb::getHueRangeLowerBound() {
149 if (!didGetBulbVersion) {
152 return ((double)hueLowerBound / 65535.0) * 360.0;
156 double LifxLightBulb::getHueRangeUpperBound() {
157 if (!didGetBulbVersion) {
160 return ((double)hueUpperBound / 65535.0) * 360.0;
164 double LifxLightBulb::getSaturationRangeLowerBound() {
165 if (!didGetBulbVersion) {
168 return ((double)saturationLowerBound / 65535.0) * 100.0;
172 double LifxLightBulb::getSaturationRangeUpperBound() {
173 if (!didGetBulbVersion) {
176 return ((double)saturationUpperBound / 65535.0) * 100.0;
180 double LifxLightBulb::getBrightnessRangeLowerBound() {
181 if (!didGetBulbVersion) {
184 return ((double)brightnessLowerBound / 65535.0) * 100.0;
188 double LifxLightBulb::getBrightnessRangeUpperBound() {
189 if (!didGetBulbVersion) {
192 return ((double)brightnessUpperBound / 65535.0) * 100.0;
196 int LifxLightBulb::getTemperatureRangeLowerBound() {
197 if (!didGetBulbVersion) {
200 return temperatureLowerBound;
204 int LifxLightBulb::getTemperatureRangeUpperBound() {
205 if (!didGetBulbVersion) {
208 return temperatureUpperBound;
212 void LifxLightBulb::setTemperature(int _temperature) {
214 settingBulbTemperatureMutex.lock();
216 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
217 sendSetLightColorPacket(newColor, 250);
219 currentTemperature = _temperature;
220 stateDidChange = true;
222 settingBulbTemperatureMutex.unlock();
226 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
228 settingBulbColorMutex.lock();
231 _saturation /= 100.0;
232 _brightness /= 100.0;
235 int newHue = (int)(_hue * 65535.0);
236 int newSaturation = (int)(_saturation * 65535.0);
237 int newBrightness = (int)(_brightness * 65535.0);
239 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
240 sendSetLightColorPacket(newColor, 250);
243 currentSaturation = newSaturation;
244 currentBrightness = newBrightness;
245 stateDidChange = true;
247 settingBulbColorMutex.unlock();
251 bool LifxLightBulb::getState() {
255 bulbStateMutex.lock();
257 bulbStateMutex.unlock();
264 // Communication helpers
265 void LifxLightBulb::receivedPacket(char* packetData) {
267 char headerBytes[36];
268 for (int i = 0; i < 36; i++) {
269 headerBytes[i] = packetData[i];
272 LifxHeader recHeader;
273 recHeader.setFromBytes(headerBytes);
275 // load the payload bytes (strip away the header)
276 char* payloadBytes = new char[recHeader.getSize()];
277 for (int i = 36; i < recHeader.getSize(); i++) {
278 payloadBytes[i - 36] = packetData[i];
281 int type = recHeader.getType();
282 //cout << "Received: " << type << endl;
284 DeviceStateService* dat = NULL;
288 dat = parseDeviceStateServiceMessage(payloadBytes);
289 //cout << "Service: " << dat->getService();
290 //cout << "Port : " << dat->getPort();
291 // Avoid memory leak - delete this object
296 handleStateVersionMessageReceived(payloadBytes);
300 parseDeviceStateInfoMessage(payloadBytes);
305 handleLightStateMessageReceived(payloadBytes);
310 //cout << "unknown packet Type" << endl;
312 // Avoid memory leaks
317 void LifxLightBulb::sendPacket(char* packetData, int len) {
318 //cout << "sendPacket: About to send" << endl;
319 lock_guard<mutex> guard(socketMutex);
320 sendSocketFlag = true;
321 communicationSocket->sendData(packetData, len);
322 sendSocketFlag = false;
326 // Worker function which runs the while loop for receiving data from the bulb.
328 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
330 // Need timeout on receives since we are not sure if a packet will be available
331 // for processing so don't block waiting
332 llb->communicationSocket->setTimeOut(50000); // In milliseconds
335 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
339 // Check if we got the bulb version yet
340 // could have requested it but message could have gotten lost (UDP)
341 if (!llb->didGetBulbVersion) {
342 int64_t currentTime = (int64_t) time(NULL);
343 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
344 // Get the bulb version so we know what type of bulb this is.
345 //cout << "Sending version packet! " << endl;
346 llb->sendGetVersionPacket();
347 lastSentGetBulbVersionRequest = currentTime;
351 // Communication resource is busy so try again later
352 if (llb->sendSocketFlag) {
356 llb->socketMutex.lock();
357 int ret = llb->communicationSocket->receiveData(dat, 1024);
358 // Never forget to release!
359 llb->socketMutex.unlock();
363 llb->receivedPacket(dat);
366 // If a state change occurred then request the bulb state to ensure that the
367 // bulb did indeed change its state to the correct state
368 if (llb->stateDidChange) {
369 llb->sendGetLightStatePacket();
372 // Wait a bit as to not tie up system resources
373 //this_thread::sleep_for (chrono::milliseconds(100));
375 //cout << endl << "Sleep and wake up!" << endl;
382 void LifxLightBulb::sendGetServicePacket() {
385 header.setTagged(true);
386 header.setMacAddress(bulbMacAddress);
387 header.setSource(0); // randomly picked
388 header.setAck_required(false);
389 header.setRes_required(false);
390 header.setSequence(0);
394 header.getHeaderBytes(dataBytes);
396 sendPacket(dataBytes, 36);
400 void LifxLightBulb::sendGetHostInfoPacket() {
403 header.setTagged(false);
404 header.setMacAddress(bulbMacAddress);
405 header.setSource(10); // randomly picked
406 header.setAck_required(false);
407 header.setRes_required(false);
408 header.setSequence(0);
412 header.getHeaderBytes(dataBytes);
414 sendPacket(dataBytes, 36);
418 void LifxLightBulb::sendGetHostFirmwarePacket() {
421 header.setTagged(false);
422 header.setMacAddress(bulbMacAddress);
423 header.setSource(10); // randomly picked
424 header.setAck_required(false);
425 header.setRes_required(false);
426 header.setSequence(0);
430 header.getHeaderBytes(dataBytes);
432 sendPacket(dataBytes, 36);
436 void LifxLightBulb::sendGetWifiInfoPacket() {
439 header.setTagged(false);
440 header.setMacAddress(bulbMacAddress);
441 header.setSource(10); // randomly picked
442 header.setAck_required(false);
443 header.setRes_required(false);
444 header.setSequence(0);
448 header.getHeaderBytes(dataBytes);
450 sendPacket(dataBytes, 36);
454 void LifxLightBulb::sendGetWifiFirmwarePacket() {
457 header.setTagged(false);
458 header.setMacAddress(bulbMacAddress);
459 header.setSource(10); // randomly picked
460 header.setAck_required(false);
461 header.setRes_required(false);
462 header.setSequence(0);
466 header.getHeaderBytes(dataBytes);
468 sendPacket(dataBytes, 36);
472 void LifxLightBulb::sendGetPowerPacket() {
475 header.setTagged(false);
476 header.setMacAddress(bulbMacAddress);
477 header.setSource(10); // randomly picked
478 header.setAck_required(false);
479 header.setRes_required(false);
480 header.setSequence(0);
484 header.getHeaderBytes(dataBytes);
486 sendPacket(dataBytes, 36);
490 void LifxLightBulb::sendSetPowerPacket(int level) {
491 // Currently only 0 and 65535 are supported
492 // This is a fix for now
493 if ((level != 65535) && (level != 0)) {
494 cerr << "Invalid parameter values" << endl;
498 if ((level > 65535) || (level < 0)) {
499 cerr << "Invalid parameter values" << endl;
503 char packetBytes[38];
507 header.setTagged(false);
508 header.setMacAddress(bulbMacAddress);
509 header.setSource(10); // randomly picked
510 header.setAck_required(false);
511 header.setRes_required(false);
512 header.setSequence(0);
514 char headerBytes[36];
515 header.getHeaderBytes(headerBytes);
517 for (int i = 0; i < 36; i++) {
518 packetBytes[i] = headerBytes[i];
521 packetBytes[36] = (char)(level & 0xFF);
522 packetBytes[37] = (char)((level >> 8) & 0xFF);
524 sendPacket(packetBytes, 38);
528 void LifxLightBulb::sendGetLabelPacket() {
531 header.setTagged(false);
532 header.setMacAddress(bulbMacAddress);
533 header.setSource(10); // randomly picked
534 header.setAck_required(false);
535 header.setRes_required(false);
536 header.setSequence(0);
540 header.getHeaderBytes(dataBytes);
542 sendPacket(dataBytes, 36);
546 void LifxLightBulb::sendSetLabelPacket(string label) {
547 // Currently only 0 and 65535 are supported
548 // This is a fix for now
549 if (label.length() != 32) {
550 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
554 char packetBytes[68];
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);
565 char headerBytes[36];
566 header.getHeaderBytes(headerBytes);
568 for (int i = 0; i < 36; i++) {
569 packetBytes[i] = headerBytes[i];
572 for (int i = 0; i < 32; i++) {
573 packetBytes[i + 36] = label.c_str()[i];
576 sendPacket(packetBytes, 68);
580 void LifxLightBulb::sendGetVersionPacket() {
583 header.setTagged(false);
584 header.setMacAddress(bulbMacAddress);
585 header.setSource(10); // randomly picked
586 header.setAck_required(false);
587 header.setRes_required(false);
588 header.setSequence(0);
592 header.getHeaderBytes(dataBytes);
594 sendPacket(dataBytes, 36);
598 void LifxLightBulb::sendGetInfoPacket() {
601 header.setTagged(false);
602 header.setMacAddress(bulbMacAddress);
603 header.setSource(10); // randomly picked
604 header.setAck_required(false);
605 header.setRes_required(false);
606 header.setSequence(0);
610 header.getHeaderBytes(dataBytes);
612 sendPacket(dataBytes, 36);
616 void LifxLightBulb::sendGetLocationPacket() {
619 header.setTagged(false);
620 header.setMacAddress(bulbMacAddress);
621 header.setSource(10); // randomly picked
622 header.setAck_required(false);
623 header.setRes_required(false);
624 header.setSequence(0);
628 header.getHeaderBytes(dataBytes);
630 sendPacket(dataBytes, 36);
634 void LifxLightBulb::sendGetGroupPacket() {
637 header.setTagged(false);
638 header.setMacAddress(bulbMacAddress);
639 header.setSource(10); // randomly picked
640 header.setAck_required(false);
641 header.setRes_required(false);
642 header.setSequence(0);
646 header.getHeaderBytes(dataBytes);
648 sendPacket(dataBytes, 36);
654 void LifxLightBulb::sendGetLightStatePacket() {
657 header.setTagged(false);
658 header.setMacAddress(bulbMacAddress);
659 header.setSource(10); // randomly picked
660 header.setAck_required(false);
661 header.setRes_required(false);
662 header.setSequence(0);
666 header.getHeaderBytes(dataBytes);
668 sendPacket(dataBytes, 36);
672 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
674 if ((duration > 4294967295l) || (duration < 0)) {
675 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
679 char packetBytes[49];
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);
690 char headerBytes[36];
691 header.getHeaderBytes(headerBytes);
693 for (int i = 0; i < 36; i++) {
694 packetBytes[i] = headerBytes[i];
698 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
699 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
701 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
702 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
704 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
705 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
707 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
708 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
710 packetBytes[45] = (char)((duration >> 0) & 0xFF);
711 packetBytes[46] = (char)((duration >> 8) & 0xFF);
712 packetBytes[47] = (char)((duration >> 16) & 0xFF);
713 packetBytes[48] = (char)((duration >> 24) & 0xFF);
715 sendPacket(packetBytes, 49);
716 // Avoid memory leak - delete object
721 void LifxLightBulb::sendGetLightPowerPacket() {
724 header.setTagged(false);
725 header.setMacAddress(bulbMacAddress);
726 header.setSource(10); // randomly picked
727 header.setAck_required(false);
728 header.setRes_required(false);
729 header.setSequence(0);
733 header.getHeaderBytes(dataBytes);
735 sendPacket(dataBytes, 36);
739 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
741 if ((level > 65535) || (duration > 4294967295l)
742 || (level < 0) || (duration < 0)) {
743 cerr << "Invalid parameter values" << endl;
746 char packetBytes[42];
750 header.setTagged(false);
751 header.setMacAddress(bulbMacAddress);
752 header.setSource(10); // randomly picked
753 header.setAck_required(false);
754 header.setRes_required(false);
755 header.setSequence(0);
757 char headerBytes[36];
758 header.getHeaderBytes(headerBytes);
760 for (int i = 0; i < 36; i++) {
761 packetBytes[i] = headerBytes[i];
764 packetBytes[36] = (char)(level & 0xFF);
765 packetBytes[37] = (char)((level >> 8) & 0xFF);
767 packetBytes[38] = (char)((duration >> 0) & 0xFF);
768 packetBytes[39] = (char)((duration >> 8) & 0xFF);
769 packetBytes[40] = (char)((duration >> 16) & 0xFF);
770 packetBytes[41] = (char)((duration >> 24) & 0xFF);
772 sendPacket(packetBytes, 42);
776 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
778 char packetBytes[100];
782 header.setTagged(false);
783 header.setMacAddress(bulbMacAddress);
784 header.setSource(10); // randomly picked
785 header.setAck_required(false);
786 header.setRes_required(false);
787 header.setSequence(0);
789 char headerBytes[36];
790 header.getHeaderBytes(headerBytes);
792 for (int i = 0; i < 36; i++) {
793 packetBytes[i] = headerBytes[i];
796 for (int i = 0; i < 64; i++) {
797 packetBytes[i + 36] = data[i];
800 sendPacket(packetBytes, 100);
806 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
807 int service = payloadData[0];
808 int64_t port = ((payloadData[3] & 0xFF) << 24);
809 port |= ((payloadData[2] & 0xFF) << 16);
810 port |= ((payloadData[1] & 0xFF) << 8);
811 port |= (payloadData[0] & 0xFF);
813 return new DeviceStateService(service, port);
817 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
818 long signal = ((payloadData[3] & 0xFF) << 24);
819 signal |= ((payloadData[2] & 0xFF) << 16);
820 signal |= ((payloadData[1] & 0xFF) << 8);
821 signal |= (payloadData[0] & 0xFF);
823 long tx = ((payloadData[7] & 0xFF) << 24);
824 tx |= ((payloadData[6] & 0xFF) << 16);
825 tx |= ((payloadData[5] & 0xFF) << 8);
826 tx |= (payloadData[4] & 0xFF);
828 long rx = ((payloadData[11] & 0xFF) << 24);
829 rx |= ((payloadData[10] & 0xFF) << 16);
830 rx |= ((payloadData[9] & 0xFF) << 8);
831 rx |= (payloadData[8] & 0xFF);
833 return new DeviceStateHostInfo(signal, tx, rx);
837 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
839 for (int i = 0; i < 8; i++) {
840 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
845 int64_t version = ((payloadData[19] & 0xFF) << 24);
846 version |= ((payloadData[18] & 0xFF) << 16);
847 version |= ((payloadData[17] & 0xFF) << 8);
848 version |= (payloadData[16] & 0xFF);
850 return new DeviceStateHostFirmware(build, version);
854 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
855 int64_t signal = ((payloadData[3] & 0xFF) << 24);
856 signal |= ((payloadData[2] & 0xFF) << 16);
857 signal |= ((payloadData[1] & 0xFF) << 8);
858 signal |= (payloadData[0] & 0xFF);
860 int64_t tx = ((payloadData[7] & 0xFF) << 24);
861 tx |= ((payloadData[6] & 0xFF) << 16);
862 tx |= ((payloadData[5] & 0xFF) << 8);
863 tx |= (payloadData[4] & 0xFF);
865 int64_t rx = ((payloadData[11] & 0xFF) << 24);
866 rx |= ((payloadData[10] & 0xFF) << 16);
867 rx |= ((payloadData[9] & 0xFF) << 8);
868 rx |= (payloadData[8] & 0xFF);
870 return new DeviceStateWifiInfo(signal, tx, rx);
874 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
876 for (int i = 0; i < 8; i++) {
877 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
882 int64_t version = ((payloadData[19] & 0xFF) << 24);
883 version |= ((payloadData[18] & 0xFF) << 16);
884 version |= ((payloadData[17] & 0xFF) << 8);
885 version |= (payloadData[16] & 0xFF);
887 return new DeviceStateWifiFirmware(build, version);
891 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
892 int level = ((payloadData[1] & 0xFF) << 8);
893 level |= (payloadData[0] & 0xFF);
898 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
899 int64_t vender = ((payloadData[3] & 0xFF) << 24);
900 vender |= ((payloadData[2] & 0xFF) << 16);
901 vender |= ((payloadData[1] & 0xFF) << 8);
902 vender |= (payloadData[0] & 0xFF);
904 int64_t product = ((payloadData[7] & 0xFF) << 24);
905 product |= ((payloadData[6] & 0xFF) << 16);
906 product |= ((payloadData[5] & 0xFF) << 8);
907 product |= (payloadData[4] & 0xFF);
909 int64_t version = ((payloadData[11] & 0xFF) << 24);
910 version |= ((payloadData[10] & 0xFF) << 16);
911 version |= ((payloadData[9] & 0xFF) << 8);
912 version |= (payloadData[8] & 0xFF);
914 return new DeviceStateVersion(vender, product, version);
918 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
921 int64_t downTime = 0;
922 for (int i = 0; i < 8; i++) {
923 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
924 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
925 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
928 return new DeviceStateInfo(time, upTime, downTime);
932 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
934 for (int i = 0; i < 16; i++) {
935 location[i] = payloadData[i];
939 for (int i = 0; i < 32; i++) {
940 labelBytes[i] = payloadData[i + 16];
943 int64_t updatedAt = 0;
944 for (int i = 0; i < 8; i++) {
945 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
948 string str(labelBytes);
949 return new DeviceStateLocation(location, str, updatedAt);
953 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
955 for (int i = 0; i < 16; i++) {
956 group[i] = payloadData[i];
960 for (int i = 0; i < 32; i++) {
961 labelBytes[i] = payloadData[i + 16];
964 int64_t updatedAt = 0;
965 for (int i = 0; i < 8; i++) {
966 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
969 string str(labelBytes);
970 return new DeviceStateGroup(group, str, updatedAt);
976 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
979 for (int i = 0; i < 8; i++) {
980 colorData[i] = payloadData[i];
982 //BulbColor color(colorData);
983 BulbColor* color = new BulbColor(colorData);
985 int power = ((payloadData[11] & 0xFF) << 8);
986 power |= (payloadData[10] & 0xFF);
988 string label(payloadData);
991 for (int i = 0; i < 32; i++) {
992 labelArray[i] = payloadData[12 + i];
995 return new LightState(color, power, label);
999 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1000 int level = ((payloadData[1] & 0xFF) << 8);
1001 level |= (payloadData[0] & 0xFF);
1007 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1009 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1010 int productNumber = (int)deviceState->getProduct();
1012 bool isColor = false;
1014 if (productNumber == 1) {// Original 1000
1016 } else if (productNumber == 3) {//Color 650
1018 } else if (productNumber == 10) {// White 800 (Low Voltage)
1020 } else if (productNumber == 11) {// White 800 (High Voltage)
1022 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1024 } else if (productNumber == 20) {// Color 1000 BR30
1026 } else if (productNumber == 22) {// Color 1000
1032 hueUpperBound = 65535;
1033 saturationLowerBound = 0;
1034 saturationUpperBound = 65535;
1035 brightnessLowerBound = 0;
1036 brightnessUpperBound = 65535;
1037 temperatureLowerBound = 2500;
1038 temperatureUpperBound = 9000;
1042 saturationLowerBound = 0;
1043 saturationUpperBound = 0;
1044 brightnessLowerBound = 0;
1045 brightnessUpperBound = 65535;// still can dim bulb
1046 temperatureLowerBound = 2500;
1047 temperatureUpperBound = 9000;
1050 //didGetBulbVersion.exchange(true);
1051 didGetBulbVersion = true;
1052 // Avoid memory leak - delete this object
1057 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1058 LightState* lightState = parseLightStateMessage(payloadData);
1060 BulbColor* color = lightState->getColor();
1061 int power = lightState->getPower();
1063 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1064 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1065 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1066 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1068 bool bulbWrongColor = false;
1069 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1070 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1071 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1072 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1075 // gets set to true if any of the below if statements are taken
1076 stateDidChange = false;
1078 if (bulbWrongColor) {
1079 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1080 sendSetLightColorPacket(newColor, 250);
1081 //cout << "Failed Check 1" << endl;
1084 bulbStateMutex.lock();
1085 bool bulbIsOnTmp = bulbIsOn;
1086 bulbStateMutex.unlock();
1088 if ((!bulbIsOnTmp) && (power != 0)) {
1090 //cout << "Failed Check 2: " << endl;
1094 if (bulbIsOnTmp && (power < 65530)) {
1096 //cout << "Failed Check 3: " << endl;
1099 // Avoid memory leak - delete object