WLED/wled00/src/dependencies/espalexa/EspalexaDevice.cpp

309 lines
6.4 KiB
C++
Raw Normal View History

2019-01-09 22:52:42 +01:00
//EspalexaDevice Class
#include "EspalexaDevice.h"
EspalexaDevice::EspalexaDevice(){}
2019-03-01 17:10:42 +01:00
EspalexaDevice::EspalexaDevice(String deviceName, BrightnessCallbackFunction gnCallback, uint8_t initialValue) { //constructor
2019-01-09 22:52:42 +01:00
_deviceName = deviceName;
_callback = gnCallback;
_val = initialValue;
_val_last = _val;
2019-03-01 17:10:42 +01:00
_type = EspalexaDeviceType::dimmable;
2019-01-09 22:52:42 +01:00
}
2019-03-01 17:10:42 +01:00
EspalexaDevice::EspalexaDevice(String deviceName, DeviceCallbackFunction gnCallback, EspalexaDeviceType t, uint8_t initialValue) { //constructor for color device
2019-01-09 22:52:42 +01:00
_deviceName = deviceName;
2019-03-01 17:10:42 +01:00
_callbackDev = gnCallback;
2019-01-09 22:52:42 +01:00
_callback = nullptr;
2019-03-01 17:10:42 +01:00
_type = t;
2019-01-09 22:52:42 +01:00
_val = initialValue;
_val_last = _val;
}
EspalexaDevice::~EspalexaDevice(){/*nothing to destruct*/}
2019-03-01 17:10:42 +01:00
uint8_t EspalexaDevice::getId()
2019-01-09 22:52:42 +01:00
{
2019-03-01 17:10:42 +01:00
return _id;
2019-01-09 22:52:42 +01:00
}
2019-03-01 17:10:42 +01:00
EspalexaColorMode EspalexaDevice::getColorMode()
2019-01-09 22:52:42 +01:00
{
2019-03-01 17:10:42 +01:00
return _mode;
}
EspalexaDeviceType EspalexaDevice::getType()
{
return _type;
2019-01-09 22:52:42 +01:00
}
String EspalexaDevice::getName()
{
return _deviceName;
}
2019-03-01 17:10:42 +01:00
EspalexaDeviceProperty EspalexaDevice::getLastChangedProperty()
2019-01-09 22:52:42 +01:00
{
return _changed;
}
uint8_t EspalexaDevice::getValue()
{
return _val;
}
2019-03-01 17:10:42 +01:00
uint8_t EspalexaDevice::getPercent()
{
uint16_t perc = _val * 100;
return perc / 255;
}
uint8_t EspalexaDevice::getDegrees()
{
return getPercent();
}
2019-01-09 22:52:42 +01:00
uint16_t EspalexaDevice::getHue()
{
return _hue;
}
uint8_t EspalexaDevice::getSat()
{
return _sat;
}
2019-03-01 17:10:42 +01:00
float EspalexaDevice::getX()
{
return _x;
}
float EspalexaDevice::getY()
{
return _y;
}
2019-01-09 22:52:42 +01:00
uint16_t EspalexaDevice::getCt()
{
if (_ct == 0) return 500;
return _ct;
}
2019-03-01 17:10:42 +01:00
uint32_t EspalexaDevice::getKelvin()
2019-01-09 22:52:42 +01:00
{
2019-03-01 17:10:42 +01:00
if (_ct == 0) return 2000;
return 1000000/_ct;
}
uint32_t EspalexaDevice::getRGB()
{
if (_rgb != 0) return _rgb; //color has not changed
2019-01-09 22:52:42 +01:00
uint8_t rgb[3];
2019-03-01 17:10:42 +01:00
float r, g, b;
2019-01-09 22:52:42 +01:00
2019-03-01 17:10:42 +01:00
if (_mode == EspalexaColorMode::none) return 0;
if (_mode == EspalexaColorMode::ct)
2019-01-09 22:52:42 +01:00
{
//TODO tweak a bit to match hue lamp characteristics
//based on https://gist.github.com/paulkaplan/5184275
float temp = 10000/ _ct; //kelvins = 1,000,000/mired (and that /100)
float r, g, b;
if( temp <= 66 ){
r = 255;
g = temp;
g = 99.470802 * log(g) - 161.119568;
if( temp <= 19){
b = 0;
} else {
b = temp-10;
b = 138.517731 * log(b) - 305.044793;
}
} else {
r = temp - 60;
r = 329.698727 * pow(r, -0.13320476);
g = temp - 60;
g = 288.12217 * pow(g, -0.07551485 );
b = 255;
}
rgb[0] = (byte)constrain(r,0.1,255.1);
rgb[1] = (byte)constrain(g,0.1,255.1);
rgb[2] = (byte)constrain(b,0.1,255.1);
2019-03-01 17:10:42 +01:00
} else if (_mode == EspalexaColorMode::hs)
{
2019-01-09 22:52:42 +01:00
float h = ((float)_hue)/65535.0;
float s = ((float)_sat)/255.0;
byte i = floor(h*6);
float f = h * 6-i;
float p = 255 * (1-s);
float q = 255 * (1-f*s);
float t = 255 * (1-(1-f)*s);
switch (i%6) {
case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break;
case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break;
case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break;
case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break;
case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break;
case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q;
}
2019-03-01 17:10:42 +01:00
} else if (_mode == EspalexaColorMode::xy)
{
//Source: https://www.developers.meethue.com/documentation/color-conversions-rgb-xy
float z = 1.0f - _x - _y;
float X = (1.0f / _y) * _x;
float Z = (1.0f / _y) * z;
float r = (int)255*(X * 1.656492f - 0.354851f - Z * 0.255038f);
float g = (int)255*(-X * 0.707196f + 1.655397f + Z * 0.036152f);
float b = (int)255*(X * 0.051713f - 0.121364f + Z * 1.011530f);
if (r > b && r > g && r > 1.0f) {
// red is too big
g = g / r;
b = b / r;
r = 1.0f;
} else if (g > b && g > r && g > 1.0f) {
// green is too big
r = r / g;
b = b / g;
g = 1.0f;
} else if (b > r && b > g && b > 1.0f) {
// blue is too big
r = r / b;
g = g / b;
b = 1.0f;
}
// Apply gamma correction
r = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * pow(r, (1.0f / 2.4f)) - 0.055f;
g = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * pow(g, (1.0f / 2.4f)) - 0.055f;
b = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * pow(b, (1.0f / 2.4f)) - 0.055f;
if (r > b && r > g) {
// red is biggest
if (r > 1.0f) {
g = g / r;
b = b / r;
r = 1.0f;
}
} else if (g > b && g > r) {
// green is biggest
if (g > 1.0f) {
r = r / g;
b = b / g;
g = 1.0f;
}
} else if (b > r && b > g) {
// blue is biggest
if (b > 1.0f) {
r = r / b;
g = g / b;
b = 1.0f;
}
}
rgb[0] = 255.0*r;
rgb[1] = 255.0*g;
rgb[2] = 255.0*b;
2019-01-09 22:52:42 +01:00
}
2019-03-01 17:10:42 +01:00
_rgb = ((rgb[0] << 16) | (rgb[1] << 8) | (rgb[2]));
return _rgb;
}
uint8_t EspalexaDevice::getR()
{
return (getRGB() >> 16) & 0xFF;
}
uint8_t EspalexaDevice::getG()
{
return (getRGB() >> 8) & 0xFF;
}
uint8_t EspalexaDevice::getB()
{
return getRGB() & 0xFF;
2019-01-09 22:52:42 +01:00
}
uint8_t EspalexaDevice::getLastValue()
{
if (_val_last == 0) return 255;
return _val_last;
}
2019-03-01 17:10:42 +01:00
void EspalexaDevice::setPropertyChanged(EspalexaDeviceProperty p)
2019-01-09 22:52:42 +01:00
{
_changed = p;
}
2019-03-01 17:10:42 +01:00
void EspalexaDevice::setId(uint8_t id)
{
_id = id;
}
2019-01-09 22:52:42 +01:00
//you need to re-discover the device for the Alexa name to change
void EspalexaDevice::setName(String name)
{
_deviceName = name;
}
void EspalexaDevice::setValue(uint8_t val)
{
if (_val != 0)
{
_val_last = _val;
}
if (val != 0)
{
_val_last = val;
}
_val = val;
}
void EspalexaDevice::setPercent(uint8_t perc)
{
uint16_t val = perc * 255;
val /= 100;
if (val > 255) val = 255;
setValue(val);
}
2019-03-01 17:10:42 +01:00
void EspalexaDevice::setColorXY(float x, float y)
{
_x = x;
_y = y;
_rgb = 0;
_mode = EspalexaColorMode::xy;
}
2019-01-09 22:52:42 +01:00
void EspalexaDevice::setColor(uint16_t hue, uint8_t sat)
{
_hue = hue;
_sat = sat;
2019-03-01 17:10:42 +01:00
_rgb = 0;
_mode = EspalexaColorMode::hs;
2019-01-09 22:52:42 +01:00
}
void EspalexaDevice::setColor(uint16_t ct)
{
_ct = ct;
2019-03-01 17:10:42 +01:00
_rgb = 0;
_mode =EspalexaColorMode::ct;
}
void EspalexaDevice::setColor(uint8_t r, uint8_t g, uint8_t b)
{
float X = r * 0.664511f + g * 0.154324f + b * 0.162028f;
float Y = r * 0.283881f + g * 0.668433f + b * 0.047685f;
float Z = r * 0.000088f + g * 0.072310f + b * 0.986039f;
_x = X / (X + Y + Z);
_y = Y / (X + Y + Z);
_rgb = ((r << 16) | (g << 8) | b);
_mode = EspalexaColorMode::xy;
2019-01-09 22:52:42 +01:00
}
void EspalexaDevice::doCallback()
{
2019-03-01 17:10:42 +01:00
(_callback != nullptr) ? _callback(_val) : _callbackDev(this);
2019-01-09 22:52:42 +01:00
}