mirror of https://github.com/arendst/Tasmota.git
Tentative for 'xy' color space control from Alexa app (Philips Hue emulation)
This commit is contained in:
parent
e4173848b9
commit
d1b073e01d
|
@ -438,9 +438,7 @@ class LightStateClass {
|
||||||
static void RgbToHsb(uint8_t r, uint8_t g, uint8_t b, uint16_t *r_hue, uint8_t *r_sat, uint8_t *r_bri);
|
static void RgbToHsb(uint8_t r, uint8_t g, uint8_t b, uint16_t *r_hue, uint8_t *r_sat, uint8_t *r_bri);
|
||||||
static void HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b);
|
static void HsToRgb(uint16_t hue, uint8_t sat, uint8_t *r_r, uint8_t *r_g, uint8_t *r_b);
|
||||||
static void RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y);
|
static void RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x, float *r_y);
|
||||||
#if 0
|
static void XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_t *rb);
|
||||||
static void XyToRgb(float x, float y, float bri, float *r, float *g, float *b);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -561,24 +559,39 @@ void LightStateClass::RgbToXy(uint8_t i_r, uint8_t i_g, uint8_t i_b, float *r_x,
|
||||||
if (r_y) *r_y = y;
|
if (r_y) *r_y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
void LightStateClass::XyToRgb(float x, float y, uint8_t *rr, uint8_t *rg, uint8_t *rb)
|
||||||
// We don't need XY to RGB right now, but code is ready - jst in case
|
|
||||||
void LightStateClass::XyToRgb(float x, float y, float bri, float *rr, float *rg, float *rb)
|
|
||||||
{
|
{
|
||||||
x = (x > 0.99f ? 0.99f : (x < 0.01f ? 0.01f : x));
|
x = (x > 0.99f ? 0.99f : (x < 0.01f ? 0.01f : x));
|
||||||
y = (y > 0.99f ? 0.99f : (y < 0.01f ? 0.01f : y));
|
y = (y > 0.99f ? 0.99f : (y < 0.01f ? 0.01f : y));
|
||||||
float z = 1.0f - x - y;
|
float z = 1.0f - x - y;
|
||||||
float Y = bri;
|
//float Y = 1.0f;
|
||||||
float X = (Y / y) * x;
|
float X = x / y;
|
||||||
float Z = (Y / y) * z;
|
float Z = z / y;
|
||||||
float r = X * 1.4628067 - Y * 0.1840623 - Z * 0.2743606;
|
// float r = X * 1.4628067f - 0.1840623f - Z * 0.2743606f;
|
||||||
float g = -X * 0.5217933 + Y * 1.4472381 + Z * 0.0677227;
|
// float g = -X * 0.5217933f + 1.4472381f + Z * 0.0677227f;
|
||||||
float b = X * 0.0349342 - Y * 0.0968930 + Z * 1.2884099;
|
// float b = X * 0.0349342f - 0.0968930f + Z * 1.2884099f;
|
||||||
if (rr) { *rr = r <= 0.0031308f ? 12.92f * r : (1.0f + 0.055f) * powf(r, (1.0f / 2.4f)) - 0.055f; }
|
float r = X * 3.2406f - 1.5372f - Z * 0.4986f;
|
||||||
if (rg) { *rg = g <= 0.0031308f ? 12.92f * g : (1.0f + 0.055f) * powf(g, (1.0f / 2.4f)) - 0.055f; }
|
float g = -X * 0.9689f + 1.8758f + Z * 0.0415f;
|
||||||
if (rb) { *rb = b <= 0.0031308f ? 12.92f * b : (1.0f + 0.055f) * powf(b, (1.0f / 2.4f)) - 0.055f; }
|
float b = X * 0.0557f - 0.2040f + Z * 1.0570f;
|
||||||
|
float max = (r > g && r > b) ? r : (g > b) ? g : b;
|
||||||
|
r = r / max; // normalize to max == 1.0
|
||||||
|
g = g / max;
|
||||||
|
b = b / max;
|
||||||
|
r = (r <= 0.0031308f) ? 12.92f * r : 1.055f * powf(r, (1.0f / 2.4f)) - 0.055f;
|
||||||
|
g = (g <= 0.0031308f) ? 12.92f * g : 1.055f * powf(g, (1.0f / 2.4f)) - 0.055f;
|
||||||
|
b = (b <= 0.0031308f) ? 12.92f * b : 1.055f * powf(b, (1.0f / 2.4f)) - 0.055f;
|
||||||
|
//
|
||||||
|
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, "XyToRgb XZ (%s %s) rgb (%s %s %s)",
|
||||||
|
// String(X,5).c_str(), String(Z,5).c_str(),
|
||||||
|
// String(r,5).c_str(), String(g,5).c_str(),String(b,5).c_str());
|
||||||
|
|
||||||
|
int32_t ir = r * 255.0f + 0.5f;
|
||||||
|
int32_t ig = g * 255.0f + 0.5f;
|
||||||
|
int32_t ib = b * 255.0f + 0.5f;
|
||||||
|
if (rr) { *rr = (ir > 255 ? 255: (ir < 0 ? 0 : ir)); }
|
||||||
|
if (rg) { *rg = (ig > 255 ? 255: (ig < 0 ? 0 : ig)); }
|
||||||
|
if (rb) { *rb = (ib > 255 ? 255: (ib < 0 ? 0 : ib)); }
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
class LightControllerClass {
|
class LightControllerClass {
|
||||||
LightStateClass *_state;
|
LightStateClass *_state;
|
||||||
|
|
|
@ -571,6 +571,10 @@ uint16_t prev_hue = 0;
|
||||||
uint8_t prev_sat = 0;
|
uint8_t prev_sat = 0;
|
||||||
uint8_t prev_bri = 254;
|
uint8_t prev_bri = 254;
|
||||||
uint16_t prev_ct = 254;
|
uint16_t prev_ct = 254;
|
||||||
|
float prev_x = 0.31271f; // default to D65 white
|
||||||
|
float prev_y = 0.32902f; // https://en.wikipedia.org/wiki/Illuminant_D65
|
||||||
|
char prev_x_str[25] = "\0"; // store previously set xy by Alexa app
|
||||||
|
char prev_y_str[25] = "\0";
|
||||||
|
|
||||||
void HueLightStatus1(uint8_t device, String *response)
|
void HueLightStatus1(uint8_t device, String *response)
|
||||||
{
|
{
|
||||||
|
@ -631,9 +635,17 @@ void HueLightStatus1(uint8_t device, String *response)
|
||||||
light_status += "\"colormode\":\"" + String(g_gotct ? "ct" : "hs") + "\",";
|
light_status += "\"colormode\":\"" + String(g_gotct ? "ct" : "hs") + "\",";
|
||||||
}
|
}
|
||||||
if (LST_RGB <= light_subtype) { // colors
|
if (LST_RGB <= light_subtype) { // colors
|
||||||
float x, y;
|
if (prev_x_str[0] && prev_y_str[0]) {
|
||||||
light_state.getXY(&x, &y);
|
light_status += "\"xy\":[";
|
||||||
light_status += "\"xy\":[" + String(x, 5) + "," + String(y, 5) + "],";
|
light_status += prev_x_str;
|
||||||
|
light_status += ",";
|
||||||
|
light_status += prev_y_str;
|
||||||
|
light_status += "],";
|
||||||
|
} else {
|
||||||
|
float x, y;
|
||||||
|
light_state.getXY(&x, &y);
|
||||||
|
light_status += "\"xy\":[" + String(x, 5) + "," + String(y, 5) + "],";
|
||||||
|
}
|
||||||
light_status += "\"hue\":" + String(hue) + ",";
|
light_status += "\"hue\":" + String(hue) + ",";
|
||||||
light_status += "\"sat\":" + String(sat) + ",";
|
light_status += "\"sat\":" + String(sat) + ",";
|
||||||
}
|
}
|
||||||
|
@ -752,6 +764,7 @@ void HueLights(String *path)
|
||||||
g_gotct = true;
|
g_gotct = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
prev_x_str[0] = prev_y_str[0] = 0; // reset xy string
|
||||||
|
|
||||||
if (hue_json.containsKey("bri")) { // Brightness is a scale from 1 (the minimum the light is capable of) to 254 (the maximum). Note: a brightness of 1 is not off.
|
if (hue_json.containsKey("bri")) { // Brightness is a scale from 1 (the minimum the light is capable of) to 254 (the maximum). Note: a brightness of 1 is not off.
|
||||||
tmp = hue_json["bri"];
|
tmp = hue_json["bri"];
|
||||||
|
@ -800,6 +813,27 @@ void HueLights(String *path)
|
||||||
}
|
}
|
||||||
resp = true;
|
resp = true;
|
||||||
}
|
}
|
||||||
|
if (hue_json.containsKey("xy")) { // Saturation of the light. 254 is the most saturated (colored) and 0 is the least saturated (white).
|
||||||
|
prev_x = hue_json["xy"][0];
|
||||||
|
prev_y = hue_json["xy"][1];
|
||||||
|
const String &x_str = hue_json["xy"][0];
|
||||||
|
const String &y_str = hue_json["xy"][1];
|
||||||
|
x_str.toCharArray(prev_x_str, sizeof(prev_x_str));
|
||||||
|
y_str.toCharArray(prev_y_str, sizeof(prev_y_str));
|
||||||
|
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, "XY (%s %s)", String(prev_x,5).c_str(), String(prev_y,5).c_str());
|
||||||
|
uint8_t rr,gg,bb;
|
||||||
|
LightStateClass::XyToRgb(prev_x, prev_y, &rr, &gg, &bb);
|
||||||
|
LightStateClass::RgbToHsb(rr, gg, bb, &hue, &sat, nullptr);
|
||||||
|
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, "XY RGB (%d %d %d) HS (%d %d)", rr,gg,bb,hue,sat);
|
||||||
|
if (resp) { response += ","; }
|
||||||
|
response += FPSTR(HUE_LIGHT_RESPONSE_JSON);
|
||||||
|
response.replace("{id", String(device));
|
||||||
|
response.replace("{cm", "xy");
|
||||||
|
response.replace("{re", "[" + x_str + "," + y_str + "]");
|
||||||
|
g_gotct = false;
|
||||||
|
resp = true;
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
if (hue_json.containsKey("ct")) { // Color temperature 153 (Cold) to 500 (Warm)
|
if (hue_json.containsKey("ct")) { // Color temperature 153 (Cold) to 500 (Warm)
|
||||||
ct = hue_json["ct"];
|
ct = hue_json["ct"];
|
||||||
prev_ct = ct; // store commande value
|
prev_ct = ct; // store commande value
|
||||||
|
|
Loading…
Reference in New Issue