Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lights: properly divide rgb values for hsv conversion #1902

Merged
merged 3 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions code/espurna/config/general.h
Original file line number Diff line number Diff line change
Expand Up @@ -1188,20 +1188,22 @@
// Home Assistant also uses these, see Light::min_mireds, Light::max_mireds
// https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/light/__init__.py

#ifndef LIGHT_MIN_KELVIN
#define LIGHT_MIN_KELVIN 2000
// Used when LIGHT_USE_WHITE AND LIGHT_USE_CCT is 1 - (1000000/Kelvin = MiReds)
// Warning! Don't change this yet, NOT FULLY IMPLEMENTED!
#ifndef LIGHT_COLDWHITE_MIRED
#define LIGHT_COLDWHITE_MIRED 153 // Coldwhite Strip, Value must be __BELOW__ W2!! (Default: 6535 Kelvin/153 MiRed)
#endif

#ifndef LIGHT_MAX_KELVIN
#define LIGHT_MAX_KELVIN 6536
#ifndef LIGHT_WARMWHITE_MIRED
#define LIGHT_WARMWHITE_MIRED 500 // Warmwhite Strip, Value must be __ABOVE__ W1!! (Default: 2000 Kelvin/500 MiRed)
#endif

#ifndef LIGHT_MIN_MIREDS
#define LIGHT_MIN_MIREDS 153
#ifndef LIGHT_COLDWHITE_KELVIN
#define LIGHT_COLDWHITE_KELVIN 6536
#endif

#ifndef LIGHT_MAX_MIREDS
#define LIGHT_MAX_MIREDS 500
#ifndef LIGHT_WARMWHITE_KELVIN
#define LIGHT_WARMWHITE_KELVIN 2000
#endif

#ifndef LIGHT_STEP
Expand All @@ -1220,11 +1222,6 @@
#define LIGHT_USE_CCT 0 // Use the 5th channel as Coldwhite LEDs, LIGHT_USE_WHITE must be 1.
#endif

// Used when LIGHT_USE_WHITE AND LIGHT_USE_CCT is 1 - (1000000/Kelvin = MiReds)
// Warning! Don't change this yet, NOT FULLY IMPLEMENTED!
#define LIGHT_COLDWHITE_MIRED 153 // Coldwhite Strip, Value must be __BELOW__ W2!! (Default: 6535 Kelvin/153 MiRed)
#define LIGHT_WARMWHITE_MIRED 500 // Warmwhite Strip, Value must be __ABOVE__ W1!! (Default: 2000 Kelvin/500 MiRed)

