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
407 // Check if we got the bulb version yet
408 // could have requested it but message could have gotten lost (UDP)
409 if (!llb->didGetBulbVersion) {
410 int64_t currentTime = (int64_t) time(NULL);
411 if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
412 // Get the bulb version so we know what type of bulb this is.
413 //cout << "Sending version packet! " << endl;
414 llb->sendGetVersionPacket();
415 lastSentGetBulbVersionRequest = currentTime;
419 // Communication resource is busy so try again later
420 if (llb->sendSocketFlag) {
424 llb->socketMutex.lock();
425 int ret = llb->communicationSocket->receiveData(dat, 1024);
426 // Never forget to release!
427 llb->socketMutex.unlock();
431 llb->receivedPacket(dat);
434 // If a state change occurred then request the bulb state to ensure that the
435 // bulb did indeed change its state to the correct state
436 if (llb->stateDidChange) {
437 llb->sendGetLightStatePacket();
440 // Wait a bit as to not tie up system resources
441 this_thread::sleep_for (chrono::milliseconds(100));
442 //cout << endl << "Sleep and wake up!" << endl;
449 void LifxLightBulb::sendGetServicePacket() {
452 header.setTagged(true);
453 header.setMacAddress(bulbMacAddress);
454 header.setSource(0); // randomly picked
455 header.setAck_required(false);
456 header.setRes_required(false);
457 header.setSequence(0);
461 header.getHeaderBytes(dataBytes);
463 sendPacket(dataBytes, 36);
467 void LifxLightBulb::sendGetHostInfoPacket() {
470 header.setTagged(false);
471 header.setMacAddress(bulbMacAddress);
472 header.setSource(10); // randomly picked
473 header.setAck_required(false);
474 header.setRes_required(false);
475 header.setSequence(0);
479 header.getHeaderBytes(dataBytes);
481 sendPacket(dataBytes, 36);
485 void LifxLightBulb::sendGetHostFirmwarePacket() {
488 header.setTagged(false);
489 header.setMacAddress(bulbMacAddress);
490 header.setSource(10); // randomly picked
491 header.setAck_required(false);
492 header.setRes_required(false);
493 header.setSequence(0);
497 header.getHeaderBytes(dataBytes);
499 sendPacket(dataBytes, 36);
503 void LifxLightBulb::sendGetWifiInfoPacket() {
506 header.setTagged(false);
507 header.setMacAddress(bulbMacAddress);
508 header.setSource(10); // randomly picked
509 header.setAck_required(false);
510 header.setRes_required(false);
511 header.setSequence(0);
515 header.getHeaderBytes(dataBytes);
517 sendPacket(dataBytes, 36);
521 void LifxLightBulb::sendGetWifiFirmwarePacket() {
524 header.setTagged(false);
525 header.setMacAddress(bulbMacAddress);
526 header.setSource(10); // randomly picked
527 header.setAck_required(false);
528 header.setRes_required(false);
529 header.setSequence(0);
533 header.getHeaderBytes(dataBytes);
535 sendPacket(dataBytes, 36);
539 void LifxLightBulb::sendGetPowerPacket() {
542 header.setTagged(false);
543 header.setMacAddress(bulbMacAddress);
544 header.setSource(10); // randomly picked
545 header.setAck_required(false);
546 header.setRes_required(false);
547 header.setSequence(0);
551 header.getHeaderBytes(dataBytes);
553 sendPacket(dataBytes, 36);
557 void LifxLightBulb::sendSetPowerPacket(int level) {
558 // Currently only 0 and 65535 are supported
559 // This is a fix for now
560 if ((level != 65535) && (level != 0)) {
561 cerr << "Invalid parameter values" << endl;
565 if ((level > 65535) || (level < 0)) {
566 cerr << "Invalid parameter values" << endl;
570 char packetBytes[38];
574 header.setTagged(false);
575 header.setMacAddress(bulbMacAddress);
576 header.setSource(10); // randomly picked
577 header.setAck_required(false);
578 header.setRes_required(false);
579 header.setSequence(0);
581 char headerBytes[36];
582 header.getHeaderBytes(headerBytes);
584 for (int i = 0; i < 36; i++) {
585 packetBytes[i] = headerBytes[i];
588 packetBytes[36] = (char)(level & 0xFF);
589 packetBytes[37] = (char)((level >> 8) & 0xFF);
591 sendPacket(packetBytes, 38);
595 void LifxLightBulb::sendGetLabelPacket() {
598 header.setTagged(false);
599 header.setMacAddress(bulbMacAddress);
600 header.setSource(10); // randomly picked
601 header.setAck_required(false);
602 header.setRes_required(false);
603 header.setSequence(0);
607 header.getHeaderBytes(dataBytes);
609 sendPacket(dataBytes, 36);
613 void LifxLightBulb::sendSetLabelPacket(string label) {
614 // Currently only 0 and 65535 are supported
615 // This is a fix for now
616 if (label.length() != 32) {
617 cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
621 char packetBytes[68];
625 header.setTagged(false);
626 header.setMacAddress(bulbMacAddress);
627 header.setSource(10); // randomly picked
628 header.setAck_required(false);
629 header.setRes_required(false);
630 header.setSequence(0);
632 char headerBytes[36];
633 header.getHeaderBytes(headerBytes);
635 for (int i = 0; i < 36; i++) {
636 packetBytes[i] = headerBytes[i];
639 for (int i = 0; i < 32; i++) {
640 packetBytes[i + 36] = label.c_str()[i];
643 sendPacket(packetBytes, 68);
647 void LifxLightBulb::sendGetVersionPacket() {
650 header.setTagged(false);
651 header.setMacAddress(bulbMacAddress);
652 header.setSource(10); // randomly picked
653 header.setAck_required(false);
654 header.setRes_required(false);
655 header.setSequence(0);
659 header.getHeaderBytes(dataBytes);
661 sendPacket(dataBytes, 36);
665 void LifxLightBulb::sendGetInfoPacket() {
668 header.setTagged(false);
669 header.setMacAddress(bulbMacAddress);
670 header.setSource(10); // randomly picked
671 header.setAck_required(false);
672 header.setRes_required(false);
673 header.setSequence(0);
677 header.getHeaderBytes(dataBytes);
679 sendPacket(dataBytes, 36);
683 void LifxLightBulb::sendGetLocationPacket() {
686 header.setTagged(false);
687 header.setMacAddress(bulbMacAddress);
688 header.setSource(10); // randomly picked
689 header.setAck_required(false);
690 header.setRes_required(false);
691 header.setSequence(0);
695 header.getHeaderBytes(dataBytes);
697 sendPacket(dataBytes, 36);
701 void LifxLightBulb::sendGetGroupPacket() {
704 header.setTagged(false);
705 header.setMacAddress(bulbMacAddress);
706 header.setSource(10); // randomly picked
707 header.setAck_required(false);
708 header.setRes_required(false);
709 header.setSequence(0);
713 header.getHeaderBytes(dataBytes);
715 sendPacket(dataBytes, 36);
721 void LifxLightBulb::sendGetLightStatePacket() {
724 header.setTagged(false);
725 header.setMacAddress(bulbMacAddress);
726 header.setSource(10); // randomly picked
727 header.setAck_required(false);
728 header.setRes_required(false);
729 header.setSequence(0);
733 header.getHeaderBytes(dataBytes);
735 sendPacket(dataBytes, 36);
739 void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
741 if ((duration > 4294967295l) || (duration < 0)) {
742 cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
746 char packetBytes[49];
750 header.setTagged(false);
751 header.setMacAddress(bulbMacAddress);
752 header.setSource(10); // randomly picked
753 header.setAck_required(false);
754 header.setRes_required(false);
755 header.setSequence(0);
757 char headerBytes[36];
758 header.getHeaderBytes(headerBytes);
760 for (int i = 0; i < 36; i++) {
761 packetBytes[i] = headerBytes[i];
765 packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
766 packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
768 packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
769 packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
771 packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
772 packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
774 packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
775 packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
777 packetBytes[45] = (char)((duration >> 0) & 0xFF);
778 packetBytes[46] = (char)((duration >> 8) & 0xFF);
779 packetBytes[47] = (char)((duration >> 16) & 0xFF);
780 packetBytes[48] = (char)((duration >> 24) & 0xFF);
782 sendPacket(packetBytes, 49);
783 // Avoid memory leak - delete object
788 void LifxLightBulb::sendGetLightPowerPacket() {
791 header.setTagged(false);
792 header.setMacAddress(bulbMacAddress);
793 header.setSource(10); // randomly picked
794 header.setAck_required(false);
795 header.setRes_required(false);
796 header.setSequence(0);
800 header.getHeaderBytes(dataBytes);
802 sendPacket(dataBytes, 36);
806 void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
808 if ((level > 65535) || (duration > 4294967295l)
809 || (level < 0) || (duration < 0)) {
810 cerr << "Invalid parameter values" << endl;
814 char packetBytes[42];
819 header.setTagged(false);
820 header.setMacAddress(bulbMacAddress);
821 header.setSource(10); // randomly picked
822 header.setAck_required(false);
823 header.setRes_required(false);
824 header.setSequence(0);
826 char headerBytes[36];
827 header.getHeaderBytes(headerBytes);
829 for (int i = 0; i < 36; i++) {
830 packetBytes[i] = headerBytes[i];
833 packetBytes[36] = (char)(level & 0xFF);
834 packetBytes[37] = (char)((level >> 8) & 0xFF);
836 packetBytes[38] = (char)((duration >> 0) & 0xFF);
837 packetBytes[39] = (char)((duration >> 8) & 0xFF);
838 packetBytes[40] = (char)((duration >> 16) & 0xFF);
839 packetBytes[41] = (char)((duration >> 24) & 0xFF);
841 sendPacket(packetBytes, 42);
845 void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
847 char packetBytes[100];
851 header.setTagged(false);
852 header.setMacAddress(bulbMacAddress);
853 header.setSource(10); // randomly picked
854 header.setAck_required(false);
855 header.setRes_required(false);
856 header.setSequence(0);
858 char headerBytes[36];
859 header.getHeaderBytes(headerBytes);
861 for (int i = 0; i < 36; i++) {
862 packetBytes[i] = headerBytes[i];
865 for (int i = 0; i < 64; i++) {
866 packetBytes[i + 36] = data[i];
869 sendPacket(packetBytes, 100);
875 DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
876 int service = payloadData[0];
877 int64_t port = ((payloadData[3] & 0xFF) << 24);
878 port |= ((payloadData[2] & 0xFF) << 16);
879 port |= ((payloadData[1] & 0xFF) << 8);
880 port |= (payloadData[0] & 0xFF);
882 return new DeviceStateService(service, port);
886 DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
887 long signal = ((payloadData[3] & 0xFF) << 24);
888 signal |= ((payloadData[2] & 0xFF) << 16);
889 signal |= ((payloadData[1] & 0xFF) << 8);
890 signal |= (payloadData[0] & 0xFF);
892 long tx = ((payloadData[7] & 0xFF) << 24);
893 tx |= ((payloadData[6] & 0xFF) << 16);
894 tx |= ((payloadData[5] & 0xFF) << 8);
895 tx |= (payloadData[4] & 0xFF);
897 long rx = ((payloadData[11] & 0xFF) << 24);
898 rx |= ((payloadData[10] & 0xFF) << 16);
899 rx |= ((payloadData[9] & 0xFF) << 8);
900 rx |= (payloadData[8] & 0xFF);
902 return new DeviceStateHostInfo(signal, tx, rx);
906 DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
908 for (int i = 0; i < 8; i++) {
909 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
914 int64_t version = ((payloadData[19] & 0xFF) << 24);
915 version |= ((payloadData[18] & 0xFF) << 16);
916 version |= ((payloadData[17] & 0xFF) << 8);
917 version |= (payloadData[16] & 0xFF);
919 return new DeviceStateHostFirmware(build, version);
923 DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
924 int64_t signal = ((payloadData[3] & 0xFF) << 24);
925 signal |= ((payloadData[2] & 0xFF) << 16);
926 signal |= ((payloadData[1] & 0xFF) << 8);
927 signal |= (payloadData[0] & 0xFF);
929 int64_t tx = ((payloadData[7] & 0xFF) << 24);
930 tx |= ((payloadData[6] & 0xFF) << 16);
931 tx |= ((payloadData[5] & 0xFF) << 8);
932 tx |= (payloadData[4] & 0xFF);
934 int64_t rx = ((payloadData[11] & 0xFF) << 24);
935 rx |= ((payloadData[10] & 0xFF) << 16);
936 rx |= ((payloadData[9] & 0xFF) << 8);
937 rx |= (payloadData[8] & 0xFF);
939 return new DeviceStateWifiInfo(signal, tx, rx);
943 DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
945 for (int i = 0; i < 8; i++) {
946 build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
951 int64_t version = ((payloadData[19] & 0xFF) << 24);
952 version |= ((payloadData[18] & 0xFF) << 16);
953 version |= ((payloadData[17] & 0xFF) << 8);
954 version |= (payloadData[16] & 0xFF);
956 return new DeviceStateWifiFirmware(build, version);
960 int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
961 int level = ((payloadData[1] & 0xFF) << 8);
962 level |= (payloadData[0] & 0xFF);
967 DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
968 int64_t vender = ((payloadData[3] & 0xFF) << 24);
969 vender |= ((payloadData[2] & 0xFF) << 16);
970 vender |= ((payloadData[1] & 0xFF) << 8);
971 vender |= (payloadData[0] & 0xFF);
973 int64_t product = ((payloadData[7] & 0xFF) << 24);
974 product |= ((payloadData[6] & 0xFF) << 16);
975 product |= ((payloadData[5] & 0xFF) << 8);
976 product |= (payloadData[4] & 0xFF);
978 int64_t version = ((payloadData[11] & 0xFF) << 24);
979 version |= ((payloadData[10] & 0xFF) << 16);
980 version |= ((payloadData[9] & 0xFF) << 8);
981 version |= (payloadData[8] & 0xFF);
983 return new DeviceStateVersion(vender, product, version);
987 DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
990 int64_t downTime = 0;
991 for (int i = 0; i < 8; i++) {
992 time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
993 upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
994 downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
997 return new DeviceStateInfo(time, upTime, downTime);
1001 DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
1003 for (int i = 0; i < 16; i++) {
1004 location[i] = payloadData[i];
1007 char labelBytes[32];
1008 for (int i = 0; i < 32; i++) {
1009 labelBytes[i] = payloadData[i + 16];
1012 int64_t updatedAt = 0;
1013 for (int i = 0; i < 8; i++) {
1014 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1017 string str(labelBytes);
1018 return new DeviceStateLocation(location, str, updatedAt);
1022 DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
1024 for (int i = 0; i < 16; i++) {
1025 group[i] = payloadData[i];
1028 char labelBytes[32];
1029 for (int i = 0; i < 32; i++) {
1030 labelBytes[i] = payloadData[i + 16];
1033 int64_t updatedAt = 0;
1034 for (int i = 0; i < 8; i++) {
1035 updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
1038 string str(labelBytes);
1039 return new DeviceStateGroup(group, str, updatedAt);
1045 LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
1048 for (int i = 0; i < 8; i++) {
1049 colorData[i] = payloadData[i];
1051 //BulbColor color(colorData);
1052 BulbColor* color = new BulbColor(colorData);
1054 int power = ((payloadData[11] & 0xFF) << 8);
1055 power |= (payloadData[10] & 0xFF);
1057 string label(payloadData);
1059 char labelArray[32];
1060 for (int i = 0; i < 32; i++) {
1061 labelArray[i] = payloadData[12 + i];
1064 return new LightState(color, power, label);
1068 int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
1069 int level = ((payloadData[1] & 0xFF) << 8);
1070 level |= (payloadData[0] & 0xFF);
1076 void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
1078 DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
1079 int productNumber = (int)deviceState->getProduct();
1081 bool isColor = false;
1083 if (productNumber == 1) {// Original 1000
1085 } else if (productNumber == 3) {//Color 650
1087 } else if (productNumber == 10) {// White 800 (Low Voltage)
1089 } else if (productNumber == 11) {// White 800 (High Voltage)
1091 } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
1093 } else if (productNumber == 20) {// Color 1000 BR30
1095 } else if (productNumber == 22) {// Color 1000
1101 hueUpperBound = 65535;
1102 saturationLowerBound = 0;
1103 saturationUpperBound = 65535;
1104 brightnessLowerBound = 0;
1105 brightnessUpperBound = 65535;
1106 temperatureLowerBound = 2500;
1107 temperatureUpperBound = 9000;
1111 saturationLowerBound = 0;
1112 saturationUpperBound = 0;
1113 brightnessLowerBound = 0;
1114 brightnessUpperBound = 65535;// still can dim bulb
1115 temperatureLowerBound = 2500;
1116 temperatureUpperBound = 9000;
1119 didGetBulbVersion.exchange(true);
1120 // Avoid memory leak - delete this object
1125 void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
1126 LightState* lightState = parseLightStateMessage(payloadData);
1128 BulbColor* color = lightState->getColor();
1129 int power = lightState->getPower();
1131 //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
1132 //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
1133 //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
1134 //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
1136 bool bulbWrongColor = false;
1137 bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
1138 bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
1139 bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
1140 bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
1143 // gets set to true if any of the below if statements are taken
1144 stateDidChange = false;
1146 if (bulbWrongColor) {
1147 BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
1148 sendSetLightColorPacket(newColor, 250);
1149 //cout << "Failed Check 1" << endl;
1152 bulbStateMutex.lock();
1153 bool bulbIsOnTmp = bulbIsOn;
1154 bulbStateMutex.unlock();
1156 if ((!bulbIsOnTmp) && (power != 0)) {
1158 //cout << "Failed Check 2: " << endl;
1162 if (bulbIsOnTmp && (power < 65530)) {
1164 //cout << "Failed Check 3: " << endl;
1167 // Avoid memory leak - delete object
1173 // Functions for the main function
1174 void onOff(LifxLightBulb *llb) {
1176 for (int i = 0; i < 2; i++) {
1178 //cout << "Turning off!" << endl;
1179 this_thread::sleep_for (chrono::milliseconds(1000));
1181 //cout << "Turning on!" << endl;
1182 this_thread::sleep_for (chrono::milliseconds(1000));
1187 void adjustTemp(LifxLightBulb *llb) {
1189 for (int i = 2500; i < 9000; i += 100) {
1190 //cout << "Adjusting Temp: " << i << endl;
1191 llb->setTemperature(i);
1192 this_thread::sleep_for (chrono::milliseconds(100));
1194 //cout << "Adjusted temperature to 9000!" << endl;
1195 for (int i = 9000; i > 2500; i -= 100) {
1196 //cout << "Adjusting Temp: " << i << endl;
1197 llb->setTemperature(i);
1198 this_thread::sleep_for (chrono::milliseconds(100));
1200 //cout << "Adjusted temperature to 2500!" << endl;
1204 void adjustBright(LifxLightBulb *llb) {
1205 for (int i = 100; i > 0; i -= 10) {
1206 //cout << "Adjusting Brightness: " << i << endl;
1207 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1208 this_thread::sleep_for (chrono::milliseconds(100));
1210 //cout << "Adjusted brightness to 0!" << endl;
1211 for (int i = 0; i < 100; i += 10) {
1212 //cout << "Adjusting Brightness: " << i << endl;
1213 llb->setColor(llb->getHue(), llb->getSaturation(), i);
1214 this_thread::sleep_for (chrono::milliseconds(100));
1216 //cout << "Adjusting brightness to 100!" << endl;
1220 /*int main(int argc, char *argv[])
1222 string macAddress1 = "D073D5128E300000";
1223 //string macAddress = "D073D50241DA0000";
1224 string devIPAddress1 = "192.168.2.126";
1225 //string devIPAddress = "192.168.2.232";
1226 IoTDeviceAddress* devAddress1 = new IoTDeviceAddress(devIPAddress1, 12345, 56700, false, false);
1227 unordered_set<void*>* myset1 = new unordered_set<void*>();
1228 myset1->insert(devAddress1);
1230 IoTSet<void*>* setDevAddress1 = new IoTSet<void*>(myset1);
1231 LifxLightBulb *llb1 = new LifxLightBulb(setDevAddress1, macAddress1);
1232 cout << "Generated LifxLightBulb object!" << endl;
1240 // delete devAddress1;