+++ /dev/null
-#ifndef _BULBCOLOR_H__
-#define _BULBCOLOR_H__
-#include <iostream>
-
-class BulbColor {
-
- private:
- int hue;
- int saturation;
- int brightness;
- int kelvin;
-
- public:
-
- BulbColor(int _hue, int _saturation, int _brightness, int _kelvin) {
-
- if ((_hue > 65535) || (_hue < 0)) {
- cerr << "BulbColor: Invalid parameter value for _hue (0-65535)" << endl;
- exit(1);
- }
-
- if ((_saturation > 65535) || (_saturation < 0)) {
- cerr << "BulbColor: Invalid parameter value for _saturation (0-65535)" << endl;
- exit(1);
- }
-
- if ((_brightness > 65535) || (_brightness < 0)) {
- cerr << "BulbColor: Invalid parameter value for _brightness (0-65535)" << endl;
- exit(1);
- }
-
- if ((_kelvin > 65535) || (_kelvin < 0)) {
- cerr << "BulbColor: Invalid parameter value for _kelvin (0-65535)" << endl;
- exit(1);
- }
-
- hue = _hue;
- saturation = _saturation;
- brightness = _brightness;
- kelvin = _kelvin;
- }
-
-
- BulbColor(char* data) {
- hue = ((data[1] & 0xFF) << 8);
- hue |= (data[0] & 0xFF);
-
- saturation = ((data[3] & 0xFF) << 8);
- saturation |= (data[2] & 0xFF);
-
- brightness = ((data[5] & 0xFF) << 8);
- brightness |= (data[4] & 0xFF);
-
- kelvin = ((data[7] & 0xFF) << 8);
- kelvin |= (data[6] & 0xFF);
- }
-
-
- ~BulbColor() {
- }
-
-
- int getHue() {
- return hue;
- }
-
-
- int getSaturation() {
- return saturation;
- }
-
-
- int getBrightness() {
- return brightness;
- }
-
-
- int getKelvin() {
- return kelvin;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEGROUP_H__
-#define _DEVICESTATEGROUP_H__
-#include <iostream>
-#include <string>
-
-class DeviceStateGroup {
-
- private:
- char group[16];
- string label;
- int64_t updatedAt;
-
- public:
-
- DeviceStateGroup(char _location[16], string _label, int64_t _updatedAt) {
-
- strcpy(group, _location);
- label = _label;
- updatedAt = _updatedAt;
- }
-
-
- ~DeviceStateGroup() {
- }
-
-
- char* getGroup() {
- return group;
- }
-
-
- string getLabel() {
- return label;
- }
-
-
- int64_t getUpdatedAt() {
- return updatedAt;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEHOSTFIRMWARE_H__
-#define _DEVICESTATEHOSTFIRMWARE_H__
-#include <iostream>
-
-class DeviceStateHostFirmware {
- // time of build in nanosecond accuracy
- // after some tests
- private:
- int64_t build;
- int64_t version; // firmware version
-
- public:
-
- DeviceStateHostFirmware(int64_t _build, int64_t _version) {
-
- build = _build;
- version = _version;
- }
-
-
- ~DeviceStateHostFirmware() {
- }
-
-
- int64_t getBuild() {
- return build;
- }
-
-
- int64_t getVersion() {
- return version;
- }
-
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEHOSTINFO_H__
-#define _DEVICESTATEHOSTINFO_H__
-#include <iostream>
-
-class DeviceStateHostInfo {
- private:
- int64_t signal;
- int64_t tx;
- int64_t rx;
-
- public:
-
- DeviceStateHostInfo(int64_t _signal, int64_t _tx, int64_t _rx) {
-
- signal = _signal;
- tx = _tx;
- rx = _rx;
- }
-
-
- ~DeviceStateHostInfo() {
- }
-
-
- int64_t getSignal() {
- return signal;
- }
-
-
- int64_t getTx() {
- return tx;
- }
-
-
- int64_t getRx() {
- return rx;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEINFO_H__
-#define _DEVICESTATEINFO_H__
-#include <iostream>
-
-class DeviceStateInfo {
- private:
- int64_t time;
- int64_t upTime;
- int64_t downTime;
-
- public:
-
- DeviceStateInfo(int64_t _time, int64_t _upTime, int64_t _downTime) {
-
- time = _time;
- upTime = _upTime;
- downTime = _downTime;
- }
-
-
- ~DeviceStateInfo() {
- }
-
-
- int64_t getTime() {
- return time;
- }
-
-
- int64_t getUpTime() {
- return upTime;
- }
-
-
- int64_t getDownTime() {
- return downTime;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATELOCATION_H__
-#define _DEVICESTATELOCATION_H__
-#include <iostream>
-#include <string>
-
-class DeviceStateLocation {
- private:
- char location[16];
- string label;
- int64_t updatedAt;
-
- public:
-
- DeviceStateLocation(char _location[16], string _label, long _updatedAt) {
-
- strcpy(location, _location);
- label = _label;
- updatedAt = _updatedAt;
- }
-
-
- ~DeviceStateLocation() {
- }
-
-
- char* getLocation() {
- return location;
- }
-
-
- string getLabel() {
- return label;
- }
-
-
- int64_t getUpdatedAt() {
- return updatedAt;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATESERVICE_H__
-#define _DEVICESTATESERVICE_H__
-#include <iostream>
-
-class DeviceStateService {
- private:
- int service;
- int64_t port;
-
- public:
-
- DeviceStateService(int _service, long _port) {
-
- service = _service;
- port = _port;
- }
-
-
- ~DeviceStateService() {
- }
-
-
- int getService() {
- return service;
- }
-
-
- int64_t getPort() {
- return port;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEVERSION_H__
-#define _DEVICESTATEVERSION_H__
-#include <iostream>
-
-class DeviceStateVersion {
- private:
- int64_t vender;
- int64_t product;
- int64_t version;
-
- public:
-
- DeviceStateVersion(int64_t _vender, int64_t _product, int64_t _version) {
-
- vender = _vender;
- product = _product;
- version = _version;
- }
-
-
- ~DeviceStateVersion() {
- }
-
-
- int64_t getVender() {
- return vender;
- }
-
-
- int64_t getProduct() {
- return product;
- }
-
-
- int64_t getVersion() {
- return version;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEWIFIFIRMWARE_H__
-#define _DEVICESTATEWIFIFIRMWARE_H__
-#include <iostream>
-
-class DeviceStateWifiFirmware {
- // time of build in nanosecond accuracy
- // after some tests
- private:
- int64_t build;
- int64_t version; // firmware version
-
- public:
-
- DeviceStateWifiFirmware(int64_t _build, int64_t _version) {
-
- build = _build;
- version = _version;
- }
-
-
- ~DeviceStateWifiFirmware() {
- }
-
-
- int64_t getBuild() {
- return build;
- }
-
-
- int64_t getVersion() {
- return version;
- }
-};
-#endif
+++ /dev/null
-#ifndef _DEVICESTATEWIFIINFO_H__
-#define _DEVICESTATEWIFIINFO_H__
-#include <iostream>
-
-class DeviceStateWifiInfo {
- private:
- int64_t signal;
- int64_t tx;
- int64_t rx;
-
- public:
-
- DeviceStateWifiInfo(int64_t _signal, int64_t _tx, int64_t _rx) {
-
- signal = _signal;
- tx = _tx;
- rx = _rx;
- }
-
-
- ~DeviceStateWifiInfo() {
- }
-
-
- int64_t getSignal() {
- return signal;
- }
-
-
- int64_t getTx() {
- return tx;
- }
-
-
- int64_t getRx() {
- return rx;
- }
-};
-#endif
+++ /dev/null
-#ifndef _IOTADDRESS_HPP__
-#define _IOTADDRESS_HPP__
-#include <iostream>
-
-#include "application.h"
-
-using namespace std;
-
-
-// IoTAddress class for iotruntime
-// Implemented based on IoTAddress.java that is used to wrap address
-//
-// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
-// @version 1.0
-// @since 2017-01-09
-
-class IoTAddress
-{
- public:
-
- // Constructor
- IoTAddress(IPAddress _sAddress) {
-
- inetAddress = _sAddress;
- }
-
-
- // Constructor
- IoTAddress() {
- }
-
-
- ~IoTAddress() {
- }
-
-
- IPAddress getAddress() {
-
- return inetAddress;
- }
-
- // IoTAddress class properties
- protected:
- IPAddress inetAddress;
-};
-#endif
+++ /dev/null
-#ifndef _IOTDEVICEADDRESS_H__
-#define _IOTDEVICEADDRESS_H__
-#include <iostream>
-
-#include "IoTAddress.h"
-
-using namespace std;
-
-// IoTDeviceAddress class for iotruntime
-// Implemented based on IoTDeviceAddress.java that is used to wrap device address
-//
-// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
-// @version 1.0
-// @since 2017-01-09
-
-
-class IoTDeviceAddress final : public IoTAddress
-{
-
- public:
-
- // Constructor
- IoTDeviceAddress(IPAddress _sAddress, int _iSrcPort, int _iDstPort, bool _isSrcPortWildCard, bool _isDstPortWildCard) : IoTAddress(_sAddress) {
-
- iSrcPort = _iSrcPort;
- iDstPort = _iDstPort;
- isSrcPortWildCard = _isSrcPortWildCard;
- isDstPortWildCard = _isDstPortWildCard;
- }
-
-
- // Constructor
- IoTDeviceAddress() {
- }
-
-
- ~IoTDeviceAddress() {
- }
-
-
- // Getter methods
- int getSourcePortNumber() {
-
- return iSrcPort;
- }
-
-
- int getDestinationPortNumber() {
-
- return iDstPort;
- }
-
-
- bool getIsSrcPortWildcard() {
-
- return isSrcPortWildCard;
- }
-
-
- bool getIsDstPortWildcard() {
-
- return isDstPortWildCard;
- }
-
-
- // Setter methods
- void setSrcPort(int port) {
-
- if (isDstPortWildCard) {
- iDstPort = port;
- }
- }
-
-
- void setDstPort(int port) {
-
- if (isSrcPortWildCard) {
- iSrcPort = port;
- }
- }
-
-
- // IoTDeviceAddress class properties
- private:
- int iSrcPort;
- int iDstPort;
-
- bool isSrcPortWildCard;
- bool isDstPortWildCard;
-};
-#endif
+++ /dev/null
-#ifndef _IOTSET_H__
-#define _IOTSET_H__
-#include <iostream>
-#include <string>
-#include <unordered_set>
-
-using namespace std;
-
-/** This is the IoTSet implementation for C++
- *
- * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
- * @version 1.0
- * @since 2016-09-06
- */
-template <class T>
-class IoTSet final {
- private:
- const unordered_set<T>* set;
- public:
- IoTSet();
- IoTSet(const unordered_set<T>* s);
- ~IoTSet();
- public:
- typename unordered_set<T>::const_iterator find(const T& k); // Find the object
- bool empty(); // Test is empty?
- typename unordered_set<T>::const_iterator begin(); // Iterator
- typename unordered_set<T>::const_iterator end(); // Iterator
- int size(); // Set size
- unordered_set<T>* values(); // Return set contents
-};
-
-
-/**
- * Default constructor
- */
-template <class T>
-IoTSet<T>::IoTSet() {
-
-}
-
-
-/**
- * Useful constructor
- */
-template <class T>
-IoTSet<T>::IoTSet(const unordered_set<T>* s) {
-
- set = s;
-}
-
-
-/**
- * Default destructor
- */
-template <class T>
-IoTSet<T>::~IoTSet() {
-
-}
-
-
-/**
- * Find the object k in the set
- */
-template <class T>
-typename unordered_set<T>::const_iterator IoTSet<T>::find(const T& k) {
-
- return (new unordered_set<T>(*set))->find(k);
-}
-
-
-/**
- * Return the "begin" iterator
- */
-template <class T>
-typename unordered_set<T>::const_iterator IoTSet<T>::begin() {
-
- return (new unordered_set<T>(*set))->begin();
-}
-
-
-/**
- * Return the "end" iterator
- */
-template <class T>
-typename unordered_set<T>::const_iterator IoTSet<T>::end() {
-
- return (new unordered_set<T>(*set))->end();
-}
-
-
-/**
- * Return the size of the set
- */
-template <class T>
-int IoTSet<T>::size() {
-
- return set->size();
-}
-
-
-/**
- * Return a new copy of the set
- */
-template <class T>
-unordered_set<T>* IoTSet<T>::values() {
-
- return new unordered_set<T>(*set);
-}
-#endif
-
+++ /dev/null
-#ifndef _IOTUDP_H__
-#define _IOTUDP_H__
-#include <iostream>
-
-#include "IoTDeviceAddress.h"
-
-using namespace std;
-
-// IoTUDP class for iotruntime
-// Implemented based on IoTUDP.java that is used to wrap communication socket for UDP
-//
-// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
-// @version 1.0
-// @since 2017-01-09
-
-class IoTUDP final
-{
- // IoTUDP class properties
- private:
- //UDPSocket *socket;
- UDP socket;
- IPAddress strHostAddress;
- int iSrcPort;
- int iDstPort;
- bool didClose;
- int timeOut;
-
- public:
-
- // Constructor
- IoTUDP(IoTDeviceAddress* iotDevAdd) {
-
- strHostAddress = iotDevAdd->getAddress();
- iSrcPort = iotDevAdd->getSourcePortNumber();
- iDstPort = iotDevAdd->getDestinationPortNumber();
- timeOut = 0;
-
- socket.begin(iSrcPort);
- didClose = false;
- }
-
-
- ~IoTUDP() {
- }
-
-
- IPAddress getHostAddress() {
- return strHostAddress;
- }
-
-
- int getSourcePort() {
- return iSrcPort;
- }
-
-
- int getDestinationPort() {
- return iDstPort;
- }
-
-
- void setTimeOut(int interval) {
-
- timeOut = interval;
- }
-
-
- // Send data packet
- void sendData(const char* buffer, int bufferLen) {
-
- unsigned short destinationPort = (unsigned short) iDstPort;
- IPAddress ipFromBytes(strHostAddress);
- socket.sendPacket(buffer, bufferLen, strHostAddress, destinationPort);
- }
-
-
- // Receive data packet
- int receiveData(char* buffer, int iMaxDataLength) {
-
- return socket.receivePacket(buffer, iMaxDataLength);
- }
-};
-#endif
+++ /dev/null
-#ifndef _LIFXHEADER_H__
-#define _LIFXHEADER_H__
-#include <iostream>
-
-class LifxHeader {
-
- private:
- // Frame variables
- int size;
- int origin;
- bool tagged;
- bool addressable;
- int protocol;
- int64_t source;
-
- // Frame address variables
- char macAddress[8];
- bool ack_required;
- bool res_required;
- int sequence;
-
- // Protocol header
- int type;
-
- public:
-
- LifxHeader() {
- origin = 0;
- addressable = true;
- protocol =1024;
- }
-
-
- ~LifxHeader() {
- }
-
-
- void setSize(int _size) {
- if (_size < 0) {
- cerr << "Header: size cannot be less than 0" << endl;
- exit(1);
- } else if (_size > 65535) {
- cerr << "Header: size too large" << endl;
- exit(1);
- }
- size = _size;
- }
-
-
- void setOrigin(int _origin) {
- if (_origin < 0) {
- cerr << "Header: origin cannot be less than 0" << endl;
- exit(1);
- } else if (_origin > 3) {
- cerr << "Header: origin too large" << endl;
- exit(1);
- }
- origin = _origin;
- }
-
-
- void setTagged(bool _tagged) {
- tagged = _tagged;
- }
-
-
- void setAddressable(bool _addressable) {
- addressable = _addressable;
- }
-
-
- void setProtocol(int _protocol) {
- if (_protocol < 0) {
- cerr << "Header: protocol cannot be less than 0" << endl;
- exit(1);
- } else if (_protocol > 4095) {
- cerr << "Header: protocol too large" << endl;
- exit(1);
- }
- protocol = _protocol;
- }
-
-
- void setSource(int64_t _source) {
- if (_source < 0) {
- cerr << "Header: source cannot be less than 0" << endl;
- exit(1);
- } else if (_source > 4294967295) {
- cerr << "Header: source too large" << endl;
- exit(1);
- }
- source = _source;
- }
-
-
- void setSequence(int _sequence) {
- if (_sequence < 0) {
- cerr << "Header: sequence cannot be less than 0" << endl;
- exit(1);
- } else if (_sequence > 255) {
- cerr << "Header: sequence too large" << endl;
- exit(1);
- }
- sequence = _sequence;
- }
-
-
- void setType(int _type) {
- if (_type < 0) {
- cerr << "Header: type cannot be less than 0" << endl;
- exit(1);
- } else if (_type > 65535) {
- cerr << "Header: type too large" << endl;
- exit(1);
- }
- type = _type;
- }
-
-
- void setAck_required(bool _ack_required) {
- ack_required = _ack_required;
- }
-
-
- void setRes_required(bool _res_required) {
- res_required = _res_required;
- }
-
-
- void setMacAddress(char _macAddress[8]) {
- strcpy(macAddress, _macAddress);
- }
-
-
- int getSize() {
- return size;
- }
-
-
- int getOrigin() {
- return origin;
- }
-
-
- bool getTagged() {
- return tagged;
- }
-
-
- bool getAddressable() {
- return addressable;
- }
-
-
- int getProtocol() {
- return protocol;
- }
-
-
- int64_t getSource() {
- return source;
- }
-
-
- int64_t getSequence() {
- return sequence;
- }
-
-
- int getType() {
- return type;
- }
-
-
- char* getHeaderBytes(char headerBytes[36]) {
-
- //char headerBytes[36];
- headerBytes[0] = (char)(size & 0xFF);
- headerBytes[1] = (char)((size >> 8) & 0xFF);
-
-
- headerBytes[2] = (char)(protocol & 0xFF);
- headerBytes[3] = (char)((protocol >> 8) & 0x0F);
-
- headerBytes[3] |= (char)((origin & 0x03) << 6);
-
- if (tagged) {
- headerBytes[3] |= (1 << 5);
- }
-
- if (addressable) {
- headerBytes[3] |= (1 << 4);
- }
-
- headerBytes[4] = (char)((source >> 0) & 0xFF);
- headerBytes[5] = (char)((source >> 8) & 0xFF);
- headerBytes[6] = (char)((source >> 16) & 0xFF);
- headerBytes[7] = (char)((source >> 24) & 0xFF);
-
- // fix in a bit
- headerBytes[8] = macAddress[0];
- headerBytes[9] = macAddress[1];
- headerBytes[10] = macAddress[2];
- headerBytes[11] = macAddress[3];
- headerBytes[12] = macAddress[4];
- headerBytes[13] = macAddress[5];
- headerBytes[14] = macAddress[6];
- headerBytes[15] = macAddress[7];
-
- // Reserved and set to 0
- headerBytes[16] = 0;
- headerBytes[17] = 0;
- headerBytes[18] = 0;
- headerBytes[19] = 0;
- headerBytes[20] = 0;
- headerBytes[21] = 0;
-
- if (ack_required) {
- headerBytes[22] = (1 << 1);
- }
-
- if (res_required) {
- headerBytes[22] |= (1);
- }
-
- headerBytes[23] = (char)(sequence & 0xFF);
-
- // Reserved and set to 0
- headerBytes[24] = 0;
- headerBytes[25] = 0;
- headerBytes[26] = 0;
- headerBytes[27] = 0;
- headerBytes[28] = 0;
- headerBytes[29] = 0;
- headerBytes[30] = 0;
- headerBytes[31] = 0;
-
- headerBytes[32] = (char)((type >> 0) & 0xFF);
- headerBytes[33] = (char)((type >> 8) & 0xFF);
-
- // Reserved and set to 0
- headerBytes[34] = 0;
- headerBytes[35] = 0;
-
- return headerBytes;
- }
-
-
- void setFromBytes(char dataBytes[36]) {
-
- size = dataBytes[0] & 0xFF;
- size |= ((dataBytes[1] & 0xFF) << 8);
- size &= 0xFFFF;
-
- origin = (dataBytes[3] >> 6) & 0x03;
- tagged = ((dataBytes[3] >> 5) & 0x01) == 1;
- addressable = ((dataBytes[3] >> 4) & 0x01) == 1;
-
-
- protocol = (dataBytes[3] & 0x0F) << 8;
- protocol |= dataBytes[2];
- protocol &= 0x0FFF;
-
- source = (dataBytes[7] & 0xFFl) << 24;
- source |= ((dataBytes[6] & 0xFFl) << 16);
- source |= ((dataBytes[5] & 0xFFl) << 8);
- source |= ((dataBytes[4] & 0xFFl));
-
- macAddress[0] = dataBytes[8];
- macAddress[1] = dataBytes[9];
- macAddress[2] = dataBytes[10];
- macAddress[3] = dataBytes[11];
- macAddress[4] = dataBytes[12];
- macAddress[5] = dataBytes[13];
- macAddress[6] = dataBytes[14];
- macAddress[7] = dataBytes[15];
-
- ack_required = (dataBytes[22] & 0x02) == 0x02;
- res_required = (dataBytes[22] & 0x01) == 0x01;
-
- sequence = (dataBytes[23] & 0xFF);
-
- type = ((dataBytes[33] & 0xFF) << 8);
- type |= (dataBytes[32] & 0xFF);
- }
-};
-#endif
+++ /dev/null
-#include <iostream>
-#include <string>
-#include <thread>
-
-#include <pthread.h>
-
-#include "LifxLightBulb.h"
-#include "IoTSet.h"
-#include "IoTDeviceAddress.h"
-#include "application.h"
-
-using namespace std;
-
-
-// Default constructor
-LifxLightBulb::LifxLightBulb() {
-
-}
-
-
-// Constructor
-LifxLightBulb::LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort) {
-
- memcpy(bulbMacAddress, macAddress, 8);
-
- // Initialize device address
- // Port 56700 is the default port for Lifx
- IoTDeviceAddress* devAddress = new IoTDeviceAddress(ipAddress, srcPort, 56700, false, false);
- unordered_set<void*>* myset1 = new unordered_set<void*>();
- myset1->insert(devAddress);
- IoTSet<void*>* setDevAddress = new IoTSet<void*>(myset1);
- lb_addresses = setDevAddress;
-}
-
-
-LifxLightBulb::~LifxLightBulb() {
-
- // Clean up
- if (communicationSocket != NULL) {
-
- delete communicationSocket;
- communicationSocket = NULL;
- }
- for(void* dev : *lb_addresses) {
- IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
- delete dv;
- dv = NULL;
- }
- if (lb_addresses != NULL) {
-
- delete lb_addresses;
- lb_addresses = NULL;
- }
-}
-
-
-// PUBLIC METHODS
-// Initialize the lightbulb
-void LifxLightBulb::init() {
-
- if (didAlreadyInit)
- return;
- // Set to true if not yet
- didAlreadyInit = true;
-
- unordered_set<void*>::const_iterator itr = lb_addresses->begin();
- IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
-
- // Create IoTUDP socket
- communicationSocket = new IoTUDP(deviceAddress);
-
- //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
- //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
- //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
-
- // Launch the worker function in a separate thread.
- // NOTE: "this" pointer is passed into the detached thread because it does not belong
- // to this object anymore so if it executes certain methods of "this" object, then it needs
- // the correct references to stuff
- thread th1 (&LifxLightBulb::workerFunction, this, this);
- th1.detach();
-}
-
-
-void LifxLightBulb::turnOff() {
-
- //lock_guard<mutex> guard(bulbStateMutex);
- bulbStateMutex.lock();
- bulbIsOn = false;
- sendSetLightPowerPacket(0, 0);
- stateDidChange = true;
- bulbStateMutex.unlock();
-}
-
-
-void LifxLightBulb::turnOn() {
-
- //lock_guard<mutex> guard(bulbStateMutex);
- bulbStateMutex.lock();
- bulbIsOn = true;
- sendSetLightPowerPacket(65535, 0);
- stateDidChange = true;
- bulbStateMutex.unlock();
-}
-
-
-double LifxLightBulb::getHue() {
- double tmp = 0;
- settingBulbColorMutex.lock();
- tmp = ((double)currentHue / 65535.0) * 360.0;
- settingBulbColorMutex.unlock();
-
- return tmp;
-}
-
-
-double LifxLightBulb::getSaturation() {
- double tmp = 0;
- settingBulbColorMutex.lock();
- tmp = ((double)currentSaturation / 65535.0) * 360.0;
- settingBulbColorMutex.unlock();
-
- return tmp;
-}
-
-
-double LifxLightBulb::getBrightness() {
- double tmp = 0;
- settingBulbColorMutex.lock();
- tmp = ((double)currentBrightness / 65535.0) * 360.0;
- settingBulbColorMutex.unlock();
-
- return tmp;
-}
-
-
-int LifxLightBulb::getTemperature() {
-
- int tmp = 0;
- settingBulbTemperatureMutex.lock();
- tmp = currentTemperature;
- settingBulbTemperatureMutex.unlock();
-
- return tmp;
-}
-
-
-double LifxLightBulb::getHueRangeLowerBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)hueLowerBound / 65535.0) * 360.0;
-}
-
-
-double LifxLightBulb::getHueRangeUpperBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)hueUpperBound / 65535.0) * 360.0;
-}
-
-
-double LifxLightBulb::getSaturationRangeLowerBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)saturationLowerBound / 65535.0) * 100.0;
-}
-
-
-double LifxLightBulb::getSaturationRangeUpperBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)saturationUpperBound / 65535.0) * 100.0;
-}
-
-
-double LifxLightBulb::getBrightnessRangeLowerBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)brightnessLowerBound / 65535.0) * 100.0;
-}
-
-
-double LifxLightBulb::getBrightnessRangeUpperBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return ((double)brightnessUpperBound / 65535.0) * 100.0;
-}
-
-
-int LifxLightBulb::getTemperatureRangeLowerBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return temperatureLowerBound;
-}
-
-
-int LifxLightBulb::getTemperatureRangeUpperBound() {
- if (!didGetBulbVersion) {
- return -1;
- }
- return temperatureUpperBound;
-}
-
-
-void LifxLightBulb::setTemperature(int _temperature) {
-
- settingBulbTemperatureMutex.lock();
-
- BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
- sendSetLightColorPacket(newColor, 250);
-
- currentTemperature = _temperature;
- stateDidChange = true;
-
- settingBulbTemperatureMutex.unlock();
-}
-
-
-void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
-
- settingBulbColorMutex.lock();
-
- _hue /= 360.0;
- _saturation /= 100.0;
- _brightness /= 100.0;
-
-
- int newHue = (int)(_hue * 65535.0);
- int newSaturation = (int)(_saturation * 65535.0);
- int newBrightness = (int)(_brightness * 65535.0);
-
- BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
- sendSetLightColorPacket(newColor, 250);
-
- currentHue = newHue;
- currentSaturation = newSaturation;
- currentBrightness = newBrightness;
- stateDidChange = true;
-
- settingBulbColorMutex.unlock();
-}
-
-
-bool LifxLightBulb::getState() {
-
- bool tmp = false;
-
- bulbStateMutex.lock();
- tmp = bulbIsOn;
- bulbStateMutex.unlock();
-
- return tmp;
-}
-
-
-// PRIVATE METHODS
-// Communication helpers
-void LifxLightBulb::receivedPacket(char* packetData) {
-
- char headerBytes[36];
- for (int i = 0; i < 36; i++) {
- headerBytes[i] = packetData[i];
- }
-
- LifxHeader recHeader;
- recHeader.setFromBytes(headerBytes);
-
- // load the payload bytes (strip away the header)
- char* payloadBytes = new char[recHeader.getSize()];
- for (int i = 36; i < recHeader.getSize(); i++) {
- payloadBytes[i - 36] = packetData[i];
- }
-
- int type = recHeader.getType();
- //cout << "Received: " << type << endl;
-
- DeviceStateService* dat = NULL;
- switch (type) {
-
- case 3:
- dat = parseDeviceStateServiceMessage(payloadBytes);
- //cout << "Service: " << dat->getService();
- //cout << "Port : " << dat->getPort();
- // Avoid memory leak - delete this object
- delete dat;
- break;
-
- case 33:
- handleStateVersionMessageReceived(payloadBytes);
- break;
-
- case 35:
- parseDeviceStateInfoMessage(payloadBytes);
- break;
-
-
- case 107:
- handleLightStateMessageReceived(payloadBytes);
- break;
-
- default:
- break;
- //cout << "unknown packet Type" << endl;
- }
- // Avoid memory leaks
- delete payloadBytes;
-}
-
-
-void LifxLightBulb::sendPacket(char* packetData, int len) {
- //cout << "sendPacket: About to send" << endl;
- lock_guard<mutex> guard(socketMutex);
- sendSocketFlag = true;
- communicationSocket->sendData(packetData, len);
- sendSocketFlag = false;
-}
-
-
-// Worker function which runs the while loop for receiving data from the bulb.
-// Is blocking.
-void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
-
- // Need timeout on receives since we are not sure if a packet will be available
- // for processing so don't block waiting
- llb->communicationSocket->setTimeOut(50000); // In milliseconds
- llb->turnOff();
-
- int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
- char dat[1024];
-
- while (true) {
- // Check if we got the bulb version yet
- // could have requested it but message could have gotten lost (UDP)
- if (!llb->didGetBulbVersion) {
- int64_t currentTime = (int64_t) time(NULL);
- if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
- // Get the bulb version so we know what type of bulb this is.
- //cout << "Sending version packet! " << endl;
- llb->sendGetVersionPacket();
- lastSentGetBulbVersionRequest = currentTime;
- }
- }
-
- // Communication resource is busy so try again later
- if (llb->sendSocketFlag) {
- continue;
- }
-
- llb->socketMutex.lock();
- int ret = llb->communicationSocket->receiveData(dat, 1024);
- // Never forget to release!
- llb->socketMutex.unlock();
-
- // A packed arrived
- if (ret != -1) {
- llb->receivedPacket(dat);
- }
-
- // If a state change occurred then request the bulb state to ensure that the
- // bulb did indeed change its state to the correct state
- if (llb->stateDidChange) {
- llb->sendGetLightStatePacket();
- }
-
- // Wait a bit as to not tie up system resources
- //this_thread::sleep_for (chrono::milliseconds(100));
- delay(100);
- //cout << endl << "Sleep and wake up!" << endl;
- }
-}
-
-
-// Sending
-// Device Messages
-void LifxLightBulb::sendGetServicePacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(true);
- header.setMacAddress(bulbMacAddress);
- header.setSource(0); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(2);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetHostInfoPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(12);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetHostFirmwarePacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(14);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetWifiInfoPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(16);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetWifiFirmwarePacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(18);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetPowerPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(20);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendSetPowerPacket(int level) {
- // Currently only 0 and 65535 are supported
- // This is a fix for now
- if ((level != 65535) && (level != 0)) {
- cerr << "Invalid parameter values" << endl;
- exit(1);
- }
-
- if ((level > 65535) || (level < 0)) {
- cerr << "Invalid parameter values" << endl;
- exit(1);
- }
-
- char packetBytes[38];
-
- LifxHeader header;
- header.setSize(38);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(21);
- char headerBytes[36];
- header.getHeaderBytes(headerBytes);
-
- for (int i = 0; i < 36; i++) {
- packetBytes[i] = headerBytes[i];
- }
-
- packetBytes[36] = (char)(level & 0xFF);
- packetBytes[37] = (char)((level >> 8) & 0xFF);
-
- sendPacket(packetBytes, 38);
-}
-
-
-void LifxLightBulb::sendGetLabelPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(23);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendSetLabelPacket(string label) {
- // Currently only 0 and 65535 are supported
- // This is a fix for now
- if (label.length() != 32) {
- cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
- exit(1);
- }
-
- char packetBytes[68];
-
- LifxHeader header;
- header.setSize(68);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(24);
- char headerBytes[36];
- header.getHeaderBytes(headerBytes);
-
- for (int i = 0; i < 36; i++) {
- packetBytes[i] = headerBytes[i];
- }
-
- for (int i = 0; i < 32; i++) {
- packetBytes[i + 36] = label.c_str()[i];
- }
-
- sendPacket(packetBytes, 68);
-}
-
-
-void LifxLightBulb::sendGetVersionPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(32);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetInfoPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(34);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetLocationPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(34);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendGetGroupPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(51);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-// Sending
-// Light Messages
-void LifxLightBulb::sendGetLightStatePacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(101);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
-
- if ((duration > 4294967295l) || (duration < 0)) {
- cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
- exit(1);
- }
-
- char packetBytes[49];
-
- LifxHeader header;
- header.setSize(49);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(102);
- char headerBytes[36];
- header.getHeaderBytes(headerBytes);
-
- for (int i = 0; i < 36; i++) {
- packetBytes[i] = headerBytes[i];
- }
-
- // 1 reserved packet
- packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
- packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
-
- packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
- packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
-
- packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
- packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
-
- packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
- packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
-
- packetBytes[45] = (char)((duration >> 0) & 0xFF);
- packetBytes[46] = (char)((duration >> 8) & 0xFF);
- packetBytes[47] = (char)((duration >> 16) & 0xFF);
- packetBytes[48] = (char)((duration >> 24) & 0xFF);
-
- sendPacket(packetBytes, 49);
- // Avoid memory leak - delete object
- delete bulbColor;
-}
-
-
-void LifxLightBulb::sendGetLightPowerPacket() {
- LifxHeader header;
- header.setSize(36);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(116);
-
- char dataBytes[36];
- header.getHeaderBytes(dataBytes);
-
- sendPacket(dataBytes, 36);
-}
-
-
-void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
-
- if ((level > 65535) || (duration > 4294967295l)
- || (level < 0) || (duration < 0)) {
- cerr << "Invalid parameter values" << endl;
- exit(1);
- }
- char packetBytes[42];
-
- LifxHeader header;
- header.setSize(42);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(117);
- char headerBytes[36];
- header.getHeaderBytes(headerBytes);
-
- for (int i = 0; i < 36; i++) {
- packetBytes[i] = headerBytes[i];
- }
-
- packetBytes[36] = (char)(level & 0xFF);
- packetBytes[37] = (char)((level >> 8) & 0xFF);
-
- packetBytes[38] = (char)((duration >> 0) & 0xFF);
- packetBytes[39] = (char)((duration >> 8) & 0xFF);
- packetBytes[40] = (char)((duration >> 16) & 0xFF);
- packetBytes[41] = (char)((duration >> 24) & 0xFF);
-
- sendPacket(packetBytes, 42);
-}
-
-
-void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
-
- char packetBytes[100];
-
- LifxHeader header;
- header.setSize(100);
- header.setTagged(false);
- header.setMacAddress(bulbMacAddress);
- header.setSource(10); // randomly picked
- header.setAck_required(false);
- header.setRes_required(false);
- header.setSequence(0);
- header.setType(58);
- char headerBytes[36];
- header.getHeaderBytes(headerBytes);
-
- for (int i = 0; i < 36; i++) {
- packetBytes[i] = headerBytes[i];
- }
-
- for (int i = 0; i < 64; i++) {
- packetBytes[i + 36] = data[i];
- }
-
- sendPacket(packetBytes, 100);
-}
-
-
-// Receiving
-// Device Messages
-DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
- int service = payloadData[0];
- int64_t port = ((payloadData[3] & 0xFF) << 24);
- port |= ((payloadData[2] & 0xFF) << 16);
- port |= ((payloadData[1] & 0xFF) << 8);
- port |= (payloadData[0] & 0xFF);
-
- return new DeviceStateService(service, port);
-}
-
-
-DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
- long signal = ((payloadData[3] & 0xFF) << 24);
- signal |= ((payloadData[2] & 0xFF) << 16);
- signal |= ((payloadData[1] & 0xFF) << 8);
- signal |= (payloadData[0] & 0xFF);
-
- long tx = ((payloadData[7] & 0xFF) << 24);
- tx |= ((payloadData[6] & 0xFF) << 16);
- tx |= ((payloadData[5] & 0xFF) << 8);
- tx |= (payloadData[4] & 0xFF);
-
- long rx = ((payloadData[11] & 0xFF) << 24);
- rx |= ((payloadData[10] & 0xFF) << 16);
- rx |= ((payloadData[9] & 0xFF) << 8);
- rx |= (payloadData[8] & 0xFF);
-
- return new DeviceStateHostInfo(signal, tx, rx);
-}
-
-
-DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
- long build = 0;
- for (int i = 0; i < 8; i++) {
- build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
- }
-
- // 8 reserved bytes
-
- int64_t version = ((payloadData[19] & 0xFF) << 24);
- version |= ((payloadData[18] & 0xFF) << 16);
- version |= ((payloadData[17] & 0xFF) << 8);
- version |= (payloadData[16] & 0xFF);
-
- return new DeviceStateHostFirmware(build, version);
-}
-
-
-DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
- int64_t signal = ((payloadData[3] & 0xFF) << 24);
- signal |= ((payloadData[2] & 0xFF) << 16);
- signal |= ((payloadData[1] & 0xFF) << 8);
- signal |= (payloadData[0] & 0xFF);
-
- int64_t tx = ((payloadData[7] & 0xFF) << 24);
- tx |= ((payloadData[6] & 0xFF) << 16);
- tx |= ((payloadData[5] & 0xFF) << 8);
- tx |= (payloadData[4] & 0xFF);
-
- int64_t rx = ((payloadData[11] & 0xFF) << 24);
- rx |= ((payloadData[10] & 0xFF) << 16);
- rx |= ((payloadData[9] & 0xFF) << 8);
- rx |= (payloadData[8] & 0xFF);
-
- return new DeviceStateWifiInfo(signal, tx, rx);
-}
-
-
-DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
- long build = 0;
- for (int i = 0; i < 8; i++) {
- build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
- }
-
- // 8 reserved bytes
-
- int64_t version = ((payloadData[19] & 0xFF) << 24);
- version |= ((payloadData[18] & 0xFF) << 16);
- version |= ((payloadData[17] & 0xFF) << 8);
- version |= (payloadData[16] & 0xFF);
-
- return new DeviceStateWifiFirmware(build, version);
-}
-
-
-int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
- int level = ((payloadData[1] & 0xFF) << 8);
- level |= (payloadData[0] & 0xFF);
- return level;
-}
-
-
-DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
- int64_t vender = ((payloadData[3] & 0xFF) << 24);
- vender |= ((payloadData[2] & 0xFF) << 16);
- vender |= ((payloadData[1] & 0xFF) << 8);
- vender |= (payloadData[0] & 0xFF);
-
- int64_t product = ((payloadData[7] & 0xFF) << 24);
- product |= ((payloadData[6] & 0xFF) << 16);
- product |= ((payloadData[5] & 0xFF) << 8);
- product |= (payloadData[4] & 0xFF);
-
- int64_t version = ((payloadData[11] & 0xFF) << 24);
- version |= ((payloadData[10] & 0xFF) << 16);
- version |= ((payloadData[9] & 0xFF) << 8);
- version |= (payloadData[8] & 0xFF);
-
- return new DeviceStateVersion(vender, product, version);
-}
-
-
-DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
- int64_t time = 0;
- int64_t upTime = 0;
- int64_t downTime = 0;
- for (int i = 0; i < 8; i++) {
- time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
- upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
- downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
- }
-
- return new DeviceStateInfo(time, upTime, downTime);
-}
-
-
-DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
- char location[16];
- for (int i = 0; i < 16; i++) {
- location[i] = payloadData[i];
- }
-
- char labelBytes[32];
- for (int i = 0; i < 32; i++) {
- labelBytes[i] = payloadData[i + 16];
- }
-
- int64_t updatedAt = 0;
- for (int i = 0; i < 8; i++) {
- updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
- }
-
- string str(labelBytes);
- return new DeviceStateLocation(location, str, updatedAt);
-}
-
-
-DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
- char group[16];
- for (int i = 0; i < 16; i++) {
- group[i] = payloadData[i];
- }
-
- char labelBytes[32];
- for (int i = 0; i < 32; i++) {
- labelBytes[i] = payloadData[i + 16];
- }
-
- int64_t updatedAt = 0;
- for (int i = 0; i < 8; i++) {
- updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
- }
-
- string str(labelBytes);
- return new DeviceStateGroup(group, str, updatedAt);
-}
-
-
-// Receiving
-// Light Messages
-LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
-
- char colorData[8];
- for (int i = 0; i < 8; i++) {
- colorData[i] = payloadData[i];
- }
- //BulbColor color(colorData);
- BulbColor* color = new BulbColor(colorData);
-
- int power = ((payloadData[11] & 0xFF) << 8);
- power |= (payloadData[10] & 0xFF);
-
- string label(payloadData);
-
- char labelArray[32];
- for (int i = 0; i < 32; i++) {
- labelArray[i] = payloadData[12 + i];
- }
-
- return new LightState(color, power, label);
-}
-
-
-int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
- int level = ((payloadData[1] & 0xFF) << 8);
- level |= (payloadData[0] & 0xFF);
- return level;
-}
-
-
-// Private Handlers
-void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
-
- DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
- int productNumber = (int)deviceState->getProduct();
-
- bool isColor = false;
-
- if (productNumber == 1) {// Original 1000
- isColor = true;
- } else if (productNumber == 3) {//Color 650
- isColor = true;
- } else if (productNumber == 10) {// White 800 (Low Voltage)
- isColor = false;
- } else if (productNumber == 11) {// White 800 (High Voltage)
- isColor = false;
- } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
- isColor = false;
- } else if (productNumber == 20) {// Color 1000 BR30
- isColor = true;
- } else if (productNumber == 22) {// Color 1000
- isColor = true;
- }
-
- if (isColor) {
- hueLowerBound = 0;
- hueUpperBound = 65535;
- saturationLowerBound = 0;
- saturationUpperBound = 65535;
- brightnessLowerBound = 0;
- brightnessUpperBound = 65535;
- temperatureLowerBound = 2500;
- temperatureUpperBound = 9000;
- } else {
- hueLowerBound = 0;
- hueUpperBound = 0;
- saturationLowerBound = 0;
- saturationUpperBound = 0;
- brightnessLowerBound = 0;
- brightnessUpperBound = 65535;// still can dim bulb
- temperatureLowerBound = 2500;
- temperatureUpperBound = 9000;
- }
-
- //didGetBulbVersion.exchange(true);
- didGetBulbVersion = true;
- // Avoid memory leak - delete this object
- delete deviceState;
-}
-
-
-void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
- LightState* lightState = parseLightStateMessage(payloadData);
-
- BulbColor* color = lightState->getColor();
- int power = lightState->getPower();
-
- //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
- //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
- //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
- //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
-
- bool bulbWrongColor = false;
- bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
- bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
- bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
- bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
-
-
- // gets set to true if any of the below if statements are taken
- stateDidChange = false;
-
- if (bulbWrongColor) {
- BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
- sendSetLightColorPacket(newColor, 250);
- //cout << "Failed Check 1" << endl;
- }
-
- bulbStateMutex.lock();
- bool bulbIsOnTmp = bulbIsOn;
- bulbStateMutex.unlock();
-
- if ((!bulbIsOnTmp) && (power != 0)) {
- turnOff();
- //cout << "Failed Check 2: " << endl;
-
- }
-
- if (bulbIsOnTmp && (power < 65530)) {
- turnOn();
- //cout << "Failed Check 3: " << endl;
-
- }
- // Avoid memory leak - delete object
- delete lightState;
- delete color;
-}
-
+++ /dev/null
-#ifndef _LIFXLIGHTBULB_H__
-#define _LIFXLIGHTBULB_H__
-#include <iostream>
-#include <fstream>
-#include <atomic>
-#include <mutex>
-#include <thread>
-#include <chrono>
-
-#include <string.h>
-#include <time.h>
-
-#include "LightBulb.h"
-//#include "Socket.h"
-#include "IoTSet.h"
-#include "IoTUDP.h"
-#include "IoTDeviceAddress.h"
-
-// Helper classes for LifxLightBulb
-#include "LifxHeader.h"
-#include "BulbColor.h"
-#include "DeviceStateGroup.h"
-#include "DeviceStateHostFirmware.h"
-#include "DeviceStateHostInfo.h"
-#include "DeviceStateInfo.h"
-#include "DeviceStateLocation.h"
-#include "DeviceStateService.h"
-#include "DeviceStateVersion.h"
-#include "DeviceStateWifiFirmware.h"
-#include "DeviceStateWifiInfo.h"
-#include "LightState.h"
-
-
-using namespace std;
-
-// Driver LifxLightBulb
-// Implemented based on LightBulb virtual class (interface)
-
-class LifxLightBulb : public LightBulb
-{
- private:
- // Constants
- const static int64_t GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
-
- // Variables
- IoTUDP *communicationSocket;
- char bulbMacAddress[8];
- //TODO:
- bool sendSocketFlag = false;
-
- // Current Bulb Values
- int currentHue = 0;
- int currentSaturation = 0;
- int currentBrightness = 65535;
- int currentTemperature = 9000;
- bool bulbIsOn = false;
-
- bool didAlreadyInit = false;
- bool didGetBulbVersion = false;
-
- // Mutex locks
- mutex socketMutex;
- mutex settingBulbColorMutex;
- mutex settingBulbTemperatureMutex;
- mutex bulbStateMutex;
-
- // color and temperature ranges for the bulbs
- int hueLowerBound = 0;
- int hueUpperBound = 0;
- int saturationLowerBound = 0;
- int saturationUpperBound = 0;
- int brightnessLowerBound = 0;
- int brightnessUpperBound = 0;
- int temperatureLowerBound = 2500;
- int temperatureUpperBound = 9000;
-
- // Check if a state change was requested, used to poll the bulb for if the bulb did
- // preform the requested state change
- bool stateDidChange = false;
-
- // Device address
- IoTSet<void*>* lb_addresses; // IoTSet<IoTDeviceAddress*>* lb_addresses
-
- // Logging
- ofstream log;
- public:
-
- // Constructor
- LifxLightBulb();
- LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort);
- ~LifxLightBulb();
- // Initialize the lightbulb
- void init();
- void turnOff();
- void turnOn();
- double getHue();
- double getSaturation();
- double getBrightness();
- int getTemperature();
- double getHueRangeLowerBound();
- double getHueRangeUpperBound();
- double getSaturationRangeLowerBound();
- double getSaturationRangeUpperBound();
- double getBrightnessRangeLowerBound();
- double getBrightnessRangeUpperBound();
- int getTemperatureRangeLowerBound();
- int getTemperatureRangeUpperBound();
- void setTemperature(int _temperature);
- void setColor(double _hue, double _saturation, double _brightness);
- bool getState();
-
- private:
- // Private functions
- // Communication helpers
- void receivedPacket(char* packetData);
- void sendPacket(char* packetData, int len);
- // Worker function which runs the while loop for receiving data from the bulb.
- // Is blocking.
- void workerFunction(LifxLightBulb* llb);
- // Sending
- // Device Messages
- void sendGetServicePacket();
- void sendGetHostInfoPacket();
- void sendGetHostFirmwarePacket();
- void sendGetWifiInfoPacket();
- void sendGetWifiFirmwarePacket();
- void sendGetPowerPacket();
- void sendSetPowerPacket(int level);
- void sendGetLabelPacket();
- void sendSetLabelPacket(string label);
- void sendGetVersionPacket();
- void sendGetInfoPacket();
- void sendGetLocationPacket();
- void sendGetGroupPacket();
- // Sending
- // Light Messages
- void sendGetLightStatePacket();
- void sendSetLightColorPacket(BulbColor* bulbColor, long duration);
- void sendGetLightPowerPacket();
- void sendSetLightPowerPacket(int level, long duration);
- void sendEchoRequestPacket(char data[64]);
- // Receiving
- // Device Messages
- DeviceStateService* parseDeviceStateServiceMessage(char* payloadData);
- DeviceStateHostInfo* parseDeviceStateHostInfoMessage(char* payloadData);
- DeviceStateHostFirmware* parseDeviceStateHostFirmwareMessage(char* payloadData);
- DeviceStateWifiInfo* parseDeviceStateWifiInfoMessage(char* payloadData);
- DeviceStateWifiFirmware* parseDeviceStateWifiFirmwareMessage(char* payloadData);
- int parseStatePowerMessage(char* payloadData);
- DeviceStateVersion* parseDeviceStateVersionMessage(char* payloadData);
- DeviceStateInfo* parseDeviceStateInfoMessage(char* payloadData);
- DeviceStateLocation* parseDeviceStateLocationMessage(char* payloadData);
- DeviceStateGroup* parseDeviceStateGroupMessage(char* payloadData);
- // Receiving
- // Light Messages
- LightState* parseLightStateMessage(char* payloadData);
- int parseLightStatePowerMessage(char* payloadData);
- // Private Handlers
- void handleStateVersionMessageReceived(char* payloadData);
- void handleLightStateMessageReceived(char* payloadData);
-};
-
-#endif
+++ /dev/null
-#ifndef _LIGHTBULB_H__
-#define _LIGHTBULB_H__
-#include <iostream>
-
-using namespace std;
-
-class LightBulb
-{
- public:
- virtual void init() = 0;
- virtual void turnOff() = 0;
- virtual void turnOn() = 0;
- virtual bool getState() = 0;
- virtual void setColor(double _hue, double _saturation, double _brightness) = 0;
- virtual void setTemperature(int _temperature) = 0;
- virtual double getBrightness() = 0;
- virtual double getHue() = 0;
- virtual double getSaturation() = 0;
- virtual int getTemperature() = 0;
- virtual double getBrightnessRangeLowerBound() = 0;
- virtual double getBrightnessRangeUpperBound() = 0;
- virtual double getHueRangeLowerBound() = 0;
- virtual double getHueRangeUpperBound() = 0;
- virtual double getSaturationRangeLowerBound() = 0;
- virtual double getSaturationRangeUpperBound() = 0;
- virtual int getTemperatureRangeLowerBound() = 0;
- virtual int getTemperatureRangeUpperBound() = 0;
-};
-#endif
+++ /dev/null
-#ifndef _LIGHTSTATE_H__
-#define _LIGHTSTATE_H__
-#include <iostream>
-
-#include "BulbColor.h"
-
-class LightState {
- private:
- BulbColor* color;
- int power;
- string label;
-
- public:
-
- LightState(BulbColor* _color, int _power, string _label) {
-
- color = _color;
- power = _power;
- label = _label;
- }
-
-
- ~LightState() {
- }
-
-
- BulbColor* getColor() {
- return color;
- }
-
-
- int getPower() {
- return power;
- }
-
-
- string getLabel() {
- return label;
- }
-};
-#endif
+++ /dev/null
-// ------------------------------------------------
-// Controlling LifxLightBulb through Particle Cloud
-// @author Rahmadi Trimananda - UC Irvine
-// ------------------------------------------------
-
-#include "LifxLightBulb.h"
-
-LifxLightBulb *llb1;
-LifxLightBulb *llb2;
-
-int led1 = D7;
-
-void setup()
-{
- // Bulb 1
- char macAddress1[8];
- macAddress1[0] = 0xD0;
- macAddress1[1] = 0x73;
- macAddress1[2] = 0xD5;
- macAddress1[3] = 0x12;
- macAddress1[4] = 0x8E;
- macAddress1[5] = 0x30;
- macAddress1[6] = 0x00;
- macAddress1[7] = 0x00;
- IPAddress devIPAddress1(192, 168, 1, 126);
-
- llb1 = new LifxLightBulb(devIPAddress1, macAddress1, 12345);
- llb1->init();
-
- // Bulb 2
- char macAddress2[8];
- macAddress2[0] = 0xD0;
- macAddress2[1] = 0x73;
- macAddress2[2] = 0xD5;
- macAddress2[3] = 0x02;
- macAddress2[4] = 0x41;
- macAddress2[5] = 0xDA;
- macAddress2[6] = 0x00;
- macAddress2[7] = 0x00;
- IPAddress devIPAddress2(192, 168, 1, 232);
-
- llb2 = new LifxLightBulb(devIPAddress2, macAddress2, 12346);
- llb2->init();
-
- pinMode(led1, OUTPUT);
- Particle.function("lifx1",lifx1Toggle);
- Particle.function("lifx2",lifx2Toggle);
-}
-
-
-void loop() {
- // Nothing to do here
-}
-
-
-// Toggling Lifx light bulb 1
-int lifx1Toggle(String command) {
-
- if (command=="on") {
- llb1->turnOn();
- return 1;
- }
- else if (command=="off") {
- llb1->turnOff();
- return 0;
- }
- else {
- return -1;
- }
-}
-
-// Toggling Lifx light bulb 2
-int lifx2Toggle(String command) {
-
- if (command=="on") {
- llb2->turnOn();
- return 1;
- }
- else if (command=="off") {
- llb2->turnOff();
- return 0;
- }
- else {
- return -1;
- }
-}
+++ /dev/null
-include common.mk
-
-all: compile
-
-# To run Particle, we need to install Particle CLI
-# Please see:
-# https://docs.particle.io/guide/getting-started/connect/photon/#install-the-particle-cli
-monitor:
- sudo chmod 666 /dev/ttyACM0
- particle serial monitor
-
-compile-c:
- #g++ -c LifxLightBulb.cpp -o ./LifxLightBulb.o -Wall -O3 -g -I. -Wno-unused-variable -std=c++11 -pthread -pg
- g++ ./LifxLightBulb.cpp ./socket/Socket.cpp -o ./LifxLightBulb.o -Wall -Wno-unused-variable --std=c++11 -pthread -pg -I. -I./socket
-
-compile:
- rm -f *.bin
- particle compile raspberry-pi
- #particle compile photon
-
-
-flash:
- particle flash Pi-1 raspberry-pi*.bin
-
-PHONY += clean
-clean:
- rm -f *.bin
-
-PHONY += mrclean
-mrclean: clean
- rm -rf ../docs
-
-tabbing:
- uncrustify -c C.cfg --no-backup *.cpp
- uncrustify -c C.cfg --no-backup *.h
-
-wc:
- wc *.cpp *.h
-
-.PHONY: $(PHONY)
+++ /dev/null
-
-This is a RaspberryPi C++ implementation of Lifx light bulb controller.
-
-Created as a part of our testbed that will include smart home devices that will use Particle cloud.
+++ /dev/null
-# A few common Makefile items
-
-CC := gcc
-CXX := g++
-
-UNAME := $(shell uname)
-
-LIB_NAME := iotcloud
-LIB_SO := lib_$(LIB_NAME).so
-
-CPPFLAGS += -Wall -g -O0
-
-# Mac OSX options
-ifeq ($(UNAME), Darwin)
-CPPFLAGS += -D_XOPEN_SOURCE -DMAC
-endif
--- /dev/null
+#ifndef _BULBCOLOR_H__
+#define _BULBCOLOR_H__
+#include <iostream>
+
+class BulbColor {
+
+ private:
+ int hue;
+ int saturation;
+ int brightness;
+ int kelvin;
+
+ public:
+
+ BulbColor(int _hue, int _saturation, int _brightness, int _kelvin) {
+
+ if ((_hue > 65535) || (_hue < 0)) {
+ cerr << "BulbColor: Invalid parameter value for _hue (0-65535)" << endl;
+ exit(1);
+ }
+
+ if ((_saturation > 65535) || (_saturation < 0)) {
+ cerr << "BulbColor: Invalid parameter value for _saturation (0-65535)" << endl;
+ exit(1);
+ }
+
+ if ((_brightness > 65535) || (_brightness < 0)) {
+ cerr << "BulbColor: Invalid parameter value for _brightness (0-65535)" << endl;
+ exit(1);
+ }
+
+ if ((_kelvin > 65535) || (_kelvin < 0)) {
+ cerr << "BulbColor: Invalid parameter value for _kelvin (0-65535)" << endl;
+ exit(1);
+ }
+
+ hue = _hue;
+ saturation = _saturation;
+ brightness = _brightness;
+ kelvin = _kelvin;
+ }
+
+
+ BulbColor(char* data) {
+ hue = ((data[1] & 0xFF) << 8);
+ hue |= (data[0] & 0xFF);
+
+ saturation = ((data[3] & 0xFF) << 8);
+ saturation |= (data[2] & 0xFF);
+
+ brightness = ((data[5] & 0xFF) << 8);
+ brightness |= (data[4] & 0xFF);
+
+ kelvin = ((data[7] & 0xFF) << 8);
+ kelvin |= (data[6] & 0xFF);
+ }
+
+
+ ~BulbColor() {
+ }
+
+
+ int getHue() {
+ return hue;
+ }
+
+
+ int getSaturation() {
+ return saturation;
+ }
+
+
+ int getBrightness() {
+ return brightness;
+ }
+
+
+ int getKelvin() {
+ return kelvin;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEGROUP_H__
+#define _DEVICESTATEGROUP_H__
+#include <iostream>
+#include <string>
+
+class DeviceStateGroup {
+
+ private:
+ char group[16];
+ string label;
+ int64_t updatedAt;
+
+ public:
+
+ DeviceStateGroup(char _location[16], string _label, int64_t _updatedAt) {
+
+ strcpy(group, _location);
+ label = _label;
+ updatedAt = _updatedAt;
+ }
+
+
+ ~DeviceStateGroup() {
+ }
+
+
+ char* getGroup() {
+ return group;
+ }
+
+
+ string getLabel() {
+ return label;
+ }
+
+
+ int64_t getUpdatedAt() {
+ return updatedAt;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEHOSTFIRMWARE_H__
+#define _DEVICESTATEHOSTFIRMWARE_H__
+#include <iostream>
+
+class DeviceStateHostFirmware {
+ // time of build in nanosecond accuracy
+ // after some tests
+ private:
+ int64_t build;
+ int64_t version; // firmware version
+
+ public:
+
+ DeviceStateHostFirmware(int64_t _build, int64_t _version) {
+
+ build = _build;
+ version = _version;
+ }
+
+
+ ~DeviceStateHostFirmware() {
+ }
+
+
+ int64_t getBuild() {
+ return build;
+ }
+
+
+ int64_t getVersion() {
+ return version;
+ }
+
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEHOSTINFO_H__
+#define _DEVICESTATEHOSTINFO_H__
+#include <iostream>
+
+class DeviceStateHostInfo {
+ private:
+ int64_t signal;
+ int64_t tx;
+ int64_t rx;
+
+ public:
+
+ DeviceStateHostInfo(int64_t _signal, int64_t _tx, int64_t _rx) {
+
+ signal = _signal;
+ tx = _tx;
+ rx = _rx;
+ }
+
+
+ ~DeviceStateHostInfo() {
+ }
+
+
+ int64_t getSignal() {
+ return signal;
+ }
+
+
+ int64_t getTx() {
+ return tx;
+ }
+
+
+ int64_t getRx() {
+ return rx;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEINFO_H__
+#define _DEVICESTATEINFO_H__
+#include <iostream>
+
+class DeviceStateInfo {
+ private:
+ int64_t time;
+ int64_t upTime;
+ int64_t downTime;
+
+ public:
+
+ DeviceStateInfo(int64_t _time, int64_t _upTime, int64_t _downTime) {
+
+ time = _time;
+ upTime = _upTime;
+ downTime = _downTime;
+ }
+
+
+ ~DeviceStateInfo() {
+ }
+
+
+ int64_t getTime() {
+ return time;
+ }
+
+
+ int64_t getUpTime() {
+ return upTime;
+ }
+
+
+ int64_t getDownTime() {
+ return downTime;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATELOCATION_H__
+#define _DEVICESTATELOCATION_H__
+#include <iostream>
+#include <string>
+
+class DeviceStateLocation {
+ private:
+ char location[16];
+ string label;
+ int64_t updatedAt;
+
+ public:
+
+ DeviceStateLocation(char _location[16], string _label, long _updatedAt) {
+
+ strcpy(location, _location);
+ label = _label;
+ updatedAt = _updatedAt;
+ }
+
+
+ ~DeviceStateLocation() {
+ }
+
+
+ char* getLocation() {
+ return location;
+ }
+
+
+ string getLabel() {
+ return label;
+ }
+
+
+ int64_t getUpdatedAt() {
+ return updatedAt;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATESERVICE_H__
+#define _DEVICESTATESERVICE_H__
+#include <iostream>
+
+class DeviceStateService {
+ private:
+ int service;
+ int64_t port;
+
+ public:
+
+ DeviceStateService(int _service, long _port) {
+
+ service = _service;
+ port = _port;
+ }
+
+
+ ~DeviceStateService() {
+ }
+
+
+ int getService() {
+ return service;
+ }
+
+
+ int64_t getPort() {
+ return port;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEVERSION_H__
+#define _DEVICESTATEVERSION_H__
+#include <iostream>
+
+class DeviceStateVersion {
+ private:
+ int64_t vender;
+ int64_t product;
+ int64_t version;
+
+ public:
+
+ DeviceStateVersion(int64_t _vender, int64_t _product, int64_t _version) {
+
+ vender = _vender;
+ product = _product;
+ version = _version;
+ }
+
+
+ ~DeviceStateVersion() {
+ }
+
+
+ int64_t getVender() {
+ return vender;
+ }
+
+
+ int64_t getProduct() {
+ return product;
+ }
+
+
+ int64_t getVersion() {
+ return version;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEWIFIFIRMWARE_H__
+#define _DEVICESTATEWIFIFIRMWARE_H__
+#include <iostream>
+
+class DeviceStateWifiFirmware {
+ // time of build in nanosecond accuracy
+ // after some tests
+ private:
+ int64_t build;
+ int64_t version; // firmware version
+
+ public:
+
+ DeviceStateWifiFirmware(int64_t _build, int64_t _version) {
+
+ build = _build;
+ version = _version;
+ }
+
+
+ ~DeviceStateWifiFirmware() {
+ }
+
+
+ int64_t getBuild() {
+ return build;
+ }
+
+
+ int64_t getVersion() {
+ return version;
+ }
+};
+#endif
--- /dev/null
+#ifndef _DEVICESTATEWIFIINFO_H__
+#define _DEVICESTATEWIFIINFO_H__
+#include <iostream>
+
+class DeviceStateWifiInfo {
+ private:
+ int64_t signal;
+ int64_t tx;
+ int64_t rx;
+
+ public:
+
+ DeviceStateWifiInfo(int64_t _signal, int64_t _tx, int64_t _rx) {
+
+ signal = _signal;
+ tx = _tx;
+ rx = _rx;
+ }
+
+
+ ~DeviceStateWifiInfo() {
+ }
+
+
+ int64_t getSignal() {
+ return signal;
+ }
+
+
+ int64_t getTx() {
+ return tx;
+ }
+
+
+ int64_t getRx() {
+ return rx;
+ }
+};
+#endif
--- /dev/null
+#ifndef _IOTADDRESS_HPP__
+#define _IOTADDRESS_HPP__
+#include <iostream>
+
+#include "application.h"
+
+using namespace std;
+
+
+// IoTAddress class for iotruntime
+// Implemented based on IoTAddress.java that is used to wrap address
+//
+// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+// @version 1.0
+// @since 2017-01-09
+
+class IoTAddress
+{
+ public:
+
+ // Constructor
+ IoTAddress(IPAddress _sAddress) {
+
+ inetAddress = _sAddress;
+ }
+
+
+ // Constructor
+ IoTAddress() {
+ }
+
+
+ ~IoTAddress() {
+ }
+
+
+ IPAddress getAddress() {
+
+ return inetAddress;
+ }
+
+ // IoTAddress class properties
+ protected:
+ IPAddress inetAddress;
+};
+#endif
--- /dev/null
+#ifndef _IOTDEVICEADDRESS_H__
+#define _IOTDEVICEADDRESS_H__
+#include <iostream>
+
+#include "IoTAddress.h"
+
+using namespace std;
+
+// IoTDeviceAddress class for iotruntime
+// Implemented based on IoTDeviceAddress.java that is used to wrap device address
+//
+// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+// @version 1.0
+// @since 2017-01-09
+
+
+class IoTDeviceAddress final : public IoTAddress
+{
+
+ public:
+
+ // Constructor
+ IoTDeviceAddress(IPAddress _sAddress, int _iSrcPort, int _iDstPort, bool _isSrcPortWildCard, bool _isDstPortWildCard) : IoTAddress(_sAddress) {
+
+ iSrcPort = _iSrcPort;
+ iDstPort = _iDstPort;
+ isSrcPortWildCard = _isSrcPortWildCard;
+ isDstPortWildCard = _isDstPortWildCard;
+ }
+
+
+ // Constructor
+ IoTDeviceAddress() {
+ }
+
+
+ ~IoTDeviceAddress() {
+ }
+
+
+ // Getter methods
+ int getSourcePortNumber() {
+
+ return iSrcPort;
+ }
+
+
+ int getDestinationPortNumber() {
+
+ return iDstPort;
+ }
+
+
+ bool getIsSrcPortWildcard() {
+
+ return isSrcPortWildCard;
+ }
+
+
+ bool getIsDstPortWildcard() {
+
+ return isDstPortWildCard;
+ }
+
+
+ // Setter methods
+ void setSrcPort(int port) {
+
+ if (isDstPortWildCard) {
+ iDstPort = port;
+ }
+ }
+
+
+ void setDstPort(int port) {
+
+ if (isSrcPortWildCard) {
+ iSrcPort = port;
+ }
+ }
+
+
+ // IoTDeviceAddress class properties
+ private:
+ int iSrcPort;
+ int iDstPort;
+
+ bool isSrcPortWildCard;
+ bool isDstPortWildCard;
+};
+#endif
--- /dev/null
+#ifndef _IOTSET_H__
+#define _IOTSET_H__
+#include <iostream>
+#include <string>
+#include <unordered_set>
+
+using namespace std;
+
+/** This is the IoTSet implementation for C++
+ *
+ * @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+ * @version 1.0
+ * @since 2016-09-06
+ */
+template <class T>
+class IoTSet final {
+ private:
+ const unordered_set<T>* set;
+ public:
+ IoTSet();
+ IoTSet(const unordered_set<T>* s);
+ ~IoTSet();
+ public:
+ typename unordered_set<T>::const_iterator find(const T& k); // Find the object
+ bool empty(); // Test is empty?
+ typename unordered_set<T>::const_iterator begin(); // Iterator
+ typename unordered_set<T>::const_iterator end(); // Iterator
+ int size(); // Set size
+ unordered_set<T>* values(); // Return set contents
+};
+
+
+/**
+ * Default constructor
+ */
+template <class T>
+IoTSet<T>::IoTSet() {
+
+}
+
+
+/**
+ * Useful constructor
+ */
+template <class T>
+IoTSet<T>::IoTSet(const unordered_set<T>* s) {
+
+ set = s;
+}
+
+
+/**
+ * Default destructor
+ */
+template <class T>
+IoTSet<T>::~IoTSet() {
+
+}
+
+
+/**
+ * Find the object k in the set
+ */
+template <class T>
+typename unordered_set<T>::const_iterator IoTSet<T>::find(const T& k) {
+
+ return (new unordered_set<T>(*set))->find(k);
+}
+
+
+/**
+ * Return the "begin" iterator
+ */
+template <class T>
+typename unordered_set<T>::const_iterator IoTSet<T>::begin() {
+
+ return (new unordered_set<T>(*set))->begin();
+}
+
+
+/**
+ * Return the "end" iterator
+ */
+template <class T>
+typename unordered_set<T>::const_iterator IoTSet<T>::end() {
+
+ return (new unordered_set<T>(*set))->end();
+}
+
+
+/**
+ * Return the size of the set
+ */
+template <class T>
+int IoTSet<T>::size() {
+
+ return set->size();
+}
+
+
+/**
+ * Return a new copy of the set
+ */
+template <class T>
+unordered_set<T>* IoTSet<T>::values() {
+
+ return new unordered_set<T>(*set);
+}
+#endif
+
--- /dev/null
+#ifndef _IOTUDP_H__
+#define _IOTUDP_H__
+#include <iostream>
+
+#include "IoTDeviceAddress.h"
+
+using namespace std;
+
+// IoTUDP class for iotruntime
+// Implemented based on IoTUDP.java that is used to wrap communication socket for UDP
+//
+// @author Rahmadi Trimananda <rahmadi.trimananda @ uci.edu>
+// @version 1.0
+// @since 2017-01-09
+
+class IoTUDP final
+{
+ // IoTUDP class properties
+ private:
+ //UDPSocket *socket;
+ UDP socket;
+ IPAddress strHostAddress;
+ int iSrcPort;
+ int iDstPort;
+ bool didClose;
+ int timeOut;
+
+ public:
+
+ // Constructor
+ IoTUDP(IoTDeviceAddress* iotDevAdd) {
+
+ strHostAddress = iotDevAdd->getAddress();
+ iSrcPort = iotDevAdd->getSourcePortNumber();
+ iDstPort = iotDevAdd->getDestinationPortNumber();
+ timeOut = 0;
+
+ socket.begin(iSrcPort);
+ didClose = false;
+ }
+
+
+ ~IoTUDP() {
+ }
+
+
+ IPAddress getHostAddress() {
+ return strHostAddress;
+ }
+
+
+ int getSourcePort() {
+ return iSrcPort;
+ }
+
+
+ int getDestinationPort() {
+ return iDstPort;
+ }
+
+
+ void setTimeOut(int interval) {
+
+ timeOut = interval;
+ }
+
+
+ // Send data packet
+ void sendData(const char* buffer, int bufferLen) {
+
+ unsigned short destinationPort = (unsigned short) iDstPort;
+ IPAddress ipFromBytes(strHostAddress);
+ socket.sendPacket(buffer, bufferLen, strHostAddress, destinationPort);
+ }
+
+
+ // Receive data packet
+ int receiveData(char* buffer, int iMaxDataLength) {
+
+ return socket.receivePacket(buffer, iMaxDataLength);
+ }
+};
+#endif
--- /dev/null
+#ifndef _LIFXHEADER_H__
+#define _LIFXHEADER_H__
+#include <iostream>
+
+class LifxHeader {
+
+ private:
+ // Frame variables
+ int size;
+ int origin;
+ bool tagged;
+ bool addressable;
+ int protocol;
+ int64_t source;
+
+ // Frame address variables
+ char macAddress[8];
+ bool ack_required;
+ bool res_required;
+ int sequence;
+
+ // Protocol header
+ int type;
+
+ public:
+
+ LifxHeader() {
+ origin = 0;
+ addressable = true;
+ protocol =1024;
+ }
+
+
+ ~LifxHeader() {
+ }
+
+
+ void setSize(int _size) {
+ if (_size < 0) {
+ cerr << "Header: size cannot be less than 0" << endl;
+ exit(1);
+ } else if (_size > 65535) {
+ cerr << "Header: size too large" << endl;
+ exit(1);
+ }
+ size = _size;
+ }
+
+
+ void setOrigin(int _origin) {
+ if (_origin < 0) {
+ cerr << "Header: origin cannot be less than 0" << endl;
+ exit(1);
+ } else if (_origin > 3) {
+ cerr << "Header: origin too large" << endl;
+ exit(1);
+ }
+ origin = _origin;
+ }
+
+
+ void setTagged(bool _tagged) {
+ tagged = _tagged;
+ }
+
+
+ void setAddressable(bool _addressable) {
+ addressable = _addressable;
+ }
+
+
+ void setProtocol(int _protocol) {
+ if (_protocol < 0) {
+ cerr << "Header: protocol cannot be less than 0" << endl;
+ exit(1);
+ } else if (_protocol > 4095) {
+ cerr << "Header: protocol too large" << endl;
+ exit(1);
+ }
+ protocol = _protocol;
+ }
+
+
+ void setSource(int64_t _source) {
+ if (_source < 0) {
+ cerr << "Header: source cannot be less than 0" << endl;
+ exit(1);
+ } else if (_source > 4294967295) {
+ cerr << "Header: source too large" << endl;
+ exit(1);
+ }
+ source = _source;
+ }
+
+
+ void setSequence(int _sequence) {
+ if (_sequence < 0) {
+ cerr << "Header: sequence cannot be less than 0" << endl;
+ exit(1);
+ } else if (_sequence > 255) {
+ cerr << "Header: sequence too large" << endl;
+ exit(1);
+ }
+ sequence = _sequence;
+ }
+
+
+ void setType(int _type) {
+ if (_type < 0) {
+ cerr << "Header: type cannot be less than 0" << endl;
+ exit(1);
+ } else if (_type > 65535) {
+ cerr << "Header: type too large" << endl;
+ exit(1);
+ }
+ type = _type;
+ }
+
+
+ void setAck_required(bool _ack_required) {
+ ack_required = _ack_required;
+ }
+
+
+ void setRes_required(bool _res_required) {
+ res_required = _res_required;
+ }
+
+
+ void setMacAddress(char _macAddress[8]) {
+ strcpy(macAddress, _macAddress);
+ }
+
+
+ int getSize() {
+ return size;
+ }
+
+
+ int getOrigin() {
+ return origin;
+ }
+
+
+ bool getTagged() {
+ return tagged;
+ }
+
+
+ bool getAddressable() {
+ return addressable;
+ }
+
+
+ int getProtocol() {
+ return protocol;
+ }
+
+
+ int64_t getSource() {
+ return source;
+ }
+
+
+ int64_t getSequence() {
+ return sequence;
+ }
+
+
+ int getType() {
+ return type;
+ }
+
+
+ char* getHeaderBytes(char headerBytes[36]) {
+
+ //char headerBytes[36];
+ headerBytes[0] = (char)(size & 0xFF);
+ headerBytes[1] = (char)((size >> 8) & 0xFF);
+
+
+ headerBytes[2] = (char)(protocol & 0xFF);
+ headerBytes[3] = (char)((protocol >> 8) & 0x0F);
+
+ headerBytes[3] |= (char)((origin & 0x03) << 6);
+
+ if (tagged) {
+ headerBytes[3] |= (1 << 5);
+ }
+
+ if (addressable) {
+ headerBytes[3] |= (1 << 4);
+ }
+
+ headerBytes[4] = (char)((source >> 0) & 0xFF);
+ headerBytes[5] = (char)((source >> 8) & 0xFF);
+ headerBytes[6] = (char)((source >> 16) & 0xFF);
+ headerBytes[7] = (char)((source >> 24) & 0xFF);
+
+ // fix in a bit
+ headerBytes[8] = macAddress[0];
+ headerBytes[9] = macAddress[1];
+ headerBytes[10] = macAddress[2];
+ headerBytes[11] = macAddress[3];
+ headerBytes[12] = macAddress[4];
+ headerBytes[13] = macAddress[5];
+ headerBytes[14] = macAddress[6];
+ headerBytes[15] = macAddress[7];
+
+ // Reserved and set to 0
+ headerBytes[16] = 0;
+ headerBytes[17] = 0;
+ headerBytes[18] = 0;
+ headerBytes[19] = 0;
+ headerBytes[20] = 0;
+ headerBytes[21] = 0;
+
+ if (ack_required) {
+ headerBytes[22] = (1 << 1);
+ }
+
+ if (res_required) {
+ headerBytes[22] |= (1);
+ }
+
+ headerBytes[23] = (char)(sequence & 0xFF);
+
+ // Reserved and set to 0
+ headerBytes[24] = 0;
+ headerBytes[25] = 0;
+ headerBytes[26] = 0;
+ headerBytes[27] = 0;
+ headerBytes[28] = 0;
+ headerBytes[29] = 0;
+ headerBytes[30] = 0;
+ headerBytes[31] = 0;
+
+ headerBytes[32] = (char)((type >> 0) & 0xFF);
+ headerBytes[33] = (char)((type >> 8) & 0xFF);
+
+ // Reserved and set to 0
+ headerBytes[34] = 0;
+ headerBytes[35] = 0;
+
+ return headerBytes;
+ }
+
+
+ void setFromBytes(char dataBytes[36]) {
+
+ size = dataBytes[0] & 0xFF;
+ size |= ((dataBytes[1] & 0xFF) << 8);
+ size &= 0xFFFF;
+
+ origin = (dataBytes[3] >> 6) & 0x03;
+ tagged = ((dataBytes[3] >> 5) & 0x01) == 1;
+ addressable = ((dataBytes[3] >> 4) & 0x01) == 1;
+
+
+ protocol = (dataBytes[3] & 0x0F) << 8;
+ protocol |= dataBytes[2];
+ protocol &= 0x0FFF;
+
+ source = (dataBytes[7] & 0xFFl) << 24;
+ source |= ((dataBytes[6] & 0xFFl) << 16);
+ source |= ((dataBytes[5] & 0xFFl) << 8);
+ source |= ((dataBytes[4] & 0xFFl));
+
+ macAddress[0] = dataBytes[8];
+ macAddress[1] = dataBytes[9];
+ macAddress[2] = dataBytes[10];
+ macAddress[3] = dataBytes[11];
+ macAddress[4] = dataBytes[12];
+ macAddress[5] = dataBytes[13];
+ macAddress[6] = dataBytes[14];
+ macAddress[7] = dataBytes[15];
+
+ ack_required = (dataBytes[22] & 0x02) == 0x02;
+ res_required = (dataBytes[22] & 0x01) == 0x01;
+
+ sequence = (dataBytes[23] & 0xFF);
+
+ type = ((dataBytes[33] & 0xFF) << 8);
+ type |= (dataBytes[32] & 0xFF);
+ }
+};
+#endif
--- /dev/null
+#include <iostream>
+#include <string>
+#include <thread>
+
+#include <pthread.h>
+
+#include "LifxLightBulb.h"
+#include "IoTSet.h"
+#include "IoTDeviceAddress.h"
+#include "application.h"
+
+using namespace std;
+
+
+// Default constructor
+LifxLightBulb::LifxLightBulb() {
+
+}
+
+
+// Constructor
+LifxLightBulb::LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort) {
+
+ memcpy(bulbMacAddress, macAddress, 8);
+
+ // Initialize device address
+ // Port 56700 is the default port for Lifx
+ IoTDeviceAddress* devAddress = new IoTDeviceAddress(ipAddress, srcPort, 56700, false, false);
+ unordered_set<void*>* myset1 = new unordered_set<void*>();
+ myset1->insert(devAddress);
+ IoTSet<void*>* setDevAddress = new IoTSet<void*>(myset1);
+ lb_addresses = setDevAddress;
+}
+
+
+LifxLightBulb::~LifxLightBulb() {
+
+ // Clean up
+ if (communicationSocket != NULL) {
+
+ delete communicationSocket;
+ communicationSocket = NULL;
+ }
+ for(void* dev : *lb_addresses) {
+ IoTDeviceAddress* dv = (IoTDeviceAddress*) dev;
+ delete dv;
+ dv = NULL;
+ }
+ if (lb_addresses != NULL) {
+
+ delete lb_addresses;
+ lb_addresses = NULL;
+ }
+}
+
+
+// PUBLIC METHODS
+// Initialize the lightbulb
+void LifxLightBulb::init() {
+
+ if (didAlreadyInit)
+ return;
+ // Set to true if not yet
+ didAlreadyInit = true;
+
+ unordered_set<void*>::const_iterator itr = lb_addresses->begin();
+ IoTDeviceAddress* deviceAddress = (IoTDeviceAddress*) *itr;
+
+ // Create IoTUDP socket
+ communicationSocket = new IoTUDP(deviceAddress);
+
+ //cout << "Host address: " << communicationSocket->getHostAddress() << endl;
+ //cout << "Source port: " << communicationSocket->getSourcePort() << endl;
+ //cout << "Destination port: " << communicationSocket->getDestinationPort() << endl << endl;
+
+ // Launch the worker function in a separate thread.
+ // NOTE: "this" pointer is passed into the detached thread because it does not belong
+ // to this object anymore so if it executes certain methods of "this" object, then it needs
+ // the correct references to stuff
+ thread th1 (&LifxLightBulb::workerFunction, this, this);
+ th1.detach();
+}
+
+
+void LifxLightBulb::turnOff() {
+
+ //lock_guard<mutex> guard(bulbStateMutex);
+ bulbStateMutex.lock();
+ bulbIsOn = false;
+ sendSetLightPowerPacket(0, 0);
+ stateDidChange = true;
+ bulbStateMutex.unlock();
+}
+
+
+void LifxLightBulb::turnOn() {
+
+ //lock_guard<mutex> guard(bulbStateMutex);
+ bulbStateMutex.lock();
+ bulbIsOn = true;
+ sendSetLightPowerPacket(65535, 0);
+ stateDidChange = true;
+ bulbStateMutex.unlock();
+}
+
+
+double LifxLightBulb::getHue() {
+ double tmp = 0;
+ settingBulbColorMutex.lock();
+ tmp = ((double)currentHue / 65535.0) * 360.0;
+ settingBulbColorMutex.unlock();
+
+ return tmp;
+}
+
+
+double LifxLightBulb::getSaturation() {
+ double tmp = 0;
+ settingBulbColorMutex.lock();
+ tmp = ((double)currentSaturation / 65535.0) * 360.0;
+ settingBulbColorMutex.unlock();
+
+ return tmp;
+}
+
+
+double LifxLightBulb::getBrightness() {
+ double tmp = 0;
+ settingBulbColorMutex.lock();
+ tmp = ((double)currentBrightness / 65535.0) * 360.0;
+ settingBulbColorMutex.unlock();
+
+ return tmp;
+}
+
+
+int LifxLightBulb::getTemperature() {
+
+ int tmp = 0;
+ settingBulbTemperatureMutex.lock();
+ tmp = currentTemperature;
+ settingBulbTemperatureMutex.unlock();
+
+ return tmp;
+}
+
+
+double LifxLightBulb::getHueRangeLowerBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)hueLowerBound / 65535.0) * 360.0;
+}
+
+
+double LifxLightBulb::getHueRangeUpperBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)hueUpperBound / 65535.0) * 360.0;
+}
+
+
+double LifxLightBulb::getSaturationRangeLowerBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)saturationLowerBound / 65535.0) * 100.0;
+}
+
+
+double LifxLightBulb::getSaturationRangeUpperBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)saturationUpperBound / 65535.0) * 100.0;
+}
+
+
+double LifxLightBulb::getBrightnessRangeLowerBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)brightnessLowerBound / 65535.0) * 100.0;
+}
+
+
+double LifxLightBulb::getBrightnessRangeUpperBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return ((double)brightnessUpperBound / 65535.0) * 100.0;
+}
+
+
+int LifxLightBulb::getTemperatureRangeLowerBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return temperatureLowerBound;
+}
+
+
+int LifxLightBulb::getTemperatureRangeUpperBound() {
+ if (!didGetBulbVersion) {
+ return -1;
+ }
+ return temperatureUpperBound;
+}
+
+
+void LifxLightBulb::setTemperature(int _temperature) {
+
+ settingBulbTemperatureMutex.lock();
+
+ BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, _temperature);
+ sendSetLightColorPacket(newColor, 250);
+
+ currentTemperature = _temperature;
+ stateDidChange = true;
+
+ settingBulbTemperatureMutex.unlock();
+}
+
+
+void LifxLightBulb::setColor(double _hue, double _saturation, double _brightness) {
+
+ settingBulbColorMutex.lock();
+
+ _hue /= 360.0;
+ _saturation /= 100.0;
+ _brightness /= 100.0;
+
+
+ int newHue = (int)(_hue * 65535.0);
+ int newSaturation = (int)(_saturation * 65535.0);
+ int newBrightness = (int)(_brightness * 65535.0);
+
+ BulbColor* newColor = new BulbColor(newHue, newSaturation, newBrightness, currentTemperature);
+ sendSetLightColorPacket(newColor, 250);
+
+ currentHue = newHue;
+ currentSaturation = newSaturation;
+ currentBrightness = newBrightness;
+ stateDidChange = true;
+
+ settingBulbColorMutex.unlock();
+}
+
+
+bool LifxLightBulb::getState() {
+
+ bool tmp = false;
+
+ bulbStateMutex.lock();
+ tmp = bulbIsOn;
+ bulbStateMutex.unlock();
+
+ return tmp;
+}
+
+
+// PRIVATE METHODS
+// Communication helpers
+void LifxLightBulb::receivedPacket(char* packetData) {
+
+ char headerBytes[36];
+ for (int i = 0; i < 36; i++) {
+ headerBytes[i] = packetData[i];
+ }
+
+ LifxHeader recHeader;
+ recHeader.setFromBytes(headerBytes);
+
+ // load the payload bytes (strip away the header)
+ char* payloadBytes = new char[recHeader.getSize()];
+ for (int i = 36; i < recHeader.getSize(); i++) {
+ payloadBytes[i - 36] = packetData[i];
+ }
+
+ int type = recHeader.getType();
+ //cout << "Received: " << type << endl;
+
+ DeviceStateService* dat = NULL;
+ switch (type) {
+
+ case 3:
+ dat = parseDeviceStateServiceMessage(payloadBytes);
+ //cout << "Service: " << dat->getService();
+ //cout << "Port : " << dat->getPort();
+ // Avoid memory leak - delete this object
+ delete dat;
+ break;
+
+ case 33:
+ handleStateVersionMessageReceived(payloadBytes);
+ break;
+
+ case 35:
+ parseDeviceStateInfoMessage(payloadBytes);
+ break;
+
+
+ case 107:
+ handleLightStateMessageReceived(payloadBytes);
+ break;
+
+ default:
+ break;
+ //cout << "unknown packet Type" << endl;
+ }
+ // Avoid memory leaks
+ delete payloadBytes;
+}
+
+
+void LifxLightBulb::sendPacket(char* packetData, int len) {
+ //cout << "sendPacket: About to send" << endl;
+ lock_guard<mutex> guard(socketMutex);
+ sendSocketFlag = true;
+ communicationSocket->sendData(packetData, len);
+ sendSocketFlag = false;
+}
+
+
+// Worker function which runs the while loop for receiving data from the bulb.
+// Is blocking.
+void LifxLightBulb::workerFunction(LifxLightBulb* llb) {
+
+ // Need timeout on receives since we are not sure if a packet will be available
+ // for processing so don't block waiting
+ llb->communicationSocket->setTimeOut(50000); // In milliseconds
+ llb->turnOff();
+
+ int64_t lastSentGetBulbVersionRequest = 0; // time last request sent
+ char dat[1024];
+
+ while (true) {
+ // Check if we got the bulb version yet
+ // could have requested it but message could have gotten lost (UDP)
+ if (!llb->didGetBulbVersion) {
+ int64_t currentTime = (int64_t) time(NULL);
+ if ((currentTime - lastSentGetBulbVersionRequest) > llb->GET_BULB_VERSION_RESEND_WAIT_SECONDS) {
+ // Get the bulb version so we know what type of bulb this is.
+ //cout << "Sending version packet! " << endl;
+ llb->sendGetVersionPacket();
+ lastSentGetBulbVersionRequest = currentTime;
+ }
+ }
+
+ // Communication resource is busy so try again later
+ if (llb->sendSocketFlag) {
+ continue;
+ }
+
+ llb->socketMutex.lock();
+ int ret = llb->communicationSocket->receiveData(dat, 1024);
+ // Never forget to release!
+ llb->socketMutex.unlock();
+
+ // A packed arrived
+ if (ret != -1) {
+ llb->receivedPacket(dat);
+ }
+
+ // If a state change occurred then request the bulb state to ensure that the
+ // bulb did indeed change its state to the correct state
+ if (llb->stateDidChange) {
+ llb->sendGetLightStatePacket();
+ }
+
+ // Wait a bit as to not tie up system resources
+ //this_thread::sleep_for (chrono::milliseconds(100));
+ delay(100);
+ //cout << endl << "Sleep and wake up!" << endl;
+ }
+}
+
+
+// Sending
+// Device Messages
+void LifxLightBulb::sendGetServicePacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(true);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(0); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(2);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetHostInfoPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(12);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetHostFirmwarePacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(14);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetWifiInfoPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(16);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetWifiFirmwarePacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(18);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetPowerPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(20);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendSetPowerPacket(int level) {
+ // Currently only 0 and 65535 are supported
+ // This is a fix for now
+ if ((level != 65535) && (level != 0)) {
+ cerr << "Invalid parameter values" << endl;
+ exit(1);
+ }
+
+ if ((level > 65535) || (level < 0)) {
+ cerr << "Invalid parameter values" << endl;
+ exit(1);
+ }
+
+ char packetBytes[38];
+
+ LifxHeader header;
+ header.setSize(38);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(21);
+ char headerBytes[36];
+ header.getHeaderBytes(headerBytes);
+
+ for (int i = 0; i < 36; i++) {
+ packetBytes[i] = headerBytes[i];
+ }
+
+ packetBytes[36] = (char)(level & 0xFF);
+ packetBytes[37] = (char)((level >> 8) & 0xFF);
+
+ sendPacket(packetBytes, 38);
+}
+
+
+void LifxLightBulb::sendGetLabelPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(23);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendSetLabelPacket(string label) {
+ // Currently only 0 and 65535 are supported
+ // This is a fix for now
+ if (label.length() != 32) {
+ cerr << "Invalid parameter values, label must be 32 bytes long" << endl;
+ exit(1);
+ }
+
+ char packetBytes[68];
+
+ LifxHeader header;
+ header.setSize(68);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(24);
+ char headerBytes[36];
+ header.getHeaderBytes(headerBytes);
+
+ for (int i = 0; i < 36; i++) {
+ packetBytes[i] = headerBytes[i];
+ }
+
+ for (int i = 0; i < 32; i++) {
+ packetBytes[i + 36] = label.c_str()[i];
+ }
+
+ sendPacket(packetBytes, 68);
+}
+
+
+void LifxLightBulb::sendGetVersionPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(32);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetInfoPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(34);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetLocationPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(34);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendGetGroupPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(51);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+// Sending
+// Light Messages
+void LifxLightBulb::sendGetLightStatePacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(101);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendSetLightColorPacket(BulbColor* bulbColor, long duration) {
+
+ if ((duration > 4294967295l) || (duration < 0)) {
+ cerr << "Invalid parameter value, duration out of range (0 - 4294967295)" << endl;
+ exit(1);
+ }
+
+ char packetBytes[49];
+
+ LifxHeader header;
+ header.setSize(49);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(102);
+ char headerBytes[36];
+ header.getHeaderBytes(headerBytes);
+
+ for (int i = 0; i < 36; i++) {
+ packetBytes[i] = headerBytes[i];
+ }
+
+ // 1 reserved packet
+ packetBytes[37] = (char)(bulbColor->getHue() & 0xFF);
+ packetBytes[38] = (char)((bulbColor->getHue() >> 8) & 0xFF);
+
+ packetBytes[39] = (char)(bulbColor->getSaturation() & 0xFF);
+ packetBytes[40] = (char)((bulbColor->getSaturation() >> 8) & 0xFF);
+
+ packetBytes[41] = (char)(bulbColor->getBrightness() & 0xFF);
+ packetBytes[42] = (char)((bulbColor->getBrightness() >> 8) & 0xFF);
+
+ packetBytes[43] = (char)(bulbColor->getKelvin() & 0xFF);
+ packetBytes[44] = (char)((bulbColor->getKelvin() >> 8) & 0xFF);
+
+ packetBytes[45] = (char)((duration >> 0) & 0xFF);
+ packetBytes[46] = (char)((duration >> 8) & 0xFF);
+ packetBytes[47] = (char)((duration >> 16) & 0xFF);
+ packetBytes[48] = (char)((duration >> 24) & 0xFF);
+
+ sendPacket(packetBytes, 49);
+ // Avoid memory leak - delete object
+ delete bulbColor;
+}
+
+
+void LifxLightBulb::sendGetLightPowerPacket() {
+ LifxHeader header;
+ header.setSize(36);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(116);
+
+ char dataBytes[36];
+ header.getHeaderBytes(dataBytes);
+
+ sendPacket(dataBytes, 36);
+}
+
+
+void LifxLightBulb::sendSetLightPowerPacket(int level, long duration) {
+
+ if ((level > 65535) || (duration > 4294967295l)
+ || (level < 0) || (duration < 0)) {
+ cerr << "Invalid parameter values" << endl;
+ exit(1);
+ }
+ char packetBytes[42];
+
+ LifxHeader header;
+ header.setSize(42);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(117);
+ char headerBytes[36];
+ header.getHeaderBytes(headerBytes);
+
+ for (int i = 0; i < 36; i++) {
+ packetBytes[i] = headerBytes[i];
+ }
+
+ packetBytes[36] = (char)(level & 0xFF);
+ packetBytes[37] = (char)((level >> 8) & 0xFF);
+
+ packetBytes[38] = (char)((duration >> 0) & 0xFF);
+ packetBytes[39] = (char)((duration >> 8) & 0xFF);
+ packetBytes[40] = (char)((duration >> 16) & 0xFF);
+ packetBytes[41] = (char)((duration >> 24) & 0xFF);
+
+ sendPacket(packetBytes, 42);
+}
+
+
+void LifxLightBulb::sendEchoRequestPacket(char data[64]) {
+
+ char packetBytes[100];
+
+ LifxHeader header;
+ header.setSize(100);
+ header.setTagged(false);
+ header.setMacAddress(bulbMacAddress);
+ header.setSource(10); // randomly picked
+ header.setAck_required(false);
+ header.setRes_required(false);
+ header.setSequence(0);
+ header.setType(58);
+ char headerBytes[36];
+ header.getHeaderBytes(headerBytes);
+
+ for (int i = 0; i < 36; i++) {
+ packetBytes[i] = headerBytes[i];
+ }
+
+ for (int i = 0; i < 64; i++) {
+ packetBytes[i + 36] = data[i];
+ }
+
+ sendPacket(packetBytes, 100);
+}
+
+
+// Receiving
+// Device Messages
+DeviceStateService* LifxLightBulb::parseDeviceStateServiceMessage(char* payloadData) {
+ int service = payloadData[0];
+ int64_t port = ((payloadData[3] & 0xFF) << 24);
+ port |= ((payloadData[2] & 0xFF) << 16);
+ port |= ((payloadData[1] & 0xFF) << 8);
+ port |= (payloadData[0] & 0xFF);
+
+ return new DeviceStateService(service, port);
+}
+
+
+DeviceStateHostInfo* LifxLightBulb::parseDeviceStateHostInfoMessage(char* payloadData) {
+ long signal = ((payloadData[3] & 0xFF) << 24);
+ signal |= ((payloadData[2] & 0xFF) << 16);
+ signal |= ((payloadData[1] & 0xFF) << 8);
+ signal |= (payloadData[0] & 0xFF);
+
+ long tx = ((payloadData[7] & 0xFF) << 24);
+ tx |= ((payloadData[6] & 0xFF) << 16);
+ tx |= ((payloadData[5] & 0xFF) << 8);
+ tx |= (payloadData[4] & 0xFF);
+
+ long rx = ((payloadData[11] & 0xFF) << 24);
+ rx |= ((payloadData[10] & 0xFF) << 16);
+ rx |= ((payloadData[9] & 0xFF) << 8);
+ rx |= (payloadData[8] & 0xFF);
+
+ return new DeviceStateHostInfo(signal, tx, rx);
+}
+
+
+DeviceStateHostFirmware* LifxLightBulb::parseDeviceStateHostFirmwareMessage(char* payloadData) {
+ long build = 0;
+ for (int i = 0; i < 8; i++) {
+ build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
+ }
+
+ // 8 reserved bytes
+
+ int64_t version = ((payloadData[19] & 0xFF) << 24);
+ version |= ((payloadData[18] & 0xFF) << 16);
+ version |= ((payloadData[17] & 0xFF) << 8);
+ version |= (payloadData[16] & 0xFF);
+
+ return new DeviceStateHostFirmware(build, version);
+}
+
+
+DeviceStateWifiInfo* LifxLightBulb::parseDeviceStateWifiInfoMessage(char* payloadData) {
+ int64_t signal = ((payloadData[3] & 0xFF) << 24);
+ signal |= ((payloadData[2] & 0xFF) << 16);
+ signal |= ((payloadData[1] & 0xFF) << 8);
+ signal |= (payloadData[0] & 0xFF);
+
+ int64_t tx = ((payloadData[7] & 0xFF) << 24);
+ tx |= ((payloadData[6] & 0xFF) << 16);
+ tx |= ((payloadData[5] & 0xFF) << 8);
+ tx |= (payloadData[4] & 0xFF);
+
+ int64_t rx = ((payloadData[11] & 0xFF) << 24);
+ rx |= ((payloadData[10] & 0xFF) << 16);
+ rx |= ((payloadData[9] & 0xFF) << 8);
+ rx |= (payloadData[8] & 0xFF);
+
+ return new DeviceStateWifiInfo(signal, tx, rx);
+}
+
+
+DeviceStateWifiFirmware* LifxLightBulb::parseDeviceStateWifiFirmwareMessage(char* payloadData) {
+ long build = 0;
+ for (int i = 0; i < 8; i++) {
+ build += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
+ }
+
+ // 8 reserved bytes
+
+ int64_t version = ((payloadData[19] & 0xFF) << 24);
+ version |= ((payloadData[18] & 0xFF) << 16);
+ version |= ((payloadData[17] & 0xFF) << 8);
+ version |= (payloadData[16] & 0xFF);
+
+ return new DeviceStateWifiFirmware(build, version);
+}
+
+
+int LifxLightBulb::parseStatePowerMessage(char* payloadData) {
+ int level = ((payloadData[1] & 0xFF) << 8);
+ level |= (payloadData[0] & 0xFF);
+ return level;
+}
+
+
+DeviceStateVersion* LifxLightBulb::parseDeviceStateVersionMessage(char* payloadData) {
+ int64_t vender = ((payloadData[3] & 0xFF) << 24);
+ vender |= ((payloadData[2] & 0xFF) << 16);
+ vender |= ((payloadData[1] & 0xFF) << 8);
+ vender |= (payloadData[0] & 0xFF);
+
+ int64_t product = ((payloadData[7] & 0xFF) << 24);
+ product |= ((payloadData[6] & 0xFF) << 16);
+ product |= ((payloadData[5] & 0xFF) << 8);
+ product |= (payloadData[4] & 0xFF);
+
+ int64_t version = ((payloadData[11] & 0xFF) << 24);
+ version |= ((payloadData[10] & 0xFF) << 16);
+ version |= ((payloadData[9] & 0xFF) << 8);
+ version |= (payloadData[8] & 0xFF);
+
+ return new DeviceStateVersion(vender, product, version);
+}
+
+
+DeviceStateInfo* LifxLightBulb::parseDeviceStateInfoMessage(char* payloadData) {
+ int64_t time = 0;
+ int64_t upTime = 0;
+ int64_t downTime = 0;
+ for (int i = 0; i < 8; i++) {
+ time += ((int64_t) payloadData[i] & 0xffL) << (8 * i);
+ upTime += ((int64_t) payloadData[i + 8] & 0xffL) << (8 * i);
+ downTime += ((int64_t) payloadData[i + 16] & 0xffL) << (8 * i);
+ }
+
+ return new DeviceStateInfo(time, upTime, downTime);
+}
+
+
+DeviceStateLocation* LifxLightBulb::parseDeviceStateLocationMessage(char* payloadData) {
+ char location[16];
+ for (int i = 0; i < 16; i++) {
+ location[i] = payloadData[i];
+ }
+
+ char labelBytes[32];
+ for (int i = 0; i < 32; i++) {
+ labelBytes[i] = payloadData[i + 16];
+ }
+
+ int64_t updatedAt = 0;
+ for (int i = 0; i < 8; i++) {
+ updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
+ }
+
+ string str(labelBytes);
+ return new DeviceStateLocation(location, str, updatedAt);
+}
+
+
+DeviceStateGroup* LifxLightBulb::parseDeviceStateGroupMessage(char* payloadData) {
+ char group[16];
+ for (int i = 0; i < 16; i++) {
+ group[i] = payloadData[i];
+ }
+
+ char labelBytes[32];
+ for (int i = 0; i < 32; i++) {
+ labelBytes[i] = payloadData[i + 16];
+ }
+
+ int64_t updatedAt = 0;
+ for (int i = 0; i < 8; i++) {
+ updatedAt += ((int64_t) payloadData[48] & 0xffL) << (8 * i);
+ }
+
+ string str(labelBytes);
+ return new DeviceStateGroup(group, str, updatedAt);
+}
+
+
+// Receiving
+// Light Messages
+LightState* LifxLightBulb::parseLightStateMessage(char* payloadData) {
+
+ char colorData[8];
+ for (int i = 0; i < 8; i++) {
+ colorData[i] = payloadData[i];
+ }
+ //BulbColor color(colorData);
+ BulbColor* color = new BulbColor(colorData);
+
+ int power = ((payloadData[11] & 0xFF) << 8);
+ power |= (payloadData[10] & 0xFF);
+
+ string label(payloadData);
+
+ char labelArray[32];
+ for (int i = 0; i < 32; i++) {
+ labelArray[i] = payloadData[12 + i];
+ }
+
+ return new LightState(color, power, label);
+}
+
+
+int LifxLightBulb::parseLightStatePowerMessage(char* payloadData) {
+ int level = ((payloadData[1] & 0xFF) << 8);
+ level |= (payloadData[0] & 0xFF);
+ return level;
+}
+
+
+// Private Handlers
+void LifxLightBulb::handleStateVersionMessageReceived(char* payloadData) {
+
+ DeviceStateVersion* deviceState = parseDeviceStateVersionMessage(payloadData);
+ int productNumber = (int)deviceState->getProduct();
+
+ bool isColor = false;
+
+ if (productNumber == 1) {// Original 1000
+ isColor = true;
+ } else if (productNumber == 3) {//Color 650
+ isColor = true;
+ } else if (productNumber == 10) {// White 800 (Low Voltage)
+ isColor = false;
+ } else if (productNumber == 11) {// White 800 (High Voltage)
+ isColor = false;
+ } else if (productNumber == 18) {// White 900 BR30 (Low Voltage)
+ isColor = false;
+ } else if (productNumber == 20) {// Color 1000 BR30
+ isColor = true;
+ } else if (productNumber == 22) {// Color 1000
+ isColor = true;
+ }
+
+ if (isColor) {
+ hueLowerBound = 0;
+ hueUpperBound = 65535;
+ saturationLowerBound = 0;
+ saturationUpperBound = 65535;
+ brightnessLowerBound = 0;
+ brightnessUpperBound = 65535;
+ temperatureLowerBound = 2500;
+ temperatureUpperBound = 9000;
+ } else {
+ hueLowerBound = 0;
+ hueUpperBound = 0;
+ saturationLowerBound = 0;
+ saturationUpperBound = 0;
+ brightnessLowerBound = 0;
+ brightnessUpperBound = 65535;// still can dim bulb
+ temperatureLowerBound = 2500;
+ temperatureUpperBound = 9000;
+ }
+
+ //didGetBulbVersion.exchange(true);
+ didGetBulbVersion = true;
+ // Avoid memory leak - delete this object
+ delete deviceState;
+}
+
+
+void LifxLightBulb::handleLightStateMessageReceived(char* payloadData) {
+ LightState* lightState = parseLightStateMessage(payloadData);
+
+ BulbColor* color = lightState->getColor();
+ int power = lightState->getPower();
+
+ //cout << "color->getHue(): " << color->getHue() << " - currentHue: " << currentHue << endl;
+ //cout << "color->getSaturation(): " << color->getSaturation() << " - currentSaturation: " << currentSaturation << endl;
+ //cout << "color->getBrightness(): " << color->getBrightness() << " - currentBrightness: " << currentBrightness << endl;
+ //cout << "color->getKelvin(): " << color->getKelvin() << " - currentTemperature: " << currentTemperature << endl;
+
+ bool bulbWrongColor = false;
+ bulbWrongColor = bulbWrongColor || (color->getHue() != currentHue);
+ bulbWrongColor = bulbWrongColor || (color->getSaturation() != currentSaturation);
+ bulbWrongColor = bulbWrongColor || (color->getBrightness() != currentBrightness);
+ bulbWrongColor = bulbWrongColor || (color->getKelvin() != currentTemperature);
+
+
+ // gets set to true if any of the below if statements are taken
+ stateDidChange = false;
+
+ if (bulbWrongColor) {
+ BulbColor* newColor = new BulbColor(currentHue, currentSaturation, currentBrightness, currentTemperature);
+ sendSetLightColorPacket(newColor, 250);
+ //cout << "Failed Check 1" << endl;
+ }
+
+ bulbStateMutex.lock();
+ bool bulbIsOnTmp = bulbIsOn;
+ bulbStateMutex.unlock();
+
+ if ((!bulbIsOnTmp) && (power != 0)) {
+ turnOff();
+ //cout << "Failed Check 2: " << endl;
+
+ }
+
+ if (bulbIsOnTmp && (power < 65530)) {
+ turnOn();
+ //cout << "Failed Check 3: " << endl;
+
+ }
+ // Avoid memory leak - delete object
+ delete lightState;
+ delete color;
+}
+
--- /dev/null
+#ifndef _LIFXLIGHTBULB_H__
+#define _LIFXLIGHTBULB_H__
+#include <iostream>
+#include <fstream>
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include <chrono>
+
+#include <string.h>
+#include <time.h>
+
+#include "LightBulb.h"
+//#include "Socket.h"
+#include "IoTSet.h"
+#include "IoTUDP.h"
+#include "IoTDeviceAddress.h"
+
+// Helper classes for LifxLightBulb
+#include "LifxHeader.h"
+#include "BulbColor.h"
+#include "DeviceStateGroup.h"
+#include "DeviceStateHostFirmware.h"
+#include "DeviceStateHostInfo.h"
+#include "DeviceStateInfo.h"
+#include "DeviceStateLocation.h"
+#include "DeviceStateService.h"
+#include "DeviceStateVersion.h"
+#include "DeviceStateWifiFirmware.h"
+#include "DeviceStateWifiInfo.h"
+#include "LightState.h"
+
+
+using namespace std;
+
+// Driver LifxLightBulb
+// Implemented based on LightBulb virtual class (interface)
+
+class LifxLightBulb : public LightBulb
+{
+ private:
+ // Constants
+ const static int64_t GET_BULB_VERSION_RESEND_WAIT_SECONDS = 10;
+
+ // Variables
+ IoTUDP *communicationSocket;
+ char bulbMacAddress[8];
+ //TODO:
+ bool sendSocketFlag = false;
+
+ // Current Bulb Values
+ int currentHue = 0;
+ int currentSaturation = 0;
+ int currentBrightness = 65535;
+ int currentTemperature = 9000;
+ bool bulbIsOn = false;
+
+ bool didAlreadyInit = false;
+ bool didGetBulbVersion = false;
+
+ // Mutex locks
+ mutex socketMutex;
+ mutex settingBulbColorMutex;
+ mutex settingBulbTemperatureMutex;
+ mutex bulbStateMutex;
+
+ // color and temperature ranges for the bulbs
+ int hueLowerBound = 0;
+ int hueUpperBound = 0;
+ int saturationLowerBound = 0;
+ int saturationUpperBound = 0;
+ int brightnessLowerBound = 0;
+ int brightnessUpperBound = 0;
+ int temperatureLowerBound = 2500;
+ int temperatureUpperBound = 9000;
+
+ // Check if a state change was requested, used to poll the bulb for if the bulb did
+ // preform the requested state change
+ bool stateDidChange = false;
+
+ // Device address
+ IoTSet<void*>* lb_addresses; // IoTSet<IoTDeviceAddress*>* lb_addresses
+
+ // Logging
+ ofstream log;
+ public:
+
+ // Constructor
+ LifxLightBulb();
+ LifxLightBulb(IPAddress ipAddress, char* macAddress, int srcPort);
+ ~LifxLightBulb();
+ // Initialize the lightbulb
+ void init();
+ void turnOff();
+ void turnOn();
+ double getHue();
+ double getSaturation();
+ double getBrightness();
+ int getTemperature();
+ double getHueRangeLowerBound();
+ double getHueRangeUpperBound();
+ double getSaturationRangeLowerBound();
+ double getSaturationRangeUpperBound();
+ double getBrightnessRangeLowerBound();
+ double getBrightnessRangeUpperBound();
+ int getTemperatureRangeLowerBound();
+ int getTemperatureRangeUpperBound();
+ void setTemperature(int _temperature);
+ void setColor(double _hue, double _saturation, double _brightness);
+ bool getState();
+
+ private:
+ // Private functions
+ // Communication helpers
+ void receivedPacket(char* packetData);
+ void sendPacket(char* packetData, int len);
+ // Worker function which runs the while loop for receiving data from the bulb.
+ // Is blocking.
+ void workerFunction(LifxLightBulb* llb);
+ // Sending
+ // Device Messages
+ void sendGetServicePacket();
+ void sendGetHostInfoPacket();
+ void sendGetHostFirmwarePacket();
+ void sendGetWifiInfoPacket();
+ void sendGetWifiFirmwarePacket();
+ void sendGetPowerPacket();
+ void sendSetPowerPacket(int level);
+ void sendGetLabelPacket();
+ void sendSetLabelPacket(string label);
+ void sendGetVersionPacket();
+ void sendGetInfoPacket();
+ void sendGetLocationPacket();
+ void sendGetGroupPacket();
+ // Sending
+ // Light Messages
+ void sendGetLightStatePacket();
+ void sendSetLightColorPacket(BulbColor* bulbColor, long duration);
+ void sendGetLightPowerPacket();
+ void sendSetLightPowerPacket(int level, long duration);
+ void sendEchoRequestPacket(char data[64]);
+ // Receiving
+ // Device Messages
+ DeviceStateService* parseDeviceStateServiceMessage(char* payloadData);
+ DeviceStateHostInfo* parseDeviceStateHostInfoMessage(char* payloadData);
+ DeviceStateHostFirmware* parseDeviceStateHostFirmwareMessage(char* payloadData);
+ DeviceStateWifiInfo* parseDeviceStateWifiInfoMessage(char* payloadData);
+ DeviceStateWifiFirmware* parseDeviceStateWifiFirmwareMessage(char* payloadData);
+ int parseStatePowerMessage(char* payloadData);
+ DeviceStateVersion* parseDeviceStateVersionMessage(char* payloadData);
+ DeviceStateInfo* parseDeviceStateInfoMessage(char* payloadData);
+ DeviceStateLocation* parseDeviceStateLocationMessage(char* payloadData);
+ DeviceStateGroup* parseDeviceStateGroupMessage(char* payloadData);
+ // Receiving
+ // Light Messages
+ LightState* parseLightStateMessage(char* payloadData);
+ int parseLightStatePowerMessage(char* payloadData);
+ // Private Handlers
+ void handleStateVersionMessageReceived(char* payloadData);
+ void handleLightStateMessageReceived(char* payloadData);
+};
+
+#endif
--- /dev/null
+#ifndef _LIGHTBULB_H__
+#define _LIGHTBULB_H__
+#include <iostream>
+
+using namespace std;
+
+class LightBulb
+{
+ public:
+ virtual void init() = 0;
+ virtual void turnOff() = 0;
+ virtual void turnOn() = 0;
+ virtual bool getState() = 0;
+ virtual void setColor(double _hue, double _saturation, double _brightness) = 0;
+ virtual void setTemperature(int _temperature) = 0;
+ virtual double getBrightness() = 0;
+ virtual double getHue() = 0;
+ virtual double getSaturation() = 0;
+ virtual int getTemperature() = 0;
+ virtual double getBrightnessRangeLowerBound() = 0;
+ virtual double getBrightnessRangeUpperBound() = 0;
+ virtual double getHueRangeLowerBound() = 0;
+ virtual double getHueRangeUpperBound() = 0;
+ virtual double getSaturationRangeLowerBound() = 0;
+ virtual double getSaturationRangeUpperBound() = 0;
+ virtual int getTemperatureRangeLowerBound() = 0;
+ virtual int getTemperatureRangeUpperBound() = 0;
+};
+#endif
--- /dev/null
+#ifndef _LIGHTSTATE_H__
+#define _LIGHTSTATE_H__
+#include <iostream>
+
+#include "BulbColor.h"
+
+class LightState {
+ private:
+ BulbColor* color;
+ int power;
+ string label;
+
+ public:
+
+ LightState(BulbColor* _color, int _power, string _label) {
+
+ color = _color;
+ power = _power;
+ label = _label;
+ }
+
+
+ ~LightState() {
+ }
+
+
+ BulbColor* getColor() {
+ return color;
+ }
+
+
+ int getPower() {
+ return power;
+ }
+
+
+ string getLabel() {
+ return label;
+ }
+};
+#endif
--- /dev/null
+// ------------------------------------------------
+// Controlling LifxLightBulb through Particle Cloud
+// @author Rahmadi Trimananda - UC Irvine
+// ------------------------------------------------
+
+#include "LifxLightBulb.h"
+
+LifxLightBulb *llb1;
+LifxLightBulb *llb2;
+
+int led1 = D7;
+
+void setup()
+{
+ // Bulb 1
+ char macAddress1[8];
+ macAddress1[0] = 0xD0;
+ macAddress1[1] = 0x73;
+ macAddress1[2] = 0xD5;
+ macAddress1[3] = 0x12;
+ macAddress1[4] = 0x8E;
+ macAddress1[5] = 0x30;
+ macAddress1[6] = 0x00;
+ macAddress1[7] = 0x00;
+ IPAddress devIPAddress1(192, 168, 1, 126);
+
+ llb1 = new LifxLightBulb(devIPAddress1, macAddress1, 12345);
+ llb1->init();
+
+ // Bulb 2
+ char macAddress2[8];
+ macAddress2[0] = 0xD0;
+ macAddress2[1] = 0x73;
+ macAddress2[2] = 0xD5;
+ macAddress2[3] = 0x02;
+ macAddress2[4] = 0x41;
+ macAddress2[5] = 0xDA;
+ macAddress2[6] = 0x00;
+ macAddress2[7] = 0x00;
+ IPAddress devIPAddress2(192, 168, 1, 232);
+
+ llb2 = new LifxLightBulb(devIPAddress2, macAddress2, 12346);
+ llb2->init();
+
+ pinMode(led1, OUTPUT);
+ Particle.function("lifx1",lifx1Toggle);
+ Particle.function("lifx2",lifx2Toggle);
+}
+
+
+void loop() {
+ // Nothing to do here
+}
+
+
+// Toggling Lifx light bulb 1
+int lifx1Toggle(String command) {
+
+ if (command=="on") {
+ llb1->turnOn();
+ return 1;
+ }
+ else if (command=="off") {
+ llb1->turnOff();
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+// Toggling Lifx light bulb 2
+int lifx2Toggle(String command) {
+
+ if (command=="on") {
+ llb2->turnOn();
+ return 1;
+ }
+ else if (command=="off") {
+ llb2->turnOff();
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
--- /dev/null
+include common.mk
+
+all: compile
+
+# To run Particle, we need to install Particle CLI
+# Please see:
+# https://docs.particle.io/guide/getting-started/connect/photon/#install-the-particle-cli
+monitor:
+ sudo chmod 666 /dev/ttyACM0
+ particle serial monitor
+
+compile-c:
+ #g++ -c LifxLightBulb.cpp -o ./LifxLightBulb.o -Wall -O3 -g -I. -Wno-unused-variable -std=c++11 -pthread -pg
+ g++ ./LifxLightBulb.cpp ./socket/Socket.cpp -o ./LifxLightBulb.o -Wall -Wno-unused-variable --std=c++11 -pthread -pg -I. -I./socket
+
+compile:
+ rm -f *.bin
+ particle compile raspberry-pi
+ #particle compile photon
+
+
+flash:
+ particle flash Pi-1 raspberry-pi*.bin
+
+PHONY += clean
+clean:
+ rm -f *.bin
+
+PHONY += mrclean
+mrclean: clean
+ rm -rf ../docs
+
+tabbing:
+ uncrustify -c C.cfg --no-backup *.cpp
+ uncrustify -c C.cfg --no-backup *.h
+
+wc:
+ wc *.cpp *.h
+
+.PHONY: $(PHONY)
--- /dev/null
+
+This is a RaspberryPi C++ implementation of Lifx light bulb controller.
+
+Created as a part of our testbed that will include smart home devices that will use Particle cloud.
--- /dev/null
+# A few common Makefile items
+
+CC := gcc
+CXX := g++
+
+UNAME := $(shell uname)
+
+LIB_NAME := iotcloud
+LIB_SO := lib_$(LIB_NAME).so
+
+CPPFLAGS += -Wall -g -O0
+
+# Mac OSX options
+ifeq ($(UNAME), Darwin)
+CPPFLAGS += -D_XOPEN_SOURCE -DMAC
+endif