#ifndef LIGHT_USE_GAMMA
#define LIGHT_USE_GAMMA 0 // Use gamma correction for color channels
#endif
Expand Down
8 changes: 4 additions & 4 deletions code/espurna/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ namespace Light {

// Default to the Philips Hue value that HA also use.
// https://developers.meethue.com/documentation/core-concepts
constexpr const unsigned int MIREDS_MIN = LIGHT_MIN_MIREDS;
constexpr const unsigned int MIREDS_MAX = LIGHT_MAX_MIREDS;
constexpr const unsigned int MIREDS_COLDWHITE = LIGHT_COLDWHITE_MIRED;
constexpr const unsigned int MIREDS_WARMWHITE = LIGHT_WARMWHITE_MIRED;

constexpr const unsigned int KELVIN_MIN = LIGHT_MIN_KELVIN;
constexpr const unsigned int KELVIN_MAX = LIGHT_MAX_KELVIN;
constexpr const unsigned int KELVIN_WARMWHITE = LIGHT_WARMWHITE_KELVIN;
constexpr const unsigned int KELVIN_COLDWHITE = LIGHT_COLDWHITE_KELVIN;

constexpr const unsigned int PWM_MIN = LIGHT_MIN_PWM;
constexpr const unsigned int PWM_MAX = LIGHT_MAX_PWM;
Expand Down
68 changes: 31 additions & 37 deletions code/espurna/light.ino
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ bool _light_use_cct = false;
bool _light_use_gamma = false;
unsigned long _light_steps_left = 1;
unsigned char _light_brightness = Light::BRIGHTNESS_MAX;
unsigned int _light_mireds = lround((LIGHT_COLDWHITE_MIRED+LIGHT_WARMWHITE_MIRED)/2);
unsigned int _light_mireds = lround((Light::MIREDS_COLDWHITE + Light::MIREDS_WARMWHITE) / 2);

using light_brightness_func_t = void();
light_brightness_func_t* _light_brightness_func = nullptr;
Expand Down Expand Up @@ -135,7 +135,7 @@ void _lightApplyBrightnessColor() {
if (_light_use_cct) {

// This change the range from 153-500 to 0-347 so we get a value between 0 and 1 in the end.
double miredFactor = ((double) _light_mireds - (double) LIGHT_COLDWHITE_MIRED)/((double) LIGHT_WARMWHITE_MIRED - (double) LIGHT_COLDWHITE_MIRED);
double miredFactor = ((double) _light_mireds - (double) Light::MIREDS_COLDWHITE)/((double) Light::MIREDS_WARMWHITE - (double) Light::MIREDS_COLDWHITE);

// set cold white
_light_channel[3].inputValue = 0;
Expand Down Expand Up @@ -281,32 +281,32 @@ void _fromHSV(const char * hsv) {
double f = (h - floor(h));
double s = (double) value[1] / 100.0;

_light_brightness = lround((double) value[2] * 2.55); // (255/100)
unsigned char p = lround(255 * (1.0 - s));
unsigned char q = lround(255 * (1.0 - s * f));
unsigned char t = lround(255 * (1.0 - s * (1.0 - f)));
_light_brightness = lround((double) value[2] * (static_cast<double>(Light::BRIGHTNESS_MAX) / 100.0)); // (default 255/100)
unsigned char p = lround(Light::VALUE_MAX * (1.0 - s));
unsigned char q = lround(Light::VALUE_MAX * (1.0 - s * f));
unsigned char t = lround(Light::VALUE_MAX * (1.0 - s * (1.0 - f)));

switch (int(h)) {
case 0:
_setRGBInputValue(255, t, p);
_setRGBInputValue(Light::VALUE_MAX, t, p);
break;
case 1:
_setRGBInputValue(q, 255, p);
_setRGBInputValue(q, Light::VALUE_MAX, p);
break;
case 2:
_setRGBInputValue(p, 255, t);
_setRGBInputValue(p, Light::VALUE_MAX, t);
break;
case 3:
_setRGBInputValue(p, q, 255);
_setRGBInputValue(p, q, Light::VALUE_MAX);
break;
case 4:
_setRGBInputValue(t, p, 255);
_setRGBInputValue(t, p, Light::VALUE_MAX);
break;
case 5:
_setRGBInputValue(255, p, q);
_setRGBInputValue(Light::VALUE_MAX, p, q);
break;
default:
_setRGBInputValue(0, 0, 0);
_setRGBInputValue(Light::VALUE_MIN, Light::VALUE_MIN, Light::VALUE_MIN);
break;
}
}
Expand All @@ -319,10 +319,10 @@ void _fromKelvin(unsigned long kelvin) {

if(!_light_use_cct) return;

_light_mireds = constrain(static_cast<unsigned int>(lround(1000000UL / kelvin)), Light::MIREDS_MIN, Light::MIREDS_MAX);
_light_mireds = constrain(static_cast<unsigned int>(lround(1000000UL / kelvin)), Light::MIREDS_COLDWHITE, Light::MIREDS_WARMWHITE);

// This change the range from 153-500 to 0-347 so we get a value between 0 and 1 in the end.
double factor = ((double) _light_mireds - (double) LIGHT_COLDWHITE_MIRED)/((double) LIGHT_WARMWHITE_MIRED - (double) LIGHT_COLDWHITE_MIRED);
double factor = ((double) _light_mireds - (double) Light::MIREDS_COLDWHITE)/((double) Light::MIREDS_WARMWHITE - (double) Light::MIREDS_COLDWHITE);
unsigned char warm = lround(factor * Light::VALUE_MAX);
unsigned char cold = lround(((double) 1.0 - factor) * Light::VALUE_MAX);

Expand All @@ -331,7 +331,7 @@ void _fromKelvin(unsigned long kelvin) {
return;
}

_light_mireds = constrain(static_cast<unsigned int>(lround(1000000UL / kelvin)), Light::MIREDS_MIN, Light::MIREDS_MAX);
_light_mireds = constrain(static_cast<unsigned int>(lround(1000000UL / kelvin)), Light::MIREDS_COLDWHITE, Light::MIREDS_WARMWHITE);

if (_light_use_cct) {
_setRGBInputValue(Light::VALUE_MAX, Light::VALUE_MAX, Light::VALUE_MAX);
Expand All @@ -358,15 +358,15 @@ void _fromKelvin(unsigned long kelvin) {

// Color temperature is measured in mireds (kelvin = 1e6/mired)
void _fromMireds(unsigned long mireds) {
unsigned long kelvin = constrain(static_cast<unsigned int>(1000000UL / mireds), Light::KELVIN_MIN, Light::KELVIN_MAX);
unsigned long kelvin = constrain(static_cast<unsigned int>(1000000UL / mireds), Light::KELVIN_WARMWHITE, Light::KELVIN_COLDWHITE);
_fromKelvin(kelvin);
}

// -----------------------------------------------------------------------------
// Output Values
// -----------------------------------------------------------------------------

void _toRGB(char * rgb, size_t len, bool target) {
void _toRGB(char * rgb, size_t len, bool target = false) {
unsigned long value = 0;

value += target ? _light_channel[0].target : _light_channel[0].inputValue;
Expand All @@ -378,19 +378,17 @@ void _toRGB(char * rgb, size_t len, bool target) {
snprintf_P(rgb, len, PSTR("#%06X"), value);
}

void _toRGB(char * rgb, size_t len) {
_toRGB(rgb, len, false);
}

void _toHSV(char * hsv, size_t len, bool target) {
double h, s, v;
void _toHSV(char * hsv, size_t len) {
double h {0.}, s {0.}, v {0.};
double r {0.}, g {0.}, b {0.};
double min {0.}, max {0.};

double r = static_cast<double>(target ? _light_channel[0].target : _light_channel[0].value);
double g = static_cast<double>(target ? _light_channel[1].target : _light_channel[1].value);
double b = static_cast<double>(target ? _light_channel[2].target : _light_channel[2].value);
r = static_cast<double>(_light_channel[0].target) / Light::VALUE_MAX;
g = static_cast<double>(_light_channel[1].target) / Light::VALUE_MAX;
b = static_cast<double>(_light_channel[2].target) / Light::VALUE_MAX;

double min = std::min(r, std::min(g, b));
double max = std::max(r, std::max(g, b));
min = std::min(r, std::min(g, b));
max = std::max(r, std::max(g, b));

v = 100.0 * max;
if (v == 0) {
Expand All @@ -414,18 +412,14 @@ void _toHSV(char * hsv, size_t len, bool target) {
}
}

// String
// Convert to string. Using lround, since we can't (yet) printf floats
snprintf(hsv, len, "%d,%d,%d",
static_cast<int>(lround(h)),
static_cast<int>(lround(s)),
static_cast<int>(lround(v))
);
}

void _toHSV(char * hsv, size_t len) {
_toHSV(hsv, len, false);
}

void _toLong(char * color, size_t len, bool target) {

if (!_light_has_color) return;
Expand Down Expand Up @@ -585,7 +579,7 @@ void _lightSaveSettings() {

void _lightRestoreSettings() {
for (unsigned int i=0; i < _light_channel.size(); i++) {
_light_channel[i].inputValue = getSetting("ch", i, i==0 ? 255 : 0).toInt();
_light_channel[i].inputValue = getSetting("ch", i, (i == 0) ? Light::VALUE_MAX : 0).toInt();
}
_light_brightness = getSetting("brightness", Light::BRIGHTNESS_MAX).toInt();
_light_mireds = getSetting("mireds", _light_mireds).toInt();
Expand Down Expand Up @@ -707,7 +701,7 @@ void lightMQTT() {
}
mqttSend(MQTT_TOPIC_COLOR_RGB, buffer);

_toHSV(buffer, sizeof(buffer), true);
_toHSV(buffer, sizeof(buffer));
mqttSend(MQTT_TOPIC_COLOR_HSV, buffer);

}
Expand Down Expand Up @@ -1041,7 +1035,7 @@ void _lightAPISetup() {

apiRegister(MQTT_TOPIC_COLOR_HSV,
[](char * buffer, size_t len) {
_toHSV(buffer, len, true);
_toHSV(buffer, len);
},
[](const char * payload) {
lightColor(payload, false);
Expand Down
Loading