7 #include "LifxLightBulb.hpp"
9 #include "IoTDeviceAddress.hpp"
14 // External functions to create, destroy and initialize this class object
15 extern "C" void* createLifxLightBulb(void** params) {
16 // Arguments: IoTSet<IoTDeviceAddress*>* _devAddress, string macAddress
17 return new LifxLightBulb((IoTSet<void*>*) params[0], *((string*) params[1]));
21 extern "C" void destroyLifxLightBulb(void* t) {
22 LifxLightBulb* llb = (LifxLightBulb*) t;
27 extern "C" void initLifxLightBulb(void* t) {
28 LifxLightBulb* llb = (LifxLightBulb*) t;
34 LifxLightBulb::LifxLightBulb() {
35 // LB1 macAddress: d0:73:d5:12:8e:30
36 // LB1 macAddress: d0:73:d5:02:41:da
37 string macAddress = "D073D5128E300000"; // bulbMacAddress: [-48, 115, -43, 18, -114, 48, 0, 0]
38 //string macAddress = "D073D50241DA0000"; // bulbMacAddress: [-48, 115, -43, 2, 65, -38, 0, 0]
39 /*bulbMacAddress[0] = 0xD0;
40 bulbMacAddress[1] = 0x73;
41 bulbMacAddress[2] = 0xD5;
42 bulbMacAddress[3] = 0x02;
43 bulbMacAddress[4] = 0x41;
44 bulbMacAddress[5] = 0xDA;
45 bulbMacAddress[6] = 0x00;
46 bulbMacAddress[7] = 0x00;*/
48 char tmpMacAddress[16];
49 strcpy(tmpMacAddress, macAddress.c_str());
50 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
51 for(int i=0; i<16; i=i+2) {
52 // Take 2 digits and then convert
54 tmpMacByte[0] = tmpMacAddress[i];
55 tmpMacByte[1] = tmpMacAddress[i+1];
56 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
58 //IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
62 // Driver constructor always gets a pointer to device address, trailed by class arguments of generic type
63 LifxLightBulb::LifxLightBulb(IoTSet<void*>* _devAddress, string macAddress) {
65 // Initialize macAddress
66 char tmpMacAddress[16];
67 strcpy(tmpMacAddress, macAddress.c_str());
68 //test[0] = (char) strtol(strTest.c_str(), NULL, 16);
69 for(int i=0; i<16; i=i+2) {
70 // Take 2 digits and then convert
72 tmpMacByte[0] = tmpMacAddress[i];
73 tmpMacByte[1] = tmpMacAddress[i+1];
74 bulbMacAddress[i/2] = (char) strtol(tmpMacByte, NULL, 16);
76 //cout << "MAC address is set. Value: ";
77 IoTRMIUtil::printBytes(bulbMacAddress, 8, false);
79 log.open("LifxLightBulb_cpp.log");
80 log << "MAC address is " << macAddress << endl;
82 // Initialize device address
83 lb_addresses = _devAddress;
84 //cout << "Device address is set! " << endl;
88 LifxLightBulb::~LifxLightBulb() {
91 if (communicationSocket != NULL) {
93 delete communicationSocket;
94 communicationSocket = NULL;
96 for(void* dev : *lb_addresses) {
97 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
101 if (lb_addresses != NULL) {
110 // Initialize the lightbulb
111 void LifxLightBulb::init() {
113 if (didAlreadyInit.exchange(true))
116 unordered_set<void*>::const_iterator itr = lb_addresses->begin();
117 IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
118 //cout << "Address: " << deviceAddress->getAddress() << endl;
119 log << "Address: " << deviceAddress->getAddress() << endl;
121 // Create IoTUDP socket
122 communicationSocket = new IoTUDP(deviceAddress);
124 //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
125 //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
126 //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
127 log << "Host address: " << communicationSocket->getHostAddress() << endl;
128 log << "Source port: " << communicationSocket->getSourcePort() << endl;
129 log << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
131 // Launch the worker function in a separate thread.
132 // NOTE: "this" pointer is passed into the detached thread because it does not belong
133 // to this object anymore so if it executes certain methods of "this" object, then it needs
134 // the correct references to stuff
135 thread th1 (&LifxLightBulb::workerFunction, this, this);
138 //cout << "Initialized LifxLightBulb!" << endl;
139 log << "Initialized LifxLightBulb!" << endl;
144 void LifxLightBulb::turnOff() {
146 //lock_guard<mutex> guard(bulbStateMutex);
147 bulbStateMutex.lock();
149 sendSetLightPowerPacket(0, 0);
150 stateDidChange = true;
151 bulbStateMutex.unlock();
155 void LifxLightBulb::turnOn() {
157 //lock_guard<mutex> guard(bulbStateMutex);
158 bulbStateMutex.lock();
160 sendSetLightPowerPacket(65535, 0);
161 stateDidChange = true;
162 bulbStateMutex.unlock();
166 double LifxLightBulb::getHue() {
168 settingBulbColorMutex.lock();
169 tmp = ((double)currentHue / 65535.0) * 360.0;
170 settingBulbColorMutex.unlock();
176 double LifxLightBulb::getSaturation() {
178 settingBulbColorMutex.lock();
179 tmp = ((double)currentSaturation / 65535.0) * 360.0;
180 settingBulbColorMutex.unlock();
186 double LifxLightBulb::getBrightness() {
188 settingBulbColorMutex.lock();
189 tmp = ((double)currentBrightness / 65535.0) * 360.0;
190 settingBulbColorMutex.unlock();
196 int LifxLightBulb::getTemperature() {
199 settingBulbTemperatureMutex.lock();
200 tmp = currentTemperature;
201 settingBulbTemperatureMutex.unlock();
207 double LifxLightBulb::getHueRangeLowerBound() {
208 if (!didGetBulbVersion) {
211 return ((double)hueLowerBound / 65535.0) * 360.0;
215 double LifxLightBulb::getHueRangeUpperBound() {
216 if (!didGetBulbVersion) {
219 return ((double)hueUpperBound / 65535.0) * 360.0;
223 double LifxLightBulb::getSaturationRangeLowerBound() {
224 if (!didGetBulbVersion) {
227 return ((double)saturationLowerBound / 65535.0) * 100.0;
231 double LifxLightBulb::getSaturationRangeUpperBound() {
232 if (!didGetBulbVersion) {
235 return ((double)saturationUpperBound / 65535.0) * 100.0;
239 double LifxLightBulb::getBrightnessRangeLowerBound() {
240 if (!didGetBulbVersion) {
243 return ((double)brightnessLowerBound / 65535.0) * 100.0;
247 double LifxLightBulb::getBrightnessRangeUpperBound() {
248 if (!didGetBulbVersion) {
251 return ((double)brightnessUpperBound / 65535.0) * 100.0;
255 int LifxLightBulb::getTemperatureRangeLowerBound() {
256 if (!didGetBulbVersion) {
259 return temperatureLowerBound;
263 int LifxLightBulb::getTemperatureRangeUpperBound() {
264 if (!didGetBulbVersion) {
267 return temperatureUpperBound;
271 void LifxLightBulb::setTemperature(int _temperature) {
273 settingBulbTemperatureMutex.lock();
275 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
276 sendSetLightColorPacket(newColor, 250);
278 currentTemperature = _temperature;
279 stateDidChange = true;
281 settingBulbTemperatureMutex.unlock();
285 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
287 settingBulbColorMutex.lock();
290 _saturation /= 100.0;
291 _brightness /= 100.0;
294 int newHue = (int)(_hue * 65535.0);
295 int newSaturation = (int)(_saturation * 65535.0);
296 int newBrightness = (int)(_brightness * 65535.0);
298 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
299 sendSetLightColorPacket(newColor, 250);
302 currentSaturation = newSaturation;
303 currentBrightness = newBrightness;
304 stateDidChange = true;
306 settingBulbColorMutex.unlock();
310 bool LifxLightBulb::getState() {
314 bulbStateMutex.lock();
316 bulbStateMutex.unlock();
323 // Communication helpers
324 void LifxLightBulb::receivedPacket(char* packetData) {
326 char headerBytes[36];
327 for (int i = 0; i < 36; i++) {
328 headerBytes[i] = packetData[i];
331 LifxHeader recHeader;
332 recHeader.setFromBytes(headerBytes);
334 // load the payload bytes (strip away the header)
335 //char payloadBytes[recHeader.getSize()];
336 char* payloadBytes = new char[recHeader.getSize()];
337 for (int i = 36; i < recHeader.getSize(); i++) {
338 payloadBytes[i - 36] = packetData[i];
341 int type = recHeader.getType();
342 //cout << "Received: " << type << endl;
344 DeviceStateService* dat = NULL;
348 dat = parseDeviceStateServiceMessage(payloadBytes);
349 //cout << "Service: " << dat->getService();
350 //cout << "Port : " << dat->getPort();
351 // Avoid memory leak - delete this object
356 handleStateVersionMessageReceived(payloadBytes);
360 parseDeviceStateInfoMessage(payloadBytes);
365 handleLightStateMessageReceived(payloadBytes);
370 //cout << "unknown packet Type" << endl;
372 // Avoid memory leaks
377 void LifxLightBulb::sendPacket(char* packetData, int len) {
378 //cout << "sendPacket: About to send" << endl;
379 lock_guard<mutex> guard(socketMutex);
380 sendSocketFlag = true;
381 communicationSocket->sendData(packetData, len);
382 sendSocketFlag = false;
386 // Worker function which runs the while loop for receiving data from the bulb.
388 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
390 // Need timeout on receives since we are not sure if a packet will be available
391 // for processing so don't block waiting
392 llb->communicationSocket->setTimeOut(50000); // In milliseconds
396 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
400 // Check if we got the bulb version yet
401 // could have requested it but message could have gotten lost (UDP)
402 if (!llb->didGetBulbVersion) {
403 int64_t currentTime = (int64_t) time(NULL);
404 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
405 // Get the bulb version so we know what type of bulb this is.
406 //cout << "Sending version packet! " << endl;
407 llb->sendGetVersionPacket();
408 lastSentGetBulbVersionRequest = currentTime;
412 // Communication resource is busy so try again later
413 if (llb->sendSocketFlag) {
417 llb->socketMutex.lock();
418 int ret = llb->communicationSocket->receiveData(dat, 1024);
419 // Never forget to release!
420 llb->socketMutex.unlock();
424 llb->receivedPacket(dat);
427 // If a state change occurred then request the bulb state to ensure that the
428 // bulb did indeed change its state to the correct state
429 if (llb->stateDidChange) {
430 llb->sendGetLightStatePacket();
433 // Wait a bit as to not tie up system resources
434 this_thread::sleep_for (chrono::milliseconds(100));
435 //cout << endl << "Sleep and wake up!" << endl;
442 void LifxLightBulb::sendGetServicePacket() {
445 header.setTagged(true);
446 header.setMacAddress(bulbMacAddress);
447 header.setSource(0); // randomly picked
448 header.setAck_required(false);
449 header.setRes_required(false);
450 header.setSequence(0);
454 header.getHeaderBytes(dataBytes);
456 sendPacket(dataBytes, 36);
460 void LifxLightBulb::sendGetHostInfoPacket() {
463 header.setTagged(false);
464 header.setMacAddress(bulbMacAddress);
465 header.setSource(10); // randomly picked
466 header.setAck_required(false);
467 header.setRes_required(false);
468 header.setSequence(0);
472 header.getHeaderBytes(dataBytes);
474 sendPacket(dataBytes, 36);
478 void LifxLightBulb::sendGetHostFirmwarePacket() {
481 header.setTagged(false);
482 header.setMacAddress(bulbMacAddress);
483 header.setSource(10); // randomly picked
484 header.setAck_required(false);
485 header.setRes_required(false);
486 header.setSequence(0);
490 header.getHeaderBytes(dataBytes);
492 sendPacket(dataBytes, 36);
496 void LifxLightBulb::sendGetWifiInfoPacket() {
499 header.setTagged(false);
500 header.setMacAddress(bulbMacAddress);
501 header.setSource(10); // randomly picked
502 header.setAck_required(false);
503 header.setRes_required(false);
504 header.setSequence(0);
508 header.getHeaderBytes(dataBytes);
510 sendPacket(dataBytes, 36);
514 void LifxLightBulb::sendGetWifiFirmwarePacket() {
517 header.setTagged(false);
518 header.setMacAddress(bulbMacAddress);
519 header.setSource(10); // randomly picked
520 header.setAck_required(false);
521 header.setRes_required(false);
522 header.setSequence(0);
526 header.getHeaderBytes(dataBytes);
528 sendPacket(dataBytes, 36);
532 void LifxLightBulb::sendGetPowerPacket() {
535 header.setTagged(false);
536 header.setMacAddress(bulbMacAddress);
537 header.setSource(10); // randomly picked
538 header.setAck_required(false);
539 header.setRes_required(false);
540 header.setSequence(0);
544 header.getHeaderBytes(dataBytes);
546 sendPacket(dataBytes, 36);
550 void LifxLightBulb::sendSetPowerPacket(int level) {
551 // Currently only 0 and 65535 are supported
552 // This is a fix for now
553 if ((level != 65535) && (level != 0)) {
554 cerr << "Invalid parameter values" << endl;
558 if ((level > 65535) || (level < 0)) {
559 cerr << "Invalid parameter values" << endl;
563 char packetBytes[38];
567 header.setTagged(false);
568 header.setMacAddress(bulbMacAddress);
569 header.setSource(10); // randomly picked
570 header.setAck_required(false);
571 header.setRes_required(false);
572 header.setSequence(0);
574 char headerBytes[36];
575 header.getHeaderBytes(headerBytes);
577 for (int i = 0; i < 36; i++) {
578 packetBytes[i] = headerBytes[i];
581 packetBytes[36] = (char)(level & 0xFF);
582 packetBytes[37] = (char)((level >> 8) & 0xFF);
584 sendPacket(packetBytes, 38);
588 void LifxLightBulb::sendGetLabelPacket() {
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);
600 header.getHeaderBytes(dataBytes);
602 sendPacket(dataBytes, 36);
606 void LifxLightBulb::sendSetLabelPacket(string label) {
607 // Currently only 0 and 65535 are supported
608 // This is a fix for now
609 if (label.length() != 32) {
610 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
614 char packetBytes[68];
618 header.setTagged(false);
619 header.setMacAddress(bulbMacAddress);
620 header.setSource(10); // randomly picked
621 header.setAck_required(false);
622 header.setRes_required(false);
623 header.setSequence(0);
625 char headerBytes[36];
626 header.getHeaderBytes(headerBytes);
628 for (int i = 0; i < 36; i++) {
629 packetBytes[i] = headerBytes[i];
632 for (int i = 0; i < 32; i++) {
633 packetBytes[i + 36] = label.c_str()[i];
636 sendPacket(packetBytes, 68);
640 void LifxLightBulb::sendGetVersionPacket() {
643 header.setTagged(false);
644 header.setMacAddress(bulbMacAddress);
645 header.setSource(10); // randomly picked
646 header.setAck_required(false);
647 header.setRes_required(false);
648 header.setSequence(0);
652 header.getHeaderBytes(dataBytes);
654 sendPacket(dataBytes, 36);
658 void LifxLightBulb::sendGetInfoPacket() {
661 header.setTagged(false);
662 header.setMacAddress(bulbMacAddress);
663 header.setSource(10); // randomly picked
664 header.setAck_required(false);
665 header.setRes_required(false);
666 header.setSequence(0);
670 header.getHeaderBytes(dataBytes);
672 sendPacket(dataBytes, 36);
676 void LifxLightBulb::sendGetLocationPacket() {
679 header.setTagged(false);
680 header.setMacAddress(bulbMacAddress);
681 header.setSource(10); // randomly picked
682 header.setAck_required(false);
683 header.setRes_required(false);
684 header.setSequence(0);
688 header.getHeaderBytes(dataBytes);
690 sendPacket(dataBytes, 36);
694 void LifxLightBulb::sendGetGroupPacket() {
697 header.setTagged(false);
698 header.setMacAddress(bulbMacAddress);
699 header.setSource(10); // randomly picked
700 header.setAck_required(false);
701 header.setRes_required(false);
702 header.setSequence(0);
706 header.getHeaderBytes(dataBytes);
708 sendPacket(dataBytes, 36);
714 void LifxLightBulb::sendGetLightStatePacket() {
717 header.setTagged(false);
718 header.setMacAddress(bulbMacAddress);
719 header.setSource(10); // randomly picked
720 header.setAck_required(false);
721 header.setRes_required(false);
722 header.setSequence(0);
726 header.getHeaderBytes(dataBytes);
728 sendPacket(dataBytes, 36);
732 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
734 if ((duration > 4294967295l) || (duration < 0)) {
735 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
739 char packetBytes[49];
743 header.setTagged(false);
744 header.setMacAddress(bulbMacAddress);
745 header.setSource(10); // randomly picked
746 header.setAck_required(false);
747 header.setRes_required(false);
748 header.setSequence(0);
750 char headerBytes[36];
751 header.getHeaderBytes(headerBytes);
753 for (int i = 0; i < 36; i++) {
754 packetBytes[i] = headerBytes[i];
758 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
759 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
761 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
762 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
764 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
765 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
767 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
768 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
770 packetBytes[45] = (char)((duration >> 0) & 0xFF);
771 packetBytes[46] = (char)((duration >> 8) & 0xFF);
772 packetBytes[47] = (char)((duration >> 16) & 0xFF);
773 packetBytes[48] = (char)((duration >> 24) & 0xFF);
775 sendPacket(packetBytes, 49);
776 // Avoid memory leak - delete object
781 void LifxLightBulb::sendGetLightPowerPacket() {
784 header.setTagged(false);
785 header.setMacAddress(bulbMacAddress);
786 header.setSource(10); // randomly picked
787 header.setAck_required(false);
788 header.setRes_required(false);
789 header.setSequence(0);
793 header.getHeaderBytes(dataBytes);
795 sendPacket(dataBytes, 36);
799 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
801 if ((level > 65535) || (duration > 4294967295l)
802 || (level < 0) || (duration < 0)) {
803 cerr << "Invalid parameter values" << endl;
807 char packetBytes[42];
812 header.setTagged(false);
813 header.setMacAddress(bulbMacAddress);
814 header.setSource(10); // randomly picked
815 header.setAck_required(false);
816 header.setRes_required(false);
817 header.setSequence(0);
819 char headerBytes[36];
820 header.getHeaderBytes(headerBytes);
822 for (int i = 0; i < 36; i++) {
823 packetBytes[i] = headerBytes[i];
826 packetBytes[36] = (char)(level & 0xFF);
827 packetBytes[37] = (char)((level >> 8) & 0xFF);
829 packetBytes[38] = (char)((duration >> 0) & 0xFF);
830 packetBytes[39] = (char)((duration >> 8) & 0xFF);
831 packetBytes[40] = (char)((duration >> 16) & 0xFF);
832 packetBytes[41] = (char)((duration >> 24) & 0xFF);
834 sendPacket(packetBytes, 42);
838 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
840 char packetBytes[100];
844 header.setTagged(false);
845 header.setMacAddress(bulbMacAddress);
846 header.setSource(10); // randomly picked
847 header.setAck_required(false);
848 header.setRes_required(false);
849 header.setSequence(0);
851 char headerBytes[36];
852 header.getHeaderBytes(headerBytes);
854 for (int i = 0; i < 36; i++) {
855 packetBytes[i] = headerBytes[i];
858 for (int i = 0; i < 64; i++) {
859 packetBytes[i + 36] = data[i];
862 sendPacket(packetBytes, 100);
868 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
869 int service = payloadData[0];
870 int64_t port = ((payloadData[3] & 0xFF) << 24);
871 port |= ((payloadData[2] & 0xFF) << 16);
872 port |= ((payloadData[1] & 0xFF) << 8);
873 port |= (payloadData[0] & 0xFF);
875 return new DeviceStateService(service, port);
879 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
880 long signal = ((payloadData[3] & 0xFF) << 24);
881 signal |= ((payloadData[2] & 0xFF) << 16);
882 signal |= ((payloadData[1] & 0xFF) << 8);
883 signal |= (payloadData[0] & 0xFF);
885 long tx = ((payloadData[7] & 0xFF) << 24);
886 tx |= ((payloadData[6] & 0xFF) << 16);
887 tx |= ((payloadData[5] & 0xFF) << 8);
888 tx |= (payloadData[4] & 0xFF);
890 long rx = ((payloadData[11] & 0xFF) << 24);
891 rx |= ((payloadData[10] & 0xFF) << 16);
892 rx |= ((payloadData[9] & 0xFF) << 8);
893 rx |= (payloadData[8] & 0xFF);
895 return new DeviceStateHostInfo(signal, tx, rx);
899 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
901 for (int i = 0; i < 8; i++) {
902 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
907 int64_t version = ((payloadData[19] & 0xFF) << 24);
908 version |= ((payloadData[18] & 0xFF) << 16);
909 version |= ((payloadData[17] & 0xFF) << 8);
910 version |= (payloadData[16] & 0xFF);
912 return new DeviceStateHostFirmware(build, version);
916 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
917 int64_t signal = ((payloadData[3] & 0xFF) << 24);
918 signal |= ((payloadData[2] & 0xFF) << 16);
919 signal |= ((payloadData[1] & 0xFF) << 8);
920 signal |= (payloadData[0] & 0xFF);
922 int64_t tx = ((payloadData[7] & 0xFF) << 24);
923 tx |= ((payloadData[6] & 0xFF) << 16);
924 tx |= ((payloadData[5] & 0xFF) << 8);
925 tx |= (payloadData[4] & 0xFF);
927 int64_t rx = ((payloadData[11] & 0xFF) << 24);
928 rx |= ((payloadData[10] & 0xFF) << 16);
929 rx |= ((payloadData[9] & 0xFF) << 8);
930 rx |= (payloadData[8] & 0xFF);
932 return new DeviceStateWifiInfo(signal, tx, rx);
936 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
938 for (int i = 0; i < 8; i++) {
939 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
944 int64_t version = ((payloadData[19] & 0xFF) << 24);
945 version |= ((payloadData[18] & 0xFF) << 16);
946 version |= ((payloadData[17] & 0xFF) << 8);
947 version |= (payloadData[16] & 0xFF);
949 return new DeviceStateWifiFirmware(build, version);
953 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
954 int level = ((payloadData[1] & 0xFF) << 8);
955 level |= (payloadData[0] & 0xFF);
960 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
961 int64_t vender = ((payloadData[3] & 0xFF) << 24);
962 vender |= ((payloadData[2] & 0xFF) << 16);
963 vender |= ((payloadData[1] & 0xFF) << 8);
964 vender |= (payloadData[0] & 0xFF);
966 int64_t product = ((payloadData[7] & 0xFF) << 24);
967 product |= ((payloadData[6] & 0xFF) << 16);
968 product |= ((payloadData[5] & 0xFF) << 8);
969 product |= (payloadData[4] & 0xFF);
971 int64_t version = ((payloadData[11] & 0xFF) << 24);
972 version |= ((payloadData[10] & 0xFF) << 16);
973 version |= ((payloadData[9] & 0xFF) << 8);
974 version |= (payloadData[8] & 0xFF);
976 return new DeviceStateVersion(vender, product, version);
980 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
983 int64_t downTime = 0;
984 for (int i = 0; i < 8; i++) {
985 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
986 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
987 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
990 return new DeviceStateInfo(time, upTime, downTime);
994 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
996 for (int i = 0; i < 16; i++) {
997 location[i] = payloadData[i];
1000 char labelBytes[32];
1001 for (int i = 0; i < 32; i++) {
1002 labelBytes[i] = payloadData[i + 16];
1005 int64_t updatedAt = 0;
1006 for (int i = 0; i < 8; i++) {
1007 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1010 string str(labelBytes);
1011 return new DeviceStateLocation(location, str, updatedAt);
1015 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1017 for (int i = 0; i < 16; i++) {
1018 group[i] = payloadData[i];
1021 char labelBytes[32];
1022 for (int i = 0; i < 32; i++) {
1023 labelBytes[i] = payloadData[i + 16];
1026 int64_t updatedAt = 0;
1027 for (int i = 0; i < 8; i++) {
1028 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1031 string str(labelBytes);
1032 return new DeviceStateGroup(group, str, updatedAt);
1038 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1041 for (int i = 0; i < 8; i++) {
1042 colorData[i] = payloadData[i];
1044 //BulbColor color(colorData);
1045 BulbColor* color = new BulbColor(colorData);
1047 int power = ((payloadData[11] & 0xFF) << 8);
1048 power |= (payloadData[10] & 0xFF);
1050 string label(payloadData);
1052 char labelArray[32];
1053 for (int i = 0; i < 32; i++) {
1054 labelArray[i] = payloadData[12 + i];
1057 return new LightState(color, power, label);
1061 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1062 int level = ((payloadData[1] & 0xFF) << 8);
1063 level |= (payloadData[0] & 0xFF);
1069 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1071 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1072 int productNumber = (int)deviceState->getProduct();
1074 bool isColor = false;
1076 if (productNumber == 1) {// Original 1000
1078 } else if (productNumber == 3) {//Color 650
1080 } else if (productNumber == 10) {// White 800 (Low Voltage)
1082 } else if (productNumber == 11) {// White 800 (High Voltage)
1084 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1086 } else if (productNumber == 20) {// Color 1000 BR30
1088 } else if (productNumber == 22) {// Color 1000
1094 hueUpperBound = 65535;
1095 saturationLowerBound = 0;
1096 saturationUpperBound = 65535;
1097 brightnessLowerBound = 0;
1098 brightnessUpperBound = 65535;
1099 temperatureLowerBound = 2500;
1100 temperatureUpperBound = 9000;
1104 saturationLowerBound = 0;
1105 saturationUpperBound = 0;
1106 brightnessLowerBound = 0;
1107 brightnessUpperBound = 65535;// still can dim bulb
1108 temperatureLowerBound = 2500;
1109 temperatureUpperBound = 9000;
1112 didGetBulbVersion.exchange(true);
1113 // Avoid memory leak - delete this object
1118 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1119 LightState* lightState = parseLightStateMessage(payloadData);
1121 BulbColor* color = lightState->getColor();
1122 int power = lightState->getPower();
1124 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1125 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1126 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1127 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1129 bool bulbWrongColor = false;
1130 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1131 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1132 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1133 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1136 // gets set to true if any of the below if statements are taken
1137 stateDidChange = false;
1139 if (bulbWrongColor) {
1140 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1141 sendSetLightColorPacket(newColor, 250);
1142 //cout << "Failed Check 1" << endl;
1145 bulbStateMutex.lock();
1146 bool bulbIsOnTmp = bulbIsOn;
1147 bulbStateMutex.unlock();
1149 if ((!bulbIsOnTmp) && (power != 0)) {
1151 //cout << "Failed Check 2: " << endl;
1155 if (bulbIsOnTmp && (power < 65530)) {
1157 //cout << "Failed Check 3: " << endl;
1160 // Avoid memory leak - delete object
1166 // Functions for the main function
1167 void onOff(LifxLightBulb *llb) {
1169 for (int i = 0; i < 2; i++) {
1171 //cout << "Turning off!" << endl;
1172 this_thread::sleep_for (chrono::milliseconds(1000));
1174 //cout << "Turning on!" << endl;
1175 this_thread::sleep_for (chrono::milliseconds(1000));
1180 void adjustTemp(LifxLightBulb *llb) {
1182 for (int i = 2500; i < 9000; i += 100) {
1183 //cout << "Adjusting Temp: " << i << endl;
1184 llb->setTemperature(i);
1185 this_thread::sleep_for (chrono::milliseconds(100));
1187 //cout << "Adjusted temperature to 9000!" << endl;
1188 for (int i = 9000; i > 2500; i -= 100) {
1189 //cout << "Adjusting Temp: " << i << endl;
1190 llb->setTemperature(i);
1191 this_thread::sleep_for (chrono::milliseconds(100));
1193 //cout << "Adjusted temperature to 2500!" << endl;
1197 void adjustBright(LifxLightBulb *llb) {
1198 for (int i = 100; i > 0; i -= 10) {
1199 //cout << "Adjusting Brightness: " << i << endl;
1200 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1201 this_thread::sleep_for (chrono::milliseconds(100));
1203 //cout << "Adjusted brightness to 0!" << endl;
1204 for (int i = 0; i < 100; i += 10) {
1205 //cout << "Adjusting Brightness: " << i << endl;
1206 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1207 this_thread::sleep_for (chrono::milliseconds(100));
1209 //cout << "Adjusting brightness to 100!" << endl;
1213 /*int main(int argc, char *argv[])
1215 string macAddress = "D073D5128E300000";
1216 //string macAddress = "D073D50241DA0000";
1217 string devIPAddress = "192.168.2.126";
1218 //string devIPAddress = "192.168.2.232";
1219 //IoTDeviceAddress devAddress(devIPAddress, 12345, 56700, false, false);
1220 IoTDeviceAddress* devAddress = new IoTDeviceAddress(devIPAddress, 12345, 56700, false, false);
1221 unordered_set<IoTDeviceAddress*> myset = { devAddress };
1223 IoTSet<IoTDeviceAddress*> setDevAddress(myset);
1224 LifxLightBulb *llb = new LifxLightBulb(setDevAddress, macAddress);
1225 cout << "Generated LifxLightBulb object!" << endl;