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;
77 // Initialize the lightbulb
78 void LifxLightBulb::init() {
80 if (didAlreadyInit.exchange(true))
83 unordered_set<IoTDeviceAddress*>::const_iterator itr = lb_addresses.begin();
84 IoTDeviceAddress* deviceAddress = *itr;
85 cout << "Address: " << deviceAddress->getAddress() << endl;
87 // Create IoTUDP socket
88 communicationSocket = new IoTUDP(deviceAddress);
90 cout << "Host address: " << communicationSocket->getHostAddress() << endl;
91 cout << "Source port: " << communicationSocket->getSourcePort() << endl;
92 cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
94 // Launch the worker function in a separate thread.
95 // NOTE: "this" pointer is passed into the detached thread because it does not belong
96 // to this object anymore so if it executes certain methods of "this" object, then it needs
97 // the correct references to stuff
98 thread th1 (&LifxLightBulb::workerFunction, this, this);
101 cout << "Initialized LifxLightBulb!" << endl;
105 void LifxLightBulb::turnOff() {
107 //lock_guard<mutex> guard(bulbStateMutex);
108 bulbStateMutex.lock();
110 sendSetLightPowerPacket(0, 0);
111 stateDidChange = true;
112 bulbStateMutex.unlock();
116 void LifxLightBulb::turnOn() {
118 //lock_guard<mutex> guard(bulbStateMutex);
119 bulbStateMutex.lock();
121 sendSetLightPowerPacket(65535, 0);
122 stateDidChange = true;
123 bulbStateMutex.unlock();
127 double LifxLightBulb::getHue() {
129 settingBulbColorMutex.lock();
130 tmp = ((double)currentHue / 65535.0) * 360.0;
131 settingBulbColorMutex.unlock();
137 double LifxLightBulb::getSaturation() {
139 settingBulbColorMutex.lock();
140 tmp = ((double)currentSaturation / 65535.0) * 360.0;
141 settingBulbColorMutex.unlock();
147 double LifxLightBulb::getBrightness() {
149 settingBulbColorMutex.lock();
150 tmp = ((double)currentBrightness / 65535.0) * 360.0;
151 settingBulbColorMutex.unlock();
157 int LifxLightBulb::getTemperature() {
160 settingBulbTemperatureMutex.lock();
161 tmp = currentTemperature;
162 settingBulbTemperatureMutex.unlock();
168 double LifxLightBulb::getHueRangeLowerBound() {
169 if (!didGetBulbVersion) {
172 return ((double)hueLowerBound / 65535.0) * 360.0;
176 double LifxLightBulb::getHueRangeUpperBound() {
177 if (!didGetBulbVersion) {
180 return ((double)hueUpperBound / 65535.0) * 360.0;
184 double LifxLightBulb::getSaturationRangeLowerBound() {
185 if (!didGetBulbVersion) {
188 return ((double)saturationLowerBound / 65535.0) * 100.0;
192 double LifxLightBulb::getSaturationRangeUpperBound() {
193 if (!didGetBulbVersion) {
196 return ((double)saturationUpperBound / 65535.0) * 100.0;
200 double LifxLightBulb::getBrightnessRangeLowerBound() {
201 if (!didGetBulbVersion) {
204 return ((double)brightnessLowerBound / 65535.0) * 100.0;
208 double LifxLightBulb::getBrightnessRangeUpperBound() {
209 if (!didGetBulbVersion) {
212 return ((double)brightnessUpperBound / 65535.0) * 100.0;
216 int LifxLightBulb::getTemperatureRangeLowerBound() {
217 if (!didGetBulbVersion) {
220 return temperatureLowerBound;
224 int LifxLightBulb::getTemperatureRangeUpperBound() {
225 if (!didGetBulbVersion) {
228 return temperatureUpperBound;
232 void LifxLightBulb::setTemperature(int _temperature) {
234 settingBulbTemperatureMutex.lock();
236 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
237 sendSetLightColorPacket(newColor, 250);
239 currentTemperature = _temperature;
240 stateDidChange = true;
242 settingBulbTemperatureMutex.unlock();
246 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
248 settingBulbColorMutex.lock();
251 _saturation /= 100.0;
252 _brightness /= 100.0;
255 int newHue = (int)(_hue * 65535.0);
256 int newSaturation = (int)(_saturation * 65535.0);
257 int newBrightness = (int)(_brightness * 65535.0);
259 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
260 sendSetLightColorPacket(newColor, 250);
263 currentSaturation = newSaturation;
264 currentBrightness = newBrightness;
265 stateDidChange = true;
267 settingBulbColorMutex.unlock();
271 bool LifxLightBulb::getState() {
275 bulbStateMutex.lock();
277 bulbStateMutex.unlock();
284 // Communication helpers
285 void LifxLightBulb::receivedPacket(char* packetData) {
287 char headerBytes[36];
288 for (int i = 0; i < 36; i++) {
289 headerBytes[i] = packetData[i];
292 LifxHeader recHeader;
293 recHeader.setFromBytes(headerBytes);
295 // load the payload bytes (strip away the header)
296 //char payloadBytes[recHeader.getSize()];
297 char* payloadBytes = new char[recHeader.getSize()];
298 for (int i = 36; i < recHeader.getSize(); i++) {
299 payloadBytes[i - 36] = packetData[i];
302 int type = recHeader.getType();
303 cout << "Received: " << type << endl;
305 DeviceStateService* dat = NULL;
309 dat = parseDeviceStateServiceMessage(payloadBytes);
310 cout << "Service: " << dat->getService();
311 cout << "Port : " << dat->getPort();
312 // Avoid memory leak - delete this object
317 handleStateVersionMessageReceived(payloadBytes);
321 parseDeviceStateInfoMessage(payloadBytes);
326 handleLightStateMessageReceived(payloadBytes);
330 cout << "unknown packet Type" << endl;
332 // Avoid memory leaks
337 void LifxLightBulb::sendPacket(char* packetData, int len) {
338 //cout << "sendPacket: About to send" << endl;
339 lock_guard<mutex> guard(socketMutex);
340 sendSocketFlag = true;
341 communicationSocket->sendData(packetData, len);
342 sendSocketFlag = false;
346 // Worker function which runs the while loop for receiving data from the bulb.
348 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
350 // Need timeout on receives since we are not sure if a packet will be available
351 // for processing so don't block waiting
352 llb->communicationSocket->setTimeOut(50000); // In milliseconds
356 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
360 // Check if we got the bulb version yet
361 // could have requested it but message could have gotten lost (UDP)
362 if (!llb->didGetBulbVersion) {
363 int64_t currentTime = (int64_t) time(NULL);
364 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
365 // Get the bulb version so we know what type of bulb this is.
366 cout << "Sending version packet! " << endl;
367 llb->sendGetVersionPacket();
368 lastSentGetBulbVersionRequest = currentTime;
372 // Communication resource is busy so try again later
373 if (llb->sendSocketFlag) {
377 llb->socketMutex.lock();
378 int ret = llb->communicationSocket->receiveData(dat, 1024);
379 // Never forget to release!
380 llb->socketMutex.unlock();
384 llb->receivedPacket(dat);
387 // If a state change occurred then request the bulb state to ensure that the
388 // bulb did indeed change its state to the correct state
389 if (llb->stateDidChange) {
390 llb->sendGetLightStatePacket();
393 // Wait a bit as to not tie up system resources
394 this_thread::sleep_for (chrono::milliseconds(100));
395 //cout << endl << "Sleep and wake up!" << endl;
402 void LifxLightBulb::sendGetServicePacket() {
405 header.setTagged(true);
406 header.setMacAddress(bulbMacAddress);
407 header.setSource(0); // randomly picked
408 header.setAck_required(false);
409 header.setRes_required(false);
410 header.setSequence(0);
414 header.getHeaderBytes(dataBytes);
416 sendPacket(dataBytes, 36);
420 void LifxLightBulb::sendGetHostInfoPacket() {
423 header.setTagged(false);
424 header.setMacAddress(bulbMacAddress);
425 header.setSource(10); // randomly picked
426 header.setAck_required(false);
427 header.setRes_required(false);
428 header.setSequence(0);
432 header.getHeaderBytes(dataBytes);
434 sendPacket(dataBytes, 36);
438 void LifxLightBulb::sendGetHostFirmwarePacket() {
441 header.setTagged(false);
442 header.setMacAddress(bulbMacAddress);
443 header.setSource(10); // randomly picked
444 header.setAck_required(false);
445 header.setRes_required(false);
446 header.setSequence(0);
450 header.getHeaderBytes(dataBytes);
452 sendPacket(dataBytes, 36);
456 void LifxLightBulb::sendGetWifiInfoPacket() {
459 header.setTagged(false);
460 header.setMacAddress(bulbMacAddress);
461 header.setSource(10); // randomly picked
462 header.setAck_required(false);
463 header.setRes_required(false);
464 header.setSequence(0);
468 header.getHeaderBytes(dataBytes);
470 sendPacket(dataBytes, 36);
474 void LifxLightBulb::sendGetWifiFirmwarePacket() {
477 header.setTagged(false);
478 header.setMacAddress(bulbMacAddress);
479 header.setSource(10); // randomly picked
480 header.setAck_required(false);
481 header.setRes_required(false);
482 header.setSequence(0);
486 header.getHeaderBytes(dataBytes);
488 sendPacket(dataBytes, 36);
492 void LifxLightBulb::sendGetPowerPacket() {
495 header.setTagged(false);
496 header.setMacAddress(bulbMacAddress);
497 header.setSource(10); // randomly picked
498 header.setAck_required(false);
499 header.setRes_required(false);
500 header.setSequence(0);
504 header.getHeaderBytes(dataBytes);
506 sendPacket(dataBytes, 36);
510 void LifxLightBulb::sendSetPowerPacket(int level) {
511 // Currently only 0 and 65535 are supported
512 // This is a fix for now
513 if ((level != 65535) && (level != 0)) {
514 cerr << "Invalid parameter values" << endl;
518 if ((level > 65535) || (level < 0)) {
519 cerr << "Invalid parameter values" << endl;
523 char packetBytes[38];
527 header.setTagged(false);
528 header.setMacAddress(bulbMacAddress);
529 header.setSource(10); // randomly picked
530 header.setAck_required(false);
531 header.setRes_required(false);
532 header.setSequence(0);
534 char headerBytes[36];
535 header.getHeaderBytes(headerBytes);
537 for (int i = 0; i < 36; i++) {
538 packetBytes[i] = headerBytes[i];
541 packetBytes[36] = (char)(level & 0xFF);
542 packetBytes[37] = (char)((level >> 8) & 0xFF);
544 sendPacket(packetBytes, 38);
548 void LifxLightBulb::sendGetLabelPacket() {
551 header.setTagged(false);
552 header.setMacAddress(bulbMacAddress);
553 header.setSource(10); // randomly picked
554 header.setAck_required(false);
555 header.setRes_required(false);
556 header.setSequence(0);
560 header.getHeaderBytes(dataBytes);
562 sendPacket(dataBytes, 36);
566 void LifxLightBulb::sendSetLabelPacket(string label) {
567 // Currently only 0 and 65535 are supported
568 // This is a fix for now
569 if (label.length() != 32) {
570 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
574 char packetBytes[68];
578 header.setTagged(false);
579 header.setMacAddress(bulbMacAddress);
580 header.setSource(10); // randomly picked
581 header.setAck_required(false);
582 header.setRes_required(false);
583 header.setSequence(0);
585 char headerBytes[36];
586 header.getHeaderBytes(headerBytes);
588 for (int i = 0; i < 36; i++) {
589 packetBytes[i] = headerBytes[i];
592 for (int i = 0; i < 32; i++) {
593 packetBytes[i + 36] = label.c_str()[i];
596 sendPacket(packetBytes, 68);
600 void LifxLightBulb::sendGetVersionPacket() {
603 header.setTagged(false);
604 header.setMacAddress(bulbMacAddress);
605 header.setSource(10); // randomly picked
606 header.setAck_required(false);
607 header.setRes_required(false);
608 header.setSequence(0);
612 header.getHeaderBytes(dataBytes);
614 sendPacket(dataBytes, 36);
618 void LifxLightBulb::sendGetInfoPacket() {
621 header.setTagged(false);
622 header.setMacAddress(bulbMacAddress);
623 header.setSource(10); // randomly picked
624 header.setAck_required(false);
625 header.setRes_required(false);
626 header.setSequence(0);
630 header.getHeaderBytes(dataBytes);
632 sendPacket(dataBytes, 36);
636 void LifxLightBulb::sendGetLocationPacket() {
639 header.setTagged(false);
640 header.setMacAddress(bulbMacAddress);
641 header.setSource(10); // randomly picked
642 header.setAck_required(false);
643 header.setRes_required(false);
644 header.setSequence(0);
648 header.getHeaderBytes(dataBytes);
650 sendPacket(dataBytes, 36);
654 void LifxLightBulb::sendGetGroupPacket() {
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);
674 void LifxLightBulb::sendGetLightStatePacket() {
677 header.setTagged(false);
678 header.setMacAddress(bulbMacAddress);
679 header.setSource(10); // randomly picked
680 header.setAck_required(false);
681 header.setRes_required(false);
682 header.setSequence(0);
686 header.getHeaderBytes(dataBytes);
688 sendPacket(dataBytes, 36);
692 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
694 if ((duration > 4294967295l) || (duration < 0)) {
695 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
699 char packetBytes[49];
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);
710 char headerBytes[36];
711 header.getHeaderBytes(headerBytes);
713 for (int i = 0; i < 36; i++) {
714 packetBytes[i] = headerBytes[i];
718 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
719 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
721 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
722 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
724 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
725 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
727 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
728 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
730 packetBytes[45] = (char)((duration >> 0) & 0xFF);
731 packetBytes[46] = (char)((duration >> 8) & 0xFF);
732 packetBytes[47] = (char)((duration >> 16) & 0xFF);
733 packetBytes[48] = (char)((duration >> 24) & 0xFF);
735 sendPacket(packetBytes, 49);
736 // Avoid memory leak - delete object
741 void LifxLightBulb::sendGetLightPowerPacket() {
744 header.setTagged(false);
745 header.setMacAddress(bulbMacAddress);
746 header.setSource(10); // randomly picked
747 header.setAck_required(false);
748 header.setRes_required(false);
749 header.setSequence(0);
753 header.getHeaderBytes(dataBytes);
755 sendPacket(dataBytes, 36);
759 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
761 if ((level > 65535) || (duration > 4294967295l)
762 || (level < 0) || (duration < 0)) {
763 cerr << "Invalid parameter values" << endl;
767 char packetBytes[42];
772 header.setTagged(false);
773 header.setMacAddress(bulbMacAddress);
774 header.setSource(10); // randomly picked
775 header.setAck_required(false);
776 header.setRes_required(false);
777 header.setSequence(0);
779 char headerBytes[36];
780 header.getHeaderBytes(headerBytes);
782 for (int i = 0; i < 36; i++) {
783 packetBytes[i] = headerBytes[i];
786 packetBytes[36] = (char)(level & 0xFF);
787 packetBytes[37] = (char)((level >> 8) & 0xFF);
789 packetBytes[38] = (char)((duration >> 0) & 0xFF);
790 packetBytes[39] = (char)((duration >> 8) & 0xFF);
791 packetBytes[40] = (char)((duration >> 16) & 0xFF);
792 packetBytes[41] = (char)((duration >> 24) & 0xFF);
794 sendPacket(packetBytes, 42);
798 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
800 char packetBytes[100];
804 header.setTagged(false);
805 header.setMacAddress(bulbMacAddress);
806 header.setSource(10); // randomly picked
807 header.setAck_required(false);
808 header.setRes_required(false);
809 header.setSequence(0);
811 char headerBytes[36];
812 header.getHeaderBytes(headerBytes);
814 for (int i = 0; i < 36; i++) {
815 packetBytes[i] = headerBytes[i];
818 for (int i = 0; i < 64; i++) {
819 packetBytes[i + 36] = data[i];
822 sendPacket(packetBytes, 100);
828 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
829 int service = payloadData[0];
830 int64_t port = ((payloadData[3] & 0xFF) << 24);
831 port |= ((payloadData[2] & 0xFF) << 16);
832 port |= ((payloadData[1] & 0xFF) << 8);
833 port |= (payloadData[0] & 0xFF);
835 return new DeviceStateService(service, port);
839 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
840 long signal = ((payloadData[3] & 0xFF) << 24);
841 signal |= ((payloadData[2] & 0xFF) << 16);
842 signal |= ((payloadData[1] & 0xFF) << 8);
843 signal |= (payloadData[0] & 0xFF);
845 long tx = ((payloadData[7] & 0xFF) << 24);
846 tx |= ((payloadData[6] & 0xFF) << 16);
847 tx |= ((payloadData[5] & 0xFF) << 8);
848 tx |= (payloadData[4] & 0xFF);
850 long rx = ((payloadData[11] & 0xFF) << 24);
851 rx |= ((payloadData[10] & 0xFF) << 16);
852 rx |= ((payloadData[9] & 0xFF) << 8);
853 rx |= (payloadData[8] & 0xFF);
855 return new DeviceStateHostInfo(signal, tx, rx);
859 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
861 for (int i = 0; i < 8; i++) {
862 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
867 int64_t version = ((payloadData[19] & 0xFF) << 24);
868 version |= ((payloadData[18] & 0xFF) << 16);
869 version |= ((payloadData[17] & 0xFF) << 8);
870 version |= (payloadData[16] & 0xFF);
872 return new DeviceStateHostFirmware(build, version);
876 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
877 int64_t signal = ((payloadData[3] & 0xFF) << 24);
878 signal |= ((payloadData[2] & 0xFF) << 16);
879 signal |= ((payloadData[1] & 0xFF) << 8);
880 signal |= (payloadData[0] & 0xFF);
882 int64_t tx = ((payloadData[7] & 0xFF) << 24);
883 tx |= ((payloadData[6] & 0xFF) << 16);
884 tx |= ((payloadData[5] & 0xFF) << 8);
885 tx |= (payloadData[4] & 0xFF);
887 int64_t rx = ((payloadData[11] & 0xFF) << 24);
888 rx |= ((payloadData[10] & 0xFF) << 16);
889 rx |= ((payloadData[9] & 0xFF) << 8);
890 rx |= (payloadData[8] & 0xFF);
892 return new DeviceStateWifiInfo(signal, tx, rx);
896 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
898 for (int i = 0; i < 8; i++) {
899 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
904 int64_t version = ((payloadData[19] & 0xFF) << 24);
905 version |= ((payloadData[18] & 0xFF) << 16);
906 version |= ((payloadData[17] & 0xFF) << 8);
907 version |= (payloadData[16] & 0xFF);
909 return new DeviceStateWifiFirmware(build, version);
913 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
914 int level = ((payloadData[1] & 0xFF) << 8);
915 level |= (payloadData[0] & 0xFF);
920 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
921 int64_t vender = ((payloadData[3] & 0xFF) << 24);
922 vender |= ((payloadData[2] & 0xFF) << 16);
923 vender |= ((payloadData[1] & 0xFF) << 8);
924 vender |= (payloadData[0] & 0xFF);
926 int64_t product = ((payloadData[7] & 0xFF) << 24);
927 product |= ((payloadData[6] & 0xFF) << 16);
928 product |= ((payloadData[5] & 0xFF) << 8);
929 product |= (payloadData[4] & 0xFF);
931 int64_t version = ((payloadData[11] & 0xFF) << 24);
932 version |= ((payloadData[10] & 0xFF) << 16);
933 version |= ((payloadData[9] & 0xFF) << 8);
934 version |= (payloadData[8] & 0xFF);
936 return new DeviceStateVersion(vender, product, version);
940 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
943 int64_t downTime = 0;
944 for (int i = 0; i < 8; i++) {
945 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
946 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
947 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
950 return new DeviceStateInfo(time, upTime, downTime);
954 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
956 for (int i = 0; i < 16; i++) {
957 location[i] = payloadData[i];
961 for (int i = 0; i < 32; i++) {
962 labelBytes[i] = payloadData[i + 16];
965 int64_t updatedAt = 0;
966 for (int i = 0; i < 8; i++) {
967 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
970 string str(labelBytes);
971 return new DeviceStateLocation(location, str, updatedAt);
975 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
977 for (int i = 0; i < 16; i++) {
978 group[i] = payloadData[i];
982 for (int i = 0; i < 32; i++) {
983 labelBytes[i] = payloadData[i + 16];
986 int64_t updatedAt = 0;
987 for (int i = 0; i < 8; i++) {
988 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
991 string str(labelBytes);
992 return new DeviceStateGroup(group, str, updatedAt);
998 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1001 for (int i = 0; i < 8; i++) {
1002 colorData[i] = payloadData[i];
1004 //BulbColor color(colorData);
1005 BulbColor* color = new BulbColor(colorData);
1007 int power = ((payloadData[11] & 0xFF) << 8);
1008 power |= (payloadData[10] & 0xFF);
1010 string label(payloadData);
1012 char labelArray[32];
1013 for (int i = 0; i < 32; i++) {
1014 labelArray[i] = payloadData[12 + i];
1017 return new LightState(color, power, label);
1021 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1022 int level = ((payloadData[1] & 0xFF) << 8);
1023 level |= (payloadData[0] & 0xFF);
1029 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1031 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1032 int productNumber = (int)deviceState->getProduct();
1034 bool isColor = false;
1036 if (productNumber == 1) {// Original 1000
1038 } else if (productNumber == 3) {//Color 650
1040 } else if (productNumber == 10) {// White 800 (Low Voltage)
1042 } else if (productNumber == 11) {// White 800 (High Voltage)
1044 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1046 } else if (productNumber == 20) {// Color 1000 BR30
1048 } else if (productNumber == 22) {// Color 1000
1054 hueUpperBound = 65535;
1055 saturationLowerBound = 0;
1056 saturationUpperBound = 65535;
1057 brightnessLowerBound = 0;
1058 brightnessUpperBound = 65535;
1059 temperatureLowerBound = 2500;
1060 temperatureUpperBound = 9000;
1064 saturationLowerBound = 0;
1065 saturationUpperBound = 0;
1066 brightnessLowerBound = 0;
1067 brightnessUpperBound = 65535;// still can dim bulb
1068 temperatureLowerBound = 2500;
1069 temperatureUpperBound = 9000;
1072 didGetBulbVersion.exchange(true);
1073 // Avoid memory leak - delete this object
1078 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1079 LightState* lightState = parseLightStateMessage(payloadData);
1081 BulbColor* color = lightState->getColor();
1082 int power = lightState->getPower();
1084 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1085 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1086 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1087 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1089 bool bulbWrongColor = false;
1090 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1091 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1092 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1093 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1096 // gets set to true if any of the below if statements are taken
1097 stateDidChange = false;
1099 if (bulbWrongColor) {
1100 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1101 sendSetLightColorPacket(newColor, 250);
1102 //cout << "Failed Check 1" << endl;
1105 bulbStateMutex.lock();
1106 bool bulbIsOnTmp = bulbIsOn;
1107 bulbStateMutex.unlock();
1109 if ((!bulbIsOnTmp) && (power != 0)) {
1111 //cout << "Failed Check 2: " << endl;
1115 if (bulbIsOnTmp && (power < 65530)) {
1117 //cout << "Failed Check 3: " << endl;
1120 // Avoid memory leak - delete object
1126 // Functions for the main function
1127 void run(LifxLightBulb *llb) {
1133 void onOff(LifxLightBulb *llb) {
1135 for (int i = 0; i < 5; i++) {
1137 cout << "Turning off!" << endl;
1138 this_thread::sleep_for (chrono::milliseconds(1000));
1140 cout << "Turning on!" << endl;
1141 this_thread::sleep_for (chrono::milliseconds(1000));
1146 void adjustTemp(LifxLightBulb *llb) {
1148 for (int i = 2500; i < 9000; i += 100) {
1149 cout << "Adjusting Temp: " << i << endl;
1150 llb->setTemperature(i);
1151 this_thread::sleep_for (chrono::milliseconds(100));
1153 cout << "Adjusted temperature to 9000!" << endl;
1154 for (int i = 9000; i > 2500; i -= 100) {
1155 cout << "Adjusting Temp: " << i << endl;
1156 llb->setTemperature(i);
1157 this_thread::sleep_for (chrono::milliseconds(100));
1159 cout << "Adjusted temperature to 2500!" << endl;
1163 void adjustBright(LifxLightBulb *llb) {
1164 for (int i = 100; i > 0; i -= 10) {
1165 cout << "Adjusting Brightness: " << i << endl;
1166 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1167 this_thread::sleep_for (chrono::milliseconds(100));
1169 cout << "Adjusted brightness to 0!" << endl;
1170 for (int i = 0; i < 100; i += 10) {
1171 cout << "Adjusting Brightness: " << i << endl;
1172 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1173 this_thread::sleep_for (chrono::milliseconds(100));
1175 cout << "Adjusting brightness to 100!" << endl;
1179 int main(int argc, char *argv[])
1181 string macAddress = "D073D5128E300000";
1182 //string macAddress = "D073D50241DA0000";
1183 string devIPAddress = "192.168.2.126";
1184 //string devIPAddress = "192.168.2.232";
1185 //IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false);
1186 IoTDeviceAddress* devAddress = new IoTDeviceAddress(devIPAddress, 12345, 56700, false, false);
1187 unordered_set<IoTDeviceAddress*> myset = { devAddress };
1189 IoTSet<IoTDeviceAddress*> setDevAddress(myset);
1190 LifxLightBulb *llb = new LifxLightBulb(setDevAddress, macAddress);
1191 cout << "Generated LifxLightBulb object!" << endl;