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);
80 string file = "LifxLightBulb_cpp" + to_string(i) + ".log";
81 while (ifstream(file.c_str())) {
83 file = "LifxLightBulb_cpp" + to_string(i) + ".log";
86 log << "MAC address is " << macAddress << endl;
88 // Initialize device address
89 lb_addresses = _devAddress;
90 //cout << "Device address is set! " << endl;
94 LifxLightBulb::~LifxLightBulb() {
97 if (communicationSocket != NULL) {
99 delete communicationSocket;
100 communicationSocket = NULL;
102 for(void* dev : *lb_addresses) {
103 IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
107 if (lb_addresses != NULL) {
116 // Initialize the lightbulb
117 void LifxLightBulb::init() {
119 if (didAlreadyInit.exchange(true))
122 log << "lb_addresses has: " << lb_addresses->size() << endl;
123 unordered_set<void*>::const_iterator itr = lb_addresses->begin();
124 IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
125 //cout << "Address: " << deviceAddress->getAddress() << endl;
126 log << "Address: " << deviceAddress->getAddress() << endl;
128 // Create IoTUDP socket
129 communicationSocket = new IoTUDP(deviceAddress);
131 //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
132 //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
133 //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
134 log << "Host address: " << communicationSocket->getHostAddress() << endl;
135 log << "Source port: " << communicationSocket->getSourcePort() << endl;
136 log << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
138 // Launch the worker function in a separate thread.
139 // NOTE: "this" pointer is passed into the detached thread because it does not belong
140 // to this object anymore so if it executes certain methods of "this" object, then it needs
141 // the correct references to stuff
142 thread th1 (&LifxLightBulb::workerFunction, this, this);
145 //cout << "Initialized LifxLightBulb!" << endl;
146 log << "Initialized LifxLightBulb!" << endl;
151 void LifxLightBulb::turnOff() {
153 //lock_guard<mutex> guard(bulbStateMutex);
154 bulbStateMutex.lock();
156 sendSetLightPowerPacket(0, 0);
157 stateDidChange = true;
158 bulbStateMutex.unlock();
162 void LifxLightBulb::turnOn() {
164 //lock_guard<mutex> guard(bulbStateMutex);
165 bulbStateMutex.lock();
167 sendSetLightPowerPacket(65535, 0);
168 stateDidChange = true;
169 bulbStateMutex.unlock();
173 double LifxLightBulb::getHue() {
175 settingBulbColorMutex.lock();
176 tmp = ((double)currentHue / 65535.0) * 360.0;
177 settingBulbColorMutex.unlock();
183 double LifxLightBulb::getSaturation() {
185 settingBulbColorMutex.lock();
186 tmp = ((double)currentSaturation / 65535.0) * 360.0;
187 settingBulbColorMutex.unlock();
193 double LifxLightBulb::getBrightness() {
195 settingBulbColorMutex.lock();
196 tmp = ((double)currentBrightness / 65535.0) * 360.0;
197 settingBulbColorMutex.unlock();
203 int LifxLightBulb::getTemperature() {
206 settingBulbTemperatureMutex.lock();
207 tmp = currentTemperature;
208 settingBulbTemperatureMutex.unlock();
214 double LifxLightBulb::getHueRangeLowerBound() {
215 if (!didGetBulbVersion) {
218 return ((double)hueLowerBound / 65535.0) * 360.0;
222 double LifxLightBulb::getHueRangeUpperBound() {
223 if (!didGetBulbVersion) {
226 return ((double)hueUpperBound / 65535.0) * 360.0;
230 double LifxLightBulb::getSaturationRangeLowerBound() {
231 if (!didGetBulbVersion) {
234 return ((double)saturationLowerBound / 65535.0) * 100.0;
238 double LifxLightBulb::getSaturationRangeUpperBound() {
239 if (!didGetBulbVersion) {
242 return ((double)saturationUpperBound / 65535.0) * 100.0;
246 double LifxLightBulb::getBrightnessRangeLowerBound() {
247 if (!didGetBulbVersion) {
250 return ((double)brightnessLowerBound / 65535.0) * 100.0;
254 double LifxLightBulb::getBrightnessRangeUpperBound() {
255 if (!didGetBulbVersion) {
258 return ((double)brightnessUpperBound / 65535.0) * 100.0;
262 int LifxLightBulb::getTemperatureRangeLowerBound() {
263 if (!didGetBulbVersion) {
266 return temperatureLowerBound;
270 int LifxLightBulb::getTemperatureRangeUpperBound() {
271 if (!didGetBulbVersion) {
274 return temperatureUpperBound;
278 void LifxLightBulb::setTemperature(int _temperature) {
280 settingBulbTemperatureMutex.lock();
282 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
283 sendSetLightColorPacket(newColor, 250);
285 currentTemperature = _temperature;
286 stateDidChange = true;
288 settingBulbTemperatureMutex.unlock();
292 void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
294 settingBulbColorMutex.lock();
297 _saturation /= 100.0;
298 _brightness /= 100.0;
301 int newHue = (int)(_hue * 65535.0);
302 int newSaturation = (int)(_saturation * 65535.0);
303 int newBrightness = (int)(_brightness * 65535.0);
305 BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
306 sendSetLightColorPacket(newColor, 250);
309 currentSaturation = newSaturation;
310 currentBrightness = newBrightness;
311 stateDidChange = true;
313 settingBulbColorMutex.unlock();
317 bool LifxLightBulb::getState() {
321 bulbStateMutex.lock();
323 bulbStateMutex.unlock();
330 // Communication helpers
331 void LifxLightBulb::receivedPacket(char* packetData) {
333 char headerBytes[36];
334 for (int i = 0; i < 36; i++) {
335 headerBytes[i] = packetData[i];
338 LifxHeader recHeader;
339 recHeader.setFromBytes(headerBytes);
341 // load the payload bytes (strip away the header)
342 //char payloadBytes[recHeader.getSize()];
343 char* payloadBytes = new char[recHeader.getSize()];
344 for (int i = 36; i < recHeader.getSize(); i++) {
345 payloadBytes[i - 36] = packetData[i];
348 int type = recHeader.getType();
349 //cout << "Received: " << type << endl;
351 DeviceStateService* dat = NULL;
355 dat = parseDeviceStateServiceMessage(payloadBytes);
356 //cout << "Service: " << dat->getService();
357 //cout << "Port : " << dat->getPort();
358 // Avoid memory leak - delete this object
363 handleStateVersionMessageReceived(payloadBytes);
367 parseDeviceStateInfoMessage(payloadBytes);
372 handleLightStateMessageReceived(payloadBytes);
377 //cout << "unknown packet Type" << endl;
379 // Avoid memory leaks
384 void LifxLightBulb::sendPacket(char* packetData, int len) {
385 //cout << "sendPacket: About to send" << endl;
386 lock_guard<mutex> guard(socketMutex);
387 sendSocketFlag = true;
388 communicationSocket->sendData(packetData, len);
389 sendSocketFlag = false;
393 // Worker function which runs the while loop for receiving data from the bulb.
395 void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
397 // Need timeout on receives since we are not sure if a packet will be available
398 // for processing so don't block waiting
399 llb->communicationSocket->setTimeOut(50000); // In milliseconds
403 int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
406 llb->log << "Turning off and entering while loop!" << endl;
409 // Check if we got the bulb version yet
410 // could have requested it but message could have gotten lost (UDP)
411 if (!llb->didGetBulbVersion) {
412 int64_t currentTime = (int64_t) time(NULL);
413 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
414 // Get the bulb version so we know what type of bulb this is.
415 //cout << "Sending version packet! " << endl;
416 llb->sendGetVersionPacket();
417 lastSentGetBulbVersionRequest = currentTime;
421 // Communication resource is busy so try again later
422 if (llb->sendSocketFlag) {
426 llb->socketMutex.lock();
427 int ret = llb->communicationSocket->receiveData(dat, 1024);
428 // Never forget to release!
429 llb->socketMutex.unlock();
433 llb->receivedPacket(dat);
436 // If a state change occurred then request the bulb state to ensure that the
437 // bulb did indeed change its state to the correct state
438 if (llb->stateDidChange) {
439 llb->sendGetLightStatePacket();
442 // Wait a bit as to not tie up system resources
443 this_thread::sleep_for (chrono::milliseconds(100));
444 //cout << endl << "Sleep and wake up!" << endl;
451 void LifxLightBulb::sendGetServicePacket() {
454 header.setTagged(true);
455 header.setMacAddress(bulbMacAddress);
456 header.setSource(0); // randomly picked
457 header.setAck_required(false);
458 header.setRes_required(false);
459 header.setSequence(0);
463 header.getHeaderBytes(dataBytes);
465 sendPacket(dataBytes, 36);
469 void LifxLightBulb::sendGetHostInfoPacket() {
472 header.setTagged(false);
473 header.setMacAddress(bulbMacAddress);
474 header.setSource(10); // randomly picked
475 header.setAck_required(false);
476 header.setRes_required(false);
477 header.setSequence(0);
481 header.getHeaderBytes(dataBytes);
483 sendPacket(dataBytes, 36);
487 void LifxLightBulb::sendGetHostFirmwarePacket() {
490 header.setTagged(false);
491 header.setMacAddress(bulbMacAddress);
492 header.setSource(10); // randomly picked
493 header.setAck_required(false);
494 header.setRes_required(false);
495 header.setSequence(0);
499 header.getHeaderBytes(dataBytes);
501 sendPacket(dataBytes, 36);
505 void LifxLightBulb::sendGetWifiInfoPacket() {
508 header.setTagged(false);
509 header.setMacAddress(bulbMacAddress);
510 header.setSource(10); // randomly picked
511 header.setAck_required(false);
512 header.setRes_required(false);
513 header.setSequence(0);
517 header.getHeaderBytes(dataBytes);
519 sendPacket(dataBytes, 36);
523 void LifxLightBulb::sendGetWifiFirmwarePacket() {
526 header.setTagged(false);
527 header.setMacAddress(bulbMacAddress);
528 header.setSource(10); // randomly picked
529 header.setAck_required(false);
530 header.setRes_required(false);
531 header.setSequence(0);
535 header.getHeaderBytes(dataBytes);
537 sendPacket(dataBytes, 36);
541 void LifxLightBulb::sendGetPowerPacket() {
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);
553 header.getHeaderBytes(dataBytes);
555 sendPacket(dataBytes, 36);
559 void LifxLightBulb::sendSetPowerPacket(int level) {
560 // Currently only 0 and 65535 are supported
561 // This is a fix for now
562 if ((level != 65535) && (level != 0)) {
563 cerr << "Invalid parameter values" << endl;
567 if ((level > 65535) || (level < 0)) {
568 cerr << "Invalid parameter values" << endl;
572 char packetBytes[38];
576 header.setTagged(false);
577 header.setMacAddress(bulbMacAddress);
578 header.setSource(10); // randomly picked
579 header.setAck_required(false);
580 header.setRes_required(false);
581 header.setSequence(0);
583 char headerBytes[36];
584 header.getHeaderBytes(headerBytes);
586 for (int i = 0; i < 36; i++) {
587 packetBytes[i] = headerBytes[i];
590 packetBytes[36] = (char)(level & 0xFF);
591 packetBytes[37] = (char)((level >> 8) & 0xFF);
593 sendPacket(packetBytes, 38);
597 void LifxLightBulb::sendGetLabelPacket() {
600 header.setTagged(false);
601 header.setMacAddress(bulbMacAddress);
602 header.setSource(10); // randomly picked
603 header.setAck_required(false);
604 header.setRes_required(false);
605 header.setSequence(0);
609 header.getHeaderBytes(dataBytes);
611 sendPacket(dataBytes, 36);
615 void LifxLightBulb::sendSetLabelPacket(string label) {
616 // Currently only 0 and 65535 are supported
617 // This is a fix for now
618 if (label.length() != 32) {
619 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
623 char packetBytes[68];
627 header.setTagged(false);
628 header.setMacAddress(bulbMacAddress);
629 header.setSource(10); // randomly picked
630 header.setAck_required(false);
631 header.setRes_required(false);
632 header.setSequence(0);
634 char headerBytes[36];
635 header.getHeaderBytes(headerBytes);
637 for (int i = 0; i < 36; i++) {
638 packetBytes[i] = headerBytes[i];
641 for (int i = 0; i < 32; i++) {
642 packetBytes[i + 36] = label.c_str()[i];
645 sendPacket(packetBytes, 68);
649 void LifxLightBulb::sendGetVersionPacket() {
652 header.setTagged(false);
653 header.setMacAddress(bulbMacAddress);
654 header.setSource(10); // randomly picked
655 header.setAck_required(false);
656 header.setRes_required(false);
657 header.setSequence(0);
661 header.getHeaderBytes(dataBytes);
663 sendPacket(dataBytes, 36);
667 void LifxLightBulb::sendGetInfoPacket() {
670 header.setTagged(false);
671 header.setMacAddress(bulbMacAddress);
672 header.setSource(10); // randomly picked
673 header.setAck_required(false);
674 header.setRes_required(false);
675 header.setSequence(0);
679 header.getHeaderBytes(dataBytes);
681 sendPacket(dataBytes, 36);
685 void LifxLightBulb::sendGetLocationPacket() {
688 header.setTagged(false);
689 header.setMacAddress(bulbMacAddress);
690 header.setSource(10); // randomly picked
691 header.setAck_required(false);
692 header.setRes_required(false);
693 header.setSequence(0);
697 header.getHeaderBytes(dataBytes);
699 sendPacket(dataBytes, 36);
703 void LifxLightBulb::sendGetGroupPacket() {
706 header.setTagged(false);
707 header.setMacAddress(bulbMacAddress);
708 header.setSource(10); // randomly picked
709 header.setAck_required(false);
710 header.setRes_required(false);
711 header.setSequence(0);
715 header.getHeaderBytes(dataBytes);
717 sendPacket(dataBytes, 36);
723 void LifxLightBulb::sendGetLightStatePacket() {
726 header.setTagged(false);
727 header.setMacAddress(bulbMacAddress);
728 header.setSource(10); // randomly picked
729 header.setAck_required(false);
730 header.setRes_required(false);
731 header.setSequence(0);
735 header.getHeaderBytes(dataBytes);
737 sendPacket(dataBytes, 36);
741 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
743 if ((duration > 4294967295l) || (duration < 0)) {
744 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
748 char packetBytes[49];
752 header.setTagged(false);
753 header.setMacAddress(bulbMacAddress);
754 header.setSource(10); // randomly picked
755 header.setAck_required(false);
756 header.setRes_required(false);
757 header.setSequence(0);
759 char headerBytes[36];
760 header.getHeaderBytes(headerBytes);
762 for (int i = 0; i < 36; i++) {
763 packetBytes[i] = headerBytes[i];
767 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
768 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
770 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
771 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
773 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
774 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
776 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
777 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
779 packetBytes[45] = (char)((duration >> 0) & 0xFF);
780 packetBytes[46] = (char)((duration >> 8) & 0xFF);
781 packetBytes[47] = (char)((duration >> 16) & 0xFF);
782 packetBytes[48] = (char)((duration >> 24) & 0xFF);
784 sendPacket(packetBytes, 49);
785 // Avoid memory leak - delete object
790 void LifxLightBulb::sendGetLightPowerPacket() {
793 header.setTagged(false);
794 header.setMacAddress(bulbMacAddress);
795 header.setSource(10); // randomly picked
796 header.setAck_required(false);
797 header.setRes_required(false);
798 header.setSequence(0);
802 header.getHeaderBytes(dataBytes);
804 sendPacket(dataBytes, 36);
808 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
810 if ((level > 65535) || (duration > 4294967295l)
811 || (level < 0) || (duration < 0)) {
812 cerr << "Invalid parameter values" << endl;
816 char packetBytes[42];
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 packetBytes[36] = (char)(level & 0xFF);
836 packetBytes[37] = (char)((level >> 8) & 0xFF);
838 packetBytes[38] = (char)((duration >> 0) & 0xFF);
839 packetBytes[39] = (char)((duration >> 8) & 0xFF);
840 packetBytes[40] = (char)((duration >> 16) & 0xFF);
841 packetBytes[41] = (char)((duration >> 24) & 0xFF);
843 sendPacket(packetBytes, 42);
847 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
849 char packetBytes[100];
853 header.setTagged(false);
854 header.setMacAddress(bulbMacAddress);
855 header.setSource(10); // randomly picked
856 header.setAck_required(false);
857 header.setRes_required(false);
858 header.setSequence(0);
860 char headerBytes[36];
861 header.getHeaderBytes(headerBytes);
863 for (int i = 0; i < 36; i++) {
864 packetBytes[i] = headerBytes[i];
867 for (int i = 0; i < 64; i++) {
868 packetBytes[i + 36] = data[i];
871 sendPacket(packetBytes, 100);
877 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
878 int service = payloadData[0];
879 int64_t port = ((payloadData[3] & 0xFF) << 24);
880 port |= ((payloadData[2] & 0xFF) << 16);
881 port |= ((payloadData[1] & 0xFF) << 8);
882 port |= (payloadData[0] & 0xFF);
884 return new DeviceStateService(service, port);
888 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
889 long signal = ((payloadData[3] & 0xFF) << 24);
890 signal |= ((payloadData[2] & 0xFF) << 16);
891 signal |= ((payloadData[1] & 0xFF) << 8);
892 signal |= (payloadData[0] & 0xFF);
894 long tx = ((payloadData[7] & 0xFF) << 24);
895 tx |= ((payloadData[6] & 0xFF) << 16);
896 tx |= ((payloadData[5] & 0xFF) << 8);
897 tx |= (payloadData[4] & 0xFF);
899 long rx = ((payloadData[11] & 0xFF) << 24);
900 rx |= ((payloadData[10] & 0xFF) << 16);
901 rx |= ((payloadData[9] & 0xFF) << 8);
902 rx |= (payloadData[8] & 0xFF);
904 return new DeviceStateHostInfo(signal, tx, rx);
908 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
910 for (int i = 0; i < 8; i++) {
911 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
916 int64_t version = ((payloadData[19] & 0xFF) << 24);
917 version |= ((payloadData[18] & 0xFF) << 16);
918 version |= ((payloadData[17] & 0xFF) << 8);
919 version |= (payloadData[16] & 0xFF);
921 return new DeviceStateHostFirmware(build, version);
925 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
926 int64_t signal = ((payloadData[3] & 0xFF) << 24);
927 signal |= ((payloadData[2] & 0xFF) << 16);
928 signal |= ((payloadData[1] & 0xFF) << 8);
929 signal |= (payloadData[0] & 0xFF);
931 int64_t tx = ((payloadData[7] & 0xFF) << 24);
932 tx |= ((payloadData[6] & 0xFF) << 16);
933 tx |= ((payloadData[5] & 0xFF) << 8);
934 tx |= (payloadData[4] & 0xFF);
936 int64_t rx = ((payloadData[11] & 0xFF) << 24);
937 rx |= ((payloadData[10] & 0xFF) << 16);
938 rx |= ((payloadData[9] & 0xFF) << 8);
939 rx |= (payloadData[8] & 0xFF);
941 return new DeviceStateWifiInfo(signal, tx, rx);
945 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
947 for (int i = 0; i < 8; i++) {
948 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
953 int64_t version = ((payloadData[19] & 0xFF) << 24);
954 version |= ((payloadData[18] & 0xFF) << 16);
955 version |= ((payloadData[17] & 0xFF) << 8);
956 version |= (payloadData[16] & 0xFF);
958 return new DeviceStateWifiFirmware(build, version);
962 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
963 int level = ((payloadData[1] & 0xFF) << 8);
964 level |= (payloadData[0] & 0xFF);
969 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
970 int64_t vender = ((payloadData[3] & 0xFF) << 24);
971 vender |= ((payloadData[2] & 0xFF) << 16);
972 vender |= ((payloadData[1] & 0xFF) << 8);
973 vender |= (payloadData[0] & 0xFF);
975 int64_t product = ((payloadData[7] & 0xFF) << 24);
976 product |= ((payloadData[6] & 0xFF) << 16);
977 product |= ((payloadData[5] & 0xFF) << 8);
978 product |= (payloadData[4] & 0xFF);
980 int64_t version = ((payloadData[11] & 0xFF) << 24);
981 version |= ((payloadData[10] & 0xFF) << 16);
982 version |= ((payloadData[9] & 0xFF) << 8);
983 version |= (payloadData[8] & 0xFF);
985 return new DeviceStateVersion(vender, product, version);
989 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
992 int64_t downTime = 0;
993 for (int i = 0; i < 8; i++) {
994 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
995 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
996 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
999 return new DeviceStateInfo(time, upTime, downTime);
1003 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
1005 for (int i = 0; i < 16; i++) {
1006 location[i] = payloadData[i];
1009 char labelBytes[32];
1010 for (int i = 0; i < 32; i++) {
1011 labelBytes[i] = payloadData[i + 16];
1014 int64_t updatedAt = 0;
1015 for (int i = 0; i < 8; i++) {
1016 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1019 string str(labelBytes);
1020 return new DeviceStateLocation(location, str, updatedAt);
1024 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1026 for (int i = 0; i < 16; i++) {
1027 group[i] = payloadData[i];
1030 char labelBytes[32];
1031 for (int i = 0; i < 32; i++) {
1032 labelBytes[i] = payloadData[i + 16];
1035 int64_t updatedAt = 0;
1036 for (int i = 0; i < 8; i++) {
1037 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1040 string str(labelBytes);
1041 return new DeviceStateGroup(group, str, updatedAt);
1047 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1050 for (int i = 0; i < 8; i++) {
1051 colorData[i] = payloadData[i];
1053 //BulbColor color(colorData);
1054 BulbColor* color = new BulbColor(colorData);
1056 int power = ((payloadData[11] & 0xFF) << 8);
1057 power |= (payloadData[10] & 0xFF);
1059 string label(payloadData);
1061 char labelArray[32];
1062 for (int i = 0; i < 32; i++) {
1063 labelArray[i] = payloadData[12 + i];
1066 return new LightState(color, power, label);
1070 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1071 int level = ((payloadData[1] & 0xFF) << 8);
1072 level |= (payloadData[0] & 0xFF);
1078 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1080 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1081 int productNumber = (int)deviceState->getProduct();
1083 bool isColor = false;
1085 if (productNumber == 1) {// Original 1000
1087 } else if (productNumber == 3) {//Color 650
1089 } else if (productNumber == 10) {// White 800 (Low Voltage)
1091 } else if (productNumber == 11) {// White 800 (High Voltage)
1093 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1095 } else if (productNumber == 20) {// Color 1000 BR30
1097 } else if (productNumber == 22) {// Color 1000
1103 hueUpperBound = 65535;
1104 saturationLowerBound = 0;
1105 saturationUpperBound = 65535;
1106 brightnessLowerBound = 0;
1107 brightnessUpperBound = 65535;
1108 temperatureLowerBound = 2500;
1109 temperatureUpperBound = 9000;
1113 saturationLowerBound = 0;
1114 saturationUpperBound = 0;
1115 brightnessLowerBound = 0;
1116 brightnessUpperBound = 65535;// still can dim bulb
1117 temperatureLowerBound = 2500;
1118 temperatureUpperBound = 9000;
1121 didGetBulbVersion.exchange(true);
1122 // Avoid memory leak - delete this object
1127 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1128 LightState* lightState = parseLightStateMessage(payloadData);
1130 BulbColor* color = lightState->getColor();
1131 int power = lightState->getPower();
1133 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1134 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1135 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1136 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1138 bool bulbWrongColor = false;
1139 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1140 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1141 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1142 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1145 // gets set to true if any of the below if statements are taken
1146 stateDidChange = false;
1148 if (bulbWrongColor) {
1149 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1150 sendSetLightColorPacket(newColor, 250);
1151 //cout << "Failed Check 1" << endl;
1154 bulbStateMutex.lock();
1155 bool bulbIsOnTmp = bulbIsOn;
1156 bulbStateMutex.unlock();
1158 if ((!bulbIsOnTmp) && (power != 0)) {
1160 //cout << "Failed Check 2: " << endl;
1164 if (bulbIsOnTmp && (power < 65530)) {
1166 //cout << "Failed Check 3: " << endl;
1169 // Avoid memory leak - delete object
1175 // Functions for the main function
1176 void onOff(LifxLightBulb *llb) {
1178 for (int i = 0; i < 2; i++) {
1180 //cout << "Turning off!" << endl;
1181 this_thread::sleep_for (chrono::milliseconds(1000));
1183 //cout << "Turning on!" << endl;
1184 this_thread::sleep_for (chrono::milliseconds(1000));
1189 void adjustTemp(LifxLightBulb *llb) {
1191 for (int i = 2500; i < 9000; i += 100) {
1192 //cout << "Adjusting Temp: " << i << endl;
1193 llb->setTemperature(i);
1194 this_thread::sleep_for (chrono::milliseconds(100));
1196 //cout << "Adjusted temperature to 9000!" << endl;
1197 for (int i = 9000; i > 2500; i -= 100) {
1198 //cout << "Adjusting Temp: " << i << endl;
1199 llb->setTemperature(i);
1200 this_thread::sleep_for (chrono::milliseconds(100));
1202 //cout << "Adjusted temperature to 2500!" << endl;
1206 void adjustBright(LifxLightBulb *llb) {
1207 for (int i = 100; i > 0; i -= 10) {
1208 //cout << "Adjusting Brightness: " << i << endl;
1209 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1210 this_thread::sleep_for (chrono::milliseconds(100));
1212 //cout << "Adjusted brightness to 0!" << endl;
1213 for (int i = 0; i < 100; i += 10) {
1214 //cout << "Adjusting Brightness: " << i << endl;
1215 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1216 this_thread::sleep_for (chrono::milliseconds(100));
1218 //cout << "Adjusting brightness to 100!" << endl;
1222 int main(int argc, char *argv[])
1224 string macAddress1 = "D073D5128E300000";
1225 //string macAddress = "D073D50241DA0000";
1226 string devIPAddress1 = "192.168.2.126";
1227 //string devIPAddress = "192.168.2.232";
1228 IoTDeviceAddress* devAddress1 = new IoTDeviceAddress(devIPAddress1, 12345, 56700, false, false);
1229 unordered_set<void*>* myset1 = new unordered_set<void*>();
1230 myset1->insert(devAddress1);
1232 IoTSet<void*>* setDevAddress1 = new IoTSet<void*>(myset1);
1233 LifxLightBulb *llb1 = new LifxLightBulb(setDevAddress1, macAddress1);
1234 cout << "Generated LifxLightBulb object!" << endl;
1242 // delete devAddress1;