7 #include "LifxLightBulb.hpp"
9 #include "IoTDeviceAddress.hpp"
13 // External creator/destroyer
14 /*extern "C" LifxLightBulb* create(IoTSet<IoTDeviceAddress*>* _devAddress, string macAddress) {
15 return new LifxLightBulb(_devAddress, macAddress);
18 extern "C" void destroy(LifxLightBulb* t) {
23 LifxLightBulb::LifxLightBulb() {
24 // LB1 macAddress: d0:73:d5:12:8e:30
25 // LB1 macAddress: d0:73:d5:02:41:da
26 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
27 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
28 /*bulbMacAddress[0] = 0xD0;
29 bulbMacAddress[1] = 0x73;
30 bulbMacAddress[2] = 0xD5;
31 bulbMacAddress[3] = 0x02;
32 bulbMacAddress[4] = 0x41;
33 bulbMacAddress[5] = 0xDA;
34 bulbMacAddress[6] = 0x00;
35 bulbMacAddress[7] = 0x00;*/
37 char tmpMacAddress[16];
38 strcpy(tmpMacAddress, macAddress.c_str());
39 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
40 for(int i=0; i<16; i=i+2) {
41 // Take 2 digits and then convert
43 tmpMacByte[0] = tmpMacAddress[i];
44 tmpMacByte[1] = tmpMacAddress[i+1];
45 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
47 //IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
51 LifxLightBulb::LifxLightBulb(IoTSet<IoTDeviceAddress*>* _devAddress, string macAddress) {
53 // Initialize macAddress
54 char tmpMacAddress[16];
55 strcpy(tmpMacAddress, macAddress.c_str());
56 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
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);
64 cout << "MAC address is set. Value: ";
65 IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
67 // Initialize device address
68 lb_addresses = _devAddress;
69 cout << "Device address is set! " << endl;
73 LifxLightBulb::~LifxLightBulb() {
76 if (communicationSocket != NULL) {
78 delete communicationSocket;
79 communicationSocket = NULL;
81 for(IoTDeviceAddress* dev : *lb_addresses) {
85 if (lb_addresses != NULL) {
94 // Initialize the lightbulb
95 void LifxLightBulb::init() {
97 if (didAlreadyInit.exchange(true))
100 unordered_set<IoTDeviceAddress*>::const_iterator itr = lb_addresses->begin();
101 IoTDeviceAddress* deviceAddress = *itr;
102 cout << "Address: " << deviceAddress->getAddress() << endl;
104 // Create IoTUDP socket
105 communicationSocket = new IoTUDP(deviceAddress);
107 cout << "Host address: " << communicationSocket->getHostAddress() << endl;
108 cout << "Source port: " << communicationSocket->getSourcePort() << endl;
109 cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
111 // Launch the worker function in a separate thread.
112 // NOTE: "this" pointer is passed into the detached thread because it does not belong
113 // to this object anymore so if it executes certain methods of "this" object, then it needs
114 // the correct references to stuff
115 thread th1 (&LifxLightBulb::workerFunction, this, this);
118 cout << "Initialized LifxLightBulb!" << endl;
122 void LifxLightBulb::turnOff() {
124 //lock_guard<mutex> guard(bulbStateMutex);
125 bulbStateMutex.lock();
127 sendSetLightPowerPacket(0, 0);
128 stateDidChange = true;
129 bulbStateMutex.unlock();
133 void LifxLightBulb::turnOn() {
135 //lock_guard<mutex> guard(bulbStateMutex);
136 bulbStateMutex.lock();
138 sendSetLightPowerPacket(65535, 0);
139 stateDidChange = true;
140 bulbStateMutex.unlock();
144 double LifxLightBulb::getHue() {
146 settingBulbColorMutex.lock();
147 tmp = ((double)currentHue / 65535.0) * 360.0;
148 settingBulbColorMutex.unlock();
154 double LifxLightBulb::getSaturation() {
156 settingBulbColorMutex.lock();
157 tmp = ((double)currentSaturation / 65535.0) * 360.0;
158 settingBulbColorMutex.unlock();
164 double LifxLightBulb::getBrightness() {
166 settingBulbColorMutex.lock();
167 tmp = ((double)currentBrightness / 65535.0) * 360.0;
168 settingBulbColorMutex.unlock();
174 int LifxLightBulb::getTemperature() {
177 settingBulbTemperatureMutex.lock();
178 tmp = currentTemperature;
179 settingBulbTemperatureMutex.unlock();
185 double LifxLightBulb::getHueRangeLowerBound() {
186 if (!didGetBulbVersion) {
189 return ((double)hueLowerBound / 65535.0) * 360.0;
193 double LifxLightBulb::getHueRangeUpperBound() {
194 if (!didGetBulbVersion) {
197 return ((double)hueUpperBound / 65535.0) * 360.0;
201 double LifxLightBulb::getSaturationRangeLowerBound() {
202 if (!didGetBulbVersion) {
205 return ((double)saturationLowerBound / 65535.0) * 100.0;
209 double LifxLightBulb::getSaturationRangeUpperBound() {
210 if (!didGetBulbVersion) {
213 return ((double)saturationUpperBound / 65535.0) * 100.0;
217 double LifxLightBulb::getBrightnessRangeLowerBound() {
218 if (!didGetBulbVersion) {
221 return ((double)brightnessLowerBound / 65535.0) * 100.0;
225 double LifxLightBulb::getBrightnessRangeUpperBound() {
226 if (!didGetBulbVersion) {
229 return ((double)brightnessUpperBound / 65535.0) * 100.0;
233 int LifxLightBulb::getTemperatureRangeLowerBound() {
234 if (!didGetBulbVersion) {
237 return temperatureLowerBound;
241 int LifxLightBulb::getTemperatureRangeUpperBound() {
242 if (!didGetBulbVersion) {
245 return temperatureUpperBound;
249 void LifxLightBulb::setTemperature(int _temperature) {
251 settingBulbTemperatureMutex.lock();
253 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
254 sendSetLightColorPacket(newColor, 250);
256 currentTemperature = _temperature;
257 stateDidChange = true;
259 settingBulbTemperatureMutex.unlock();
263 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
265 settingBulbColorMutex.lock();
268 _saturation /= 100.0;
269 _brightness /= 100.0;
272 int newHue = (int)(_hue * 65535.0);
273 int newSaturation = (int)(_saturation * 65535.0);
274 int newBrightness = (int)(_brightness * 65535.0);
276 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
277 sendSetLightColorPacket(newColor, 250);
280 currentSaturation = newSaturation;
281 currentBrightness = newBrightness;
282 stateDidChange = true;
284 settingBulbColorMutex.unlock();
288 bool LifxLightBulb::getState() {
292 bulbStateMutex.lock();
294 bulbStateMutex.unlock();
301 // Communication helpers
302 void LifxLightBulb::receivedPacket(char* packetData) {
304 char headerBytes[36];
305 for (int i = 0; i < 36; i++) {
306 headerBytes[i] = packetData[i];
309 LifxHeader recHeader;
310 recHeader.setFromBytes(headerBytes);
312 // load the payload bytes (strip away the header)
313 //char payloadBytes[recHeader.getSize()];
314 char* payloadBytes = new char[recHeader.getSize()];
315 for (int i = 36; i < recHeader.getSize(); i++) {
316 payloadBytes[i - 36] = packetData[i];
319 int type = recHeader.getType();
320 cout << "Received: " << type << endl;
322 DeviceStateService* dat = NULL;
326 dat = parseDeviceStateServiceMessage(payloadBytes);
327 cout << "Service: " << dat->getService();
328 cout << "Port : " << dat->getPort();
329 // Avoid memory leak - delete this object
334 handleStateVersionMessageReceived(payloadBytes);
338 parseDeviceStateInfoMessage(payloadBytes);
343 handleLightStateMessageReceived(payloadBytes);
347 cout << "unknown packet Type" << endl;
349 // Avoid memory leaks
354 void LifxLightBulb::sendPacket(char* packetData, int len) {
355 //cout << "sendPacket: About to send" << endl;
356 lock_guard<mutex> guard(socketMutex);
357 sendSocketFlag = true;
358 communicationSocket->sendData(packetData, len);
359 sendSocketFlag = false;
363 // Worker function which runs the while loop for receiving data from the bulb.
365 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
367 // Need timeout on receives since we are not sure if a packet will be available
368 // for processing so don't block waiting
369 llb->communicationSocket->setTimeOut(50000); // In milliseconds
373 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
377 // Check if we got the bulb version yet
378 // could have requested it but message could have gotten lost (UDP)
379 if (!llb->didGetBulbVersion) {
380 int64_t currentTime = (int64_t) time(NULL);
381 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
382 // Get the bulb version so we know what type of bulb this is.
383 cout << "Sending version packet! " << endl;
384 llb->sendGetVersionPacket();
385 lastSentGetBulbVersionRequest = currentTime;
389 // Communication resource is busy so try again later
390 if (llb->sendSocketFlag) {
394 llb->socketMutex.lock();
395 int ret = llb->communicationSocket->receiveData(dat, 1024);
396 // Never forget to release!
397 llb->socketMutex.unlock();
401 llb->receivedPacket(dat);
404 // If a state change occurred then request the bulb state to ensure that the
405 // bulb did indeed change its state to the correct state
406 if (llb->stateDidChange) {
407 llb->sendGetLightStatePacket();
410 // Wait a bit as to not tie up system resources
411 this_thread::sleep_for (chrono::milliseconds(100));
412 //cout << endl << "Sleep and wake up!" << endl;
419 void LifxLightBulb::sendGetServicePacket() {
422 header.setTagged(true);
423 header.setMacAddress(bulbMacAddress);
424 header.setSource(0); // randomly picked
425 header.setAck_required(false);
426 header.setRes_required(false);
427 header.setSequence(0);
431 header.getHeaderBytes(dataBytes);
433 sendPacket(dataBytes, 36);
437 void LifxLightBulb::sendGetHostInfoPacket() {
440 header.setTagged(false);
441 header.setMacAddress(bulbMacAddress);
442 header.setSource(10); // randomly picked
443 header.setAck_required(false);
444 header.setRes_required(false);
445 header.setSequence(0);
449 header.getHeaderBytes(dataBytes);
451 sendPacket(dataBytes, 36);
455 void LifxLightBulb::sendGetHostFirmwarePacket() {
458 header.setTagged(false);
459 header.setMacAddress(bulbMacAddress);
460 header.setSource(10); // randomly picked
461 header.setAck_required(false);
462 header.setRes_required(false);
463 header.setSequence(0);
467 header.getHeaderBytes(dataBytes);
469 sendPacket(dataBytes, 36);
473 void LifxLightBulb::sendGetWifiInfoPacket() {
476 header.setTagged(false);
477 header.setMacAddress(bulbMacAddress);
478 header.setSource(10); // randomly picked
479 header.setAck_required(false);
480 header.setRes_required(false);
481 header.setSequence(0);
485 header.getHeaderBytes(dataBytes);
487 sendPacket(dataBytes, 36);
491 void LifxLightBulb::sendGetWifiFirmwarePacket() {
494 header.setTagged(false);
495 header.setMacAddress(bulbMacAddress);
496 header.setSource(10); // randomly picked
497 header.setAck_required(false);
498 header.setRes_required(false);
499 header.setSequence(0);
503 header.getHeaderBytes(dataBytes);
505 sendPacket(dataBytes, 36);
509 void LifxLightBulb::sendGetPowerPacket() {
512 header.setTagged(false);
513 header.setMacAddress(bulbMacAddress);
514 header.setSource(10); // randomly picked
515 header.setAck_required(false);
516 header.setRes_required(false);
517 header.setSequence(0);
521 header.getHeaderBytes(dataBytes);
523 sendPacket(dataBytes, 36);
527 void LifxLightBulb::sendSetPowerPacket(int level) {
528 // Currently only 0 and 65535 are supported
529 // This is a fix for now
530 if ((level != 65535) && (level != 0)) {
531 cerr << "Invalid parameter values" << endl;
535 if ((level > 65535) || (level < 0)) {
536 cerr << "Invalid parameter values" << endl;
540 char packetBytes[38];
544 header.setTagged(false);
545 header.setMacAddress(bulbMacAddress);
546 header.setSource(10); // randomly picked
547 header.setAck_required(false);
548 header.setRes_required(false);
549 header.setSequence(0);
551 char headerBytes[36];
552 header.getHeaderBytes(headerBytes);
554 for (int i = 0; i < 36; i++) {
555 packetBytes[i] = headerBytes[i];
558 packetBytes[36] = (char)(level & 0xFF);
559 packetBytes[37] = (char)((level >> 8) & 0xFF);
561 sendPacket(packetBytes, 38);
565 void LifxLightBulb::sendGetLabelPacket() {
568 header.setTagged(false);
569 header.setMacAddress(bulbMacAddress);
570 header.setSource(10); // randomly picked
571 header.setAck_required(false);
572 header.setRes_required(false);
573 header.setSequence(0);
577 header.getHeaderBytes(dataBytes);
579 sendPacket(dataBytes, 36);
583 void LifxLightBulb::sendSetLabelPacket(string label) {
584 // Currently only 0 and 65535 are supported
585 // This is a fix for now
586 if (label.length() != 32) {
587 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
591 char packetBytes[68];
595 header.setTagged(false);
596 header.setMacAddress(bulbMacAddress);
597 header.setSource(10); // randomly picked
598 header.setAck_required(false);
599 header.setRes_required(false);
600 header.setSequence(0);
602 char headerBytes[36];
603 header.getHeaderBytes(headerBytes);
605 for (int i = 0; i < 36; i++) {
606 packetBytes[i] = headerBytes[i];
609 for (int i = 0; i < 32; i++) {
610 packetBytes[i + 36] = label.c_str()[i];
613 sendPacket(packetBytes, 68);
617 void LifxLightBulb::sendGetVersionPacket() {
620 header.setTagged(false);
621 header.setMacAddress(bulbMacAddress);
622 header.setSource(10); // randomly picked
623 header.setAck_required(false);
624 header.setRes_required(false);
625 header.setSequence(0);
629 header.getHeaderBytes(dataBytes);
631 sendPacket(dataBytes, 36);
635 void LifxLightBulb::sendGetInfoPacket() {
638 header.setTagged(false);
639 header.setMacAddress(bulbMacAddress);
640 header.setSource(10); // randomly picked
641 header.setAck_required(false);
642 header.setRes_required(false);
643 header.setSequence(0);
647 header.getHeaderBytes(dataBytes);
649 sendPacket(dataBytes, 36);
653 void LifxLightBulb::sendGetLocationPacket() {
656 header.setTagged(false);
657 header.setMacAddress(bulbMacAddress);
658 header.setSource(10); // randomly picked
659 header.setAck_required(false);
660 header.setRes_required(false);
661 header.setSequence(0);
665 header.getHeaderBytes(dataBytes);
667 sendPacket(dataBytes, 36);
671 void LifxLightBulb::sendGetGroupPacket() {
674 header.setTagged(false);
675 header.setMacAddress(bulbMacAddress);
676 header.setSource(10); // randomly picked
677 header.setAck_required(false);
678 header.setRes_required(false);
679 header.setSequence(0);
683 header.getHeaderBytes(dataBytes);
685 sendPacket(dataBytes, 36);
691 void LifxLightBulb::sendGetLightStatePacket() {
694 header.setTagged(false);
695 header.setMacAddress(bulbMacAddress);
696 header.setSource(10); // randomly picked
697 header.setAck_required(false);
698 header.setRes_required(false);
699 header.setSequence(0);
703 header.getHeaderBytes(dataBytes);
705 sendPacket(dataBytes, 36);
709 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
711 if ((duration > 4294967295l) || (duration < 0)) {
712 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
716 char packetBytes[49];
720 header.setTagged(false);
721 header.setMacAddress(bulbMacAddress);
722 header.setSource(10); // randomly picked
723 header.setAck_required(false);
724 header.setRes_required(false);
725 header.setSequence(0);
727 char headerBytes[36];
728 header.getHeaderBytes(headerBytes);
730 for (int i = 0; i < 36; i++) {
731 packetBytes[i] = headerBytes[i];
735 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
736 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
738 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
739 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
741 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
742 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
744 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
745 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
747 packetBytes[45] = (char)((duration >> 0) & 0xFF);
748 packetBytes[46] = (char)((duration >> 8) & 0xFF);
749 packetBytes[47] = (char)((duration >> 16) & 0xFF);
750 packetBytes[48] = (char)((duration >> 24) & 0xFF);
752 sendPacket(packetBytes, 49);
753 // Avoid memory leak - delete object
758 void LifxLightBulb::sendGetLightPowerPacket() {
761 header.setTagged(false);
762 header.setMacAddress(bulbMacAddress);
763 header.setSource(10); // randomly picked
764 header.setAck_required(false);
765 header.setRes_required(false);
766 header.setSequence(0);
770 header.getHeaderBytes(dataBytes);
772 sendPacket(dataBytes, 36);
776 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
778 if ((level > 65535) || (duration > 4294967295l)
779 || (level < 0) || (duration < 0)) {
780 cerr << "Invalid parameter values" << endl;
784 char packetBytes[42];
789 header.setTagged(false);
790 header.setMacAddress(bulbMacAddress);
791 header.setSource(10); // randomly picked
792 header.setAck_required(false);
793 header.setRes_required(false);
794 header.setSequence(0);
796 char headerBytes[36];
797 header.getHeaderBytes(headerBytes);
799 for (int i = 0; i < 36; i++) {
800 packetBytes[i] = headerBytes[i];
803 packetBytes[36] = (char)(level & 0xFF);
804 packetBytes[37] = (char)((level >> 8) & 0xFF);
806 packetBytes[38] = (char)((duration >> 0) & 0xFF);
807 packetBytes[39] = (char)((duration >> 8) & 0xFF);
808 packetBytes[40] = (char)((duration >> 16) & 0xFF);
809 packetBytes[41] = (char)((duration >> 24) & 0xFF);
811 sendPacket(packetBytes, 42);
815 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
817 char packetBytes[100];
821 header.setTagged(false);
822 header.setMacAddress(bulbMacAddress);
823 header.setSource(10); // randomly picked
824 header.setAck_required(false);
825 header.setRes_required(false);
826 header.setSequence(0);
828 char headerBytes[36];
829 header.getHeaderBytes(headerBytes);
831 for (int i = 0; i < 36; i++) {
832 packetBytes[i] = headerBytes[i];
835 for (int i = 0; i < 64; i++) {
836 packetBytes[i + 36] = data[i];
839 sendPacket(packetBytes, 100);
845 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
846 int service = payloadData[0];
847 int64_t port = ((payloadData[3] & 0xFF) << 24);
848 port |= ((payloadData[2] & 0xFF) << 16);
849 port |= ((payloadData[1] & 0xFF) << 8);
850 port |= (payloadData[0] & 0xFF);
852 return new DeviceStateService(service, port);
856 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
857 long signal = ((payloadData[3] & 0xFF) << 24);
858 signal |= ((payloadData[2] & 0xFF) << 16);
859 signal |= ((payloadData[1] & 0xFF) << 8);
860 signal |= (payloadData[0] & 0xFF);
862 long tx = ((payloadData[7] & 0xFF) << 24);
863 tx |= ((payloadData[6] & 0xFF) << 16);
864 tx |= ((payloadData[5] & 0xFF) << 8);
865 tx |= (payloadData[4] & 0xFF);
867 long rx = ((payloadData[11] & 0xFF) << 24);
868 rx |= ((payloadData[10] & 0xFF) << 16);
869 rx |= ((payloadData[9] & 0xFF) << 8);
870 rx |= (payloadData[8] & 0xFF);
872 return new DeviceStateHostInfo(signal, tx, rx);
876 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
878 for (int i = 0; i < 8; i++) {
879 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
884 int64_t version = ((payloadData[19] & 0xFF) << 24);
885 version |= ((payloadData[18] & 0xFF) << 16);
886 version |= ((payloadData[17] & 0xFF) << 8);
887 version |= (payloadData[16] & 0xFF);
889 return new DeviceStateHostFirmware(build, version);
893 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
894 int64_t signal = ((payloadData[3] & 0xFF) << 24);
895 signal |= ((payloadData[2] & 0xFF) << 16);
896 signal |= ((payloadData[1] & 0xFF) << 8);
897 signal |= (payloadData[0] & 0xFF);
899 int64_t tx = ((payloadData[7] & 0xFF) << 24);
900 tx |= ((payloadData[6] & 0xFF) << 16);
901 tx |= ((payloadData[5] & 0xFF) << 8);
902 tx |= (payloadData[4] & 0xFF);
904 int64_t rx = ((payloadData[11] & 0xFF) << 24);
905 rx |= ((payloadData[10] & 0xFF) << 16);
906 rx |= ((payloadData[9] & 0xFF) << 8);
907 rx |= (payloadData[8] & 0xFF);
909 return new DeviceStateWifiInfo(signal, tx, rx);
913 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
915 for (int i = 0; i < 8; i++) {
916 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
921 int64_t version = ((payloadData[19] & 0xFF) << 24);
922 version |= ((payloadData[18] & 0xFF) << 16);
923 version |= ((payloadData[17] & 0xFF) << 8);
924 version |= (payloadData[16] & 0xFF);
926 return new DeviceStateWifiFirmware(build, version);
930 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
931 int level = ((payloadData[1] & 0xFF) << 8);
932 level |= (payloadData[0] & 0xFF);
937 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
938 int64_t vender = ((payloadData[3] & 0xFF) << 24);
939 vender |= ((payloadData[2] & 0xFF) << 16);
940 vender |= ((payloadData[1] & 0xFF) << 8);
941 vender |= (payloadData[0] & 0xFF);
943 int64_t product = ((payloadData[7] & 0xFF) << 24);
944 product |= ((payloadData[6] & 0xFF) << 16);
945 product |= ((payloadData[5] & 0xFF) << 8);
946 product |= (payloadData[4] & 0xFF);
948 int64_t version = ((payloadData[11] & 0xFF) << 24);
949 version |= ((payloadData[10] & 0xFF) << 16);
950 version |= ((payloadData[9] & 0xFF) << 8);
951 version |= (payloadData[8] & 0xFF);
953 return new DeviceStateVersion(vender, product, version);
957 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
960 int64_t downTime = 0;
961 for (int i = 0; i < 8; i++) {
962 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
963 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
964 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
967 return new DeviceStateInfo(time, upTime, downTime);
971 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
973 for (int i = 0; i < 16; i++) {
974 location[i] = payloadData[i];
978 for (int i = 0; i < 32; i++) {
979 labelBytes[i] = payloadData[i + 16];
982 int64_t updatedAt = 0;
983 for (int i = 0; i < 8; i++) {
984 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
987 string str(labelBytes);
988 return new DeviceStateLocation(location, str, updatedAt);
992 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
994 for (int i = 0; i < 16; i++) {
995 group[i] = payloadData[i];
999 for (int i = 0; i < 32; i++) {
1000 labelBytes[i] = payloadData[i + 16];
1003 int64_t updatedAt = 0;
1004 for (int i = 0; i < 8; i++) {
1005 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1008 string str(labelBytes);
1009 return new DeviceStateGroup(group, str, updatedAt);
1015 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1018 for (int i = 0; i < 8; i++) {
1019 colorData[i] = payloadData[i];
1021 //BulbColor color(colorData);
1022 BulbColor* color = new BulbColor(colorData);
1024 int power = ((payloadData[11] & 0xFF) << 8);
1025 power |= (payloadData[10] & 0xFF);
1027 string label(payloadData);
1029 char labelArray[32];
1030 for (int i = 0; i < 32; i++) {
1031 labelArray[i] = payloadData[12 + i];
1034 return new LightState(color, power, label);
1038 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1039 int level = ((payloadData[1] & 0xFF) << 8);
1040 level |= (payloadData[0] & 0xFF);
1046 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1048 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1049 int productNumber = (int)deviceState->getProduct();
1051 bool isColor = false;
1053 if (productNumber == 1) {// Original 1000
1055 } else if (productNumber == 3) {//Color 650
1057 } else if (productNumber == 10) {// White 800 (Low Voltage)
1059 } else if (productNumber == 11) {// White 800 (High Voltage)
1061 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1063 } else if (productNumber == 20) {// Color 1000 BR30
1065 } else if (productNumber == 22) {// Color 1000
1071 hueUpperBound = 65535;
1072 saturationLowerBound = 0;
1073 saturationUpperBound = 65535;
1074 brightnessLowerBound = 0;
1075 brightnessUpperBound = 65535;
1076 temperatureLowerBound = 2500;
1077 temperatureUpperBound = 9000;
1081 saturationLowerBound = 0;
1082 saturationUpperBound = 0;
1083 brightnessLowerBound = 0;
1084 brightnessUpperBound = 65535;// still can dim bulb
1085 temperatureLowerBound = 2500;
1086 temperatureUpperBound = 9000;
1089 didGetBulbVersion.exchange(true);
1090 // Avoid memory leak - delete this object
1095 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1096 LightState* lightState = parseLightStateMessage(payloadData);
1098 BulbColor* color = lightState->getColor();
1099 int power = lightState->getPower();
1101 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1102 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1103 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1104 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1106 bool bulbWrongColor = false;
1107 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1108 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1109 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1110 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1113 // gets set to true if any of the below if statements are taken
1114 stateDidChange = false;
1116 if (bulbWrongColor) {
1117 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1118 sendSetLightColorPacket(newColor, 250);
1119 //cout << "Failed Check 1" << endl;
1122 bulbStateMutex.lock();
1123 bool bulbIsOnTmp = bulbIsOn;
1124 bulbStateMutex.unlock();
1126 if ((!bulbIsOnTmp) && (power != 0)) {
1128 //cout << "Failed Check 2: " << endl;
1132 if (bulbIsOnTmp && (power < 65530)) {
1134 //cout << "Failed Check 3: " << endl;
1137 // Avoid memory leak - delete object
1143 // Functions for the main function
1144 void onOff(LifxLightBulb *llb) {
1146 for (int i = 0; i < 2; i++) {
1148 cout << "Turning off!" << endl;
1149 this_thread::sleep_for (chrono::milliseconds(1000));
1151 cout << "Turning on!" << endl;
1152 this_thread::sleep_for (chrono::milliseconds(1000));
1157 void adjustTemp(LifxLightBulb *llb) {
1159 for (int i = 2500; i < 9000; i += 100) {
1160 cout << "Adjusting Temp: " << i << endl;
1161 llb->setTemperature(i);
1162 this_thread::sleep_for (chrono::milliseconds(100));
1164 cout << "Adjusted temperature to 9000!" << endl;
1165 for (int i = 9000; i > 2500; i -= 100) {
1166 cout << "Adjusting Temp: " << i << endl;
1167 llb->setTemperature(i);
1168 this_thread::sleep_for (chrono::milliseconds(100));
1170 cout << "Adjusted temperature to 2500!" << endl;
1174 void adjustBright(LifxLightBulb *llb) {
1175 for (int i = 100; i > 0; i -= 10) {
1176 cout << "Adjusting Brightness: " << i << endl;
1177 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1178 this_thread::sleep_for (chrono::milliseconds(100));
1180 cout << "Adjusted brightness to 0!" << endl;
1181 for (int i = 0; i < 100; i += 10) {
1182 cout << "Adjusting Brightness: " << i << endl;
1183 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1184 this_thread::sleep_for (chrono::milliseconds(100));
1186 cout << "Adjusting brightness to 100!" << endl;
1190 /*int main(int argc, char *argv[])
1192 string macAddress = "D073D5128E300000";
1193 //string macAddress = "D073D50241DA0000";
1194 string devIPAddress = "192.168.2.126";
1195 //string devIPAddress = "192.168.2.232";
1196 //IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false);
1197 IoTDeviceAddress* devAddress = new IoTDeviceAddress(devIPAddress, 12345, 56700, false, false);
1198 unordered_set<IoTDeviceAddress*> myset = { devAddress };
1200 IoTSet<IoTDeviceAddress*> setDevAddress(myset);
1201 LifxLightBulb *llb = new LifxLightBulb(setDevAddress, macAddress);
1202 cout << "Generated LifxLightBulb object!" << endl;