|
@ -34,7 +34,7 @@ typedef struct { |
|
|
bool state; |
|
|
bool state; |
|
|
unsigned char inputValue; // value that has been inputted
|
|
|
unsigned char inputValue; // value that has been inputted
|
|
|
unsigned char value; // normalized value including brightness
|
|
|
unsigned char value; // normalized value including brightness
|
|
|
unsigned char shadow; // represented value
|
|
|
|
|
|
|
|
|
unsigned char target; // target value
|
|
|
double current; // transition value
|
|
|
double current; // transition value
|
|
|
} channel_t; |
|
|
} channel_t; |
|
|
std::vector<channel_t> _light_channel; |
|
|
std::vector<channel_t> _light_channel; |
|
@ -314,25 +314,29 @@ void _fromMireds(unsigned long mireds) { |
|
|
// Output Values
|
|
|
// Output Values
|
|
|
// -----------------------------------------------------------------------------
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
void _toRGB(char * rgb, size_t len) { |
|
|
|
|
|
|
|
|
void _toRGB(char * rgb, size_t len, bool target) { |
|
|
unsigned long value = 0; |
|
|
unsigned long value = 0; |
|
|
|
|
|
|
|
|
value += _light_channel[0].inputValue; |
|
|
|
|
|
|
|
|
value += target ? _light_channel[0].target : _light_channel[0].inputValue; |
|
|
value <<= 8; |
|
|
value <<= 8; |
|
|
value += _light_channel[1].inputValue; |
|
|
|
|
|
|
|
|
value += target ? _light_channel[1].target : _light_channel[1].inputValue; |
|
|
value <<= 8; |
|
|
value <<= 8; |
|
|
value += _light_channel[2].inputValue; |
|
|
|
|
|
|
|
|
value += target ? _light_channel[2].target : _light_channel[2].inputValue; |
|
|
|
|
|
|
|
|
snprintf_P(rgb, len, PSTR("#%06X"), value); |
|
|
snprintf_P(rgb, len, PSTR("#%06X"), value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _toHSV(char * hsv, size_t len) { |
|
|
|
|
|
|
|
|
void _toRGB(char * rgb, size_t len) { |
|
|
|
|
|
_toRGB(rgb, len, false); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _toHSV(char * hsv, size_t len, bool target) { |
|
|
double h, s, v; |
|
|
double h, s, v; |
|
|
double brightness = (double) _light_brightness / LIGHT_MAX_BRIGHTNESS; |
|
|
double brightness = (double) _light_brightness / LIGHT_MAX_BRIGHTNESS; |
|
|
|
|
|
|
|
|
double r = (double) (_light_channel[0].inputValue * brightness) / 255.0; |
|
|
|
|
|
double g = (double) (_light_channel[1].inputValue * brightness) / 255.0; |
|
|
|
|
|
double b = (double) (_light_channel[2].inputValue * brightness) / 255.0; |
|
|
|
|
|
|
|
|
double r = (double) ((target ? _light_channel[0].target : _light_channel[0].inputValue) * brightness) / 255.0; |
|
|
|
|
|
double g = (double) ((target ? _light_channel[1].target : _light_channel[1].inputValue) * brightness) / 255.0; |
|
|
|
|
|
double b = (double) ((target ? _light_channel[2].target : _light_channel[2].inputValue) * brightness) / 255.0; |
|
|
|
|
|
|
|
|
double min = std::min(r, std::min(g, b)); |
|
|
double min = std::min(r, std::min(g, b)); |
|
|
double max = std::max(r, std::max(g, b)); |
|
|
double max = std::max(r, std::max(g, b)); |
|
@ -363,27 +367,41 @@ void _toHSV(char * hsv, size_t len) { |
|
|
snprintf_P(hsv, len, PSTR("%d,%d,%d"), round(h), round(s), round(v)); |
|
|
snprintf_P(hsv, len, PSTR("%d,%d,%d"), round(h), round(s), round(v)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _toLong(char * color, size_t len) { |
|
|
|
|
|
|
|
|
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; |
|
|
if (!_light_has_color) return; |
|
|
|
|
|
|
|
|
snprintf_P(color, len, PSTR("%d,%d,%d"), |
|
|
snprintf_P(color, len, PSTR("%d,%d,%d"), |
|
|
(int) _light_channel[0].inputValue, |
|
|
|
|
|
(int) _light_channel[1].inputValue, |
|
|
|
|
|
(int) _light_channel[2].inputValue |
|
|
|
|
|
|
|
|
(int) (target ? _light_channel[0].target : _light_channel[0].inputValue), |
|
|
|
|
|
(int) (target ? _light_channel[1].target : _light_channel[1].inputValue), |
|
|
|
|
|
(int) (target ? _light_channel[2].target : _light_channel[2].inputValue) |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _toCSV(char * buffer, size_t len, bool applyBrightness) { |
|
|
|
|
|
|
|
|
void _toLong(char * color, size_t len) { |
|
|
|
|
|
_toLong(color, len, false); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _toCSV(char * buffer, size_t len, bool applyBrightness, bool target) { |
|
|
char num[10]; |
|
|
char num[10]; |
|
|
float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1; |
|
|
float b = applyBrightness ? (float) _light_brightness / LIGHT_MAX_BRIGHTNESS : 1; |
|
|
for (unsigned char i=0; i<_light_channel.size(); i++) { |
|
|
for (unsigned char i=0; i<_light_channel.size(); i++) { |
|
|
itoa(_light_channel[i].inputValue * b, num, 10); |
|
|
|
|
|
|
|
|
itoa((target ? _light_channel[i].target : _light_channel[i].inputValue) * b, num, 10); |
|
|
if (i>0) strncat(buffer, ",", len--); |
|
|
if (i>0) strncat(buffer, ",", len--); |
|
|
strncat(buffer, num, len); |
|
|
strncat(buffer, num, len); |
|
|
len = len - strlen(num); |
|
|
len = len - strlen(num); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _toCSV(char * buffer, size_t len, bool applyBrightness) { |
|
|
|
|
|
_toCSV(buffer, len, applyBrightness, false); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
// -----------------------------------------------------------------------------
|
|
|
// PROVIDER
|
|
|
// PROVIDER
|
|
|
// -----------------------------------------------------------------------------
|
|
|
// -----------------------------------------------------------------------------
|
|
@ -399,37 +417,32 @@ unsigned int _toPWM(unsigned long value, bool gamma, bool reverse) { |
|
|
// Returns a PWM value for the given channel ID
|
|
|
// Returns a PWM value for the given channel ID
|
|
|
unsigned int _toPWM(unsigned char id) { |
|
|
unsigned int _toPWM(unsigned char id) { |
|
|
bool useGamma = _light_use_gamma && _light_has_color && (id < 3); |
|
|
bool useGamma = _light_use_gamma && _light_has_color && (id < 3); |
|
|
return _toPWM(_light_channel[id].shadow, useGamma, _light_channel[id].reverse); |
|
|
|
|
|
|
|
|
return _toPWM(_light_channel[id].current, useGamma, _light_channel[id].reverse); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _shadow() { |
|
|
|
|
|
|
|
|
void _transition() { |
|
|
|
|
|
|
|
|
// Update transition ticker
|
|
|
// Update transition ticker
|
|
|
_light_steps_left--; |
|
|
_light_steps_left--; |
|
|
if (_light_steps_left == 0) _light_transition_ticker.detach(); |
|
|
if (_light_steps_left == 0) _light_transition_ticker.detach(); |
|
|
|
|
|
|
|
|
// Transitions
|
|
|
// Transitions
|
|
|
unsigned char target; |
|
|
|
|
|
for (unsigned int i=0; i < _light_channel.size(); i++) { |
|
|
for (unsigned int i=0; i < _light_channel.size(); i++) { |
|
|
|
|
|
|
|
|
target = _light_state && _light_channel[i].state ? _light_channel[i].value : 0; |
|
|
|
|
|
|
|
|
|
|
|
if (_light_steps_left == 0) { |
|
|
if (_light_steps_left == 0) { |
|
|
_light_channel[i].current = target; |
|
|
|
|
|
|
|
|
_light_channel[i].current = _light_channel[i].target; |
|
|
} else { |
|
|
} else { |
|
|
double difference = (double) (target - _light_channel[i].current) / (_light_steps_left + 1); |
|
|
|
|
|
|
|
|
double difference = (double) (_light_channel[i].target - _light_channel[i].current) / (_light_steps_left + 1); |
|
|
_light_channel[i].current = _light_channel[i].current + difference; |
|
|
_light_channel[i].current = _light_channel[i].current + difference; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
_light_channel[i].shadow = _light_channel[i].current; |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void _lightProviderUpdate() { |
|
|
void _lightProviderUpdate() { |
|
|
|
|
|
|
|
|
_shadow(); |
|
|
|
|
|
|
|
|
_transition(); |
|
|
|
|
|
|
|
|
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
|
|
#if LIGHT_PROVIDER == LIGHT_PROVIDER_MY92XX
|
|
|
|
|
|
|
|
@ -572,13 +585,13 @@ void lightMQTT() { |
|
|
|
|
|
|
|
|
// Color
|
|
|
// Color
|
|
|
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { |
|
|
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { |
|
|
_toRGB(buffer, sizeof(buffer)); |
|
|
|
|
|
|
|
|
_toRGB(buffer, sizeof(buffer), true); |
|
|
} else { |
|
|
} else { |
|
|
_toLong(buffer, sizeof(buffer)); |
|
|
|
|
|
|
|
|
_toLong(buffer, sizeof(buffer), true); |
|
|
} |
|
|
} |
|
|
mqttSend(MQTT_TOPIC_COLOR_RGB, buffer); |
|
|
mqttSend(MQTT_TOPIC_COLOR_RGB, buffer); |
|
|
|
|
|
|
|
|
_toHSV(buffer, sizeof(buffer)); |
|
|
|
|
|
|
|
|
_toHSV(buffer, sizeof(buffer), true); |
|
|
mqttSend(MQTT_TOPIC_COLOR_HSV, buffer); |
|
|
mqttSend(MQTT_TOPIC_COLOR_HSV, buffer); |
|
|
|
|
|
|
|
|
// Mireds
|
|
|
// Mireds
|
|
@ -589,7 +602,7 @@ void lightMQTT() { |
|
|
|
|
|
|
|
|
// Channels
|
|
|
// Channels
|
|
|
for (unsigned int i=0; i < _light_channel.size(); i++) { |
|
|
for (unsigned int i=0; i < _light_channel.size(); i++) { |
|
|
itoa(_light_channel[i].inputValue, buffer, 10); |
|
|
|
|
|
|
|
|
itoa(_light_channel[i].target, buffer, 10); |
|
|
mqttSend(MQTT_TOPIC_CHANNEL, i, buffer); |
|
|
mqttSend(MQTT_TOPIC_CHANNEL, i, buffer); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -642,6 +655,12 @@ void lightUpdate(bool save, bool forward, bool group_forward) { |
|
|
|
|
|
|
|
|
_generateBrightness(); |
|
|
_generateBrightness(); |
|
|
|
|
|
|
|
|
|
|
|
// Update channels
|
|
|
|
|
|
for (unsigned int i=0; i < _light_channel.size(); i++) { |
|
|
|
|
|
_light_channel[i].target = _light_state && _light_channel[i].state ? _light_channel[i].value : 0; |
|
|
|
|
|
DEBUG_MSG_P("[LIGHT] Channel #%u target value: %u\n", i, _light_channel[i].target); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Configure color transition
|
|
|
// Configure color transition
|
|
|
_light_steps_left = _light_use_transitions ? _light_transition_time / LIGHT_TRANSITION_STEP : 1; |
|
|
_light_steps_left = _light_use_transitions ? _light_transition_time / LIGHT_TRANSITION_STEP : 1; |
|
|
_light_transition_ticker.attach_ms(LIGHT_TRANSITION_STEP, _lightProviderUpdate); |
|
|
_light_transition_ticker.attach_ms(LIGHT_TRANSITION_STEP, _lightProviderUpdate); |
|
@ -844,9 +863,9 @@ void _lightAPISetup() { |
|
|
apiRegister(MQTT_TOPIC_COLOR_RGB, |
|
|
apiRegister(MQTT_TOPIC_COLOR_RGB, |
|
|
[](char * buffer, size_t len) { |
|
|
[](char * buffer, size_t len) { |
|
|
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { |
|
|
if (getSetting("useCSS", LIGHT_USE_CSS).toInt() == 1) { |
|
|
_toRGB(buffer, len); |
|
|
|
|
|
|
|
|
_toRGB(buffer, len, true); |
|
|
} else { |
|
|
} else { |
|
|
_toLong(buffer, len); |
|
|
|
|
|
|
|
|
_toLong(buffer, len, true); |
|
|
} |
|
|
} |
|
|
}, |
|
|
}, |
|
|
[](const char * payload) { |
|
|
[](const char * payload) { |
|
@ -857,7 +876,7 @@ void _lightAPISetup() { |
|
|
|
|
|
|
|
|
apiRegister(MQTT_TOPIC_COLOR_HSV, |
|
|
apiRegister(MQTT_TOPIC_COLOR_HSV, |
|
|
[](char * buffer, size_t len) { |
|
|
[](char * buffer, size_t len) { |
|
|
_toHSV(buffer, len); |
|
|
|
|
|
|
|
|
_toHSV(buffer, len, true); |
|
|
}, |
|
|
}, |
|
|
[](const char * payload) { |
|
|
[](const char * payload) { |
|
|
lightColor(payload, false); |
|
|
lightColor(payload, false); |
|
@ -889,7 +908,7 @@ void _lightAPISetup() { |
|
|
snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_CHANNEL, id); |
|
|
snprintf_P(key, sizeof(key), PSTR("%s/%d"), MQTT_TOPIC_CHANNEL, id); |
|
|
apiRegister(key, |
|
|
apiRegister(key, |
|
|
[id](char * buffer, size_t len) { |
|
|
[id](char * buffer, size_t len) { |
|
|
snprintf_P(buffer, len, PSTR("%d"), lightChannel(id)); |
|
|
|
|
|
|
|
|
snprintf_P(buffer, len, PSTR("%d"), _light_channel[id].target); |
|
|
}, |
|
|
}, |
|
|
[id](const char * payload) { |
|
|
[id](const char * payload) { |
|
|
lightChannel(id, atoi(payload)); |
|
|
lightChannel(id, atoi(payload)); |
|
|