diff --git a/code/espurna/button.ino b/code/espurna/button.ino index 678fda7491..909516cfec 100644 --- a/code/espurna/button.ino +++ b/code/espurna/button.ino @@ -15,6 +15,8 @@ Copyright (C) 2016-2019 by Xose Pérez #include #include +#include "light.h" + typedef struct { DebounceEvent * button; unsigned long actions; diff --git a/code/espurna/config/progmem.h b/code/espurna/config/progmem.h index 1b8aaa3512..3a53b2aa60 100644 --- a/code/espurna/config/progmem.h +++ b/code/espurna/config/progmem.h @@ -2,6 +2,12 @@ // PROGMEM definitions //-------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------- +// Various strings +//-------------------------------------------------------------------------------- + +PROGMEM const char pstr_unknown[] = "UNKNOWN"; + //-------------------------------------------------------------------------------- // Reset reasons //-------------------------------------------------------------------------------- diff --git a/code/espurna/config/prototypes.h b/code/espurna/config/prototypes.h index 265a14f6c6..26f28cce55 100644 --- a/code/espurna/config/prototypes.h +++ b/code/espurna/config/prototypes.h @@ -177,24 +177,6 @@ int16_t i2c_read_int16(uint8_t address, uint8_t reg); int16_t i2c_read_int16_le(uint8_t address, uint8_t reg); void i2c_read_buffer(uint8_t address, uint8_t * buffer, size_t len); -// ----------------------------------------------------------------------------- -// Lights -// ----------------------------------------------------------------------------- - -unsigned char lightChannels(); - -void lightState(unsigned char i, bool state); -bool lightState(unsigned char i); - -void lightState(bool state); -bool lightState(); - -void lightBrightness(unsigned int brightness); -unsigned int lightBrightness(); - -unsigned int lightChannel(unsigned char id); -void lightChannel(unsigned char id, unsigned char value); - // ----------------------------------------------------------------------------- // MQTT // ----------------------------------------------------------------------------- diff --git a/code/espurna/encoder.ino b/code/espurna/encoder.ino index 4d7775241b..0f975c91bf 100644 --- a/code/espurna/encoder.ino +++ b/code/espurna/encoder.ino @@ -11,7 +11,7 @@ Copyright (C) 2018-2019 by Xose Pérez #include "libs/Encoder.h" #include -typedef struct { +struct encoder_t { Encoder * encoder; unsigned char button_pin; unsigned char button_logic; @@ -19,20 +19,27 @@ typedef struct { unsigned char mode; unsigned char channel1; // default unsigned char channel2; // only if button defined and pressed -} encoder_t; +}; std::vector _encoders; unsigned long _encoder_min_delta = 1; void _encoderConfigure() { - // Clean previous encoders - for (unsigned char i=0; i<_encoders.size(); i++) { - free(_encoders[i].encoder); + _encoder_min_delta = getSetting("encMinDelta", ENCODER_MINIMUM_DELTA).toInt(); + if (!_encoder_min_delta) _encoder_min_delta = 1; + + // no need to reload objects right now + if (_encoders.size()) return; + + // Clean previous encoders and re-add them + for (auto& encoder : _encoders) { + delete encoder.encoder; } _encoders.clear(); - // Load encoders + // TODO: encEnable + // TODO: implement reloading without re-allocating objects #if (ENCODER1_PIN1 != GPIO_NONE) && (ENCODER1_PIN2 != GPIO_NONE) { _encoders.push_back({ @@ -79,26 +86,21 @@ void _encoderConfigure() { } #endif - // Setup encoders - for (unsigned char i=0; i<_encoders.size(); i++) { - if (GPIO_NONE != _encoders[i].button_pin) { - pinMode(_encoders[i].button_pin, _encoders[i].button_mode); + // TODO: manage buttons through debounceevent? + for (auto& encoder : _encoders) { + if (GPIO_NONE != encoder.button_pin) { + pinMode(encoder.button_pin, encoder.button_mode); } } - _encoder_min_delta = getSetting("encMinDelta", ENCODER_MINIMUM_DELTA).toInt(); - if (!_encoder_min_delta) _encoder_min_delta = 1; - } void _encoderLoop() { // for each encoder, read delta (read()) and map button action - for (unsigned char i=0; i<_encoders.size(); i++) { - - encoder_t encoder = _encoders[i]; + for (auto& encoder : _encoders) { - long delta = encoder.encoder->read(); + const auto delta = encoder.encoder->read(); encoder.encoder->write(0); if ((0 == delta) || (_encoder_min_delta > abs(delta))) continue; diff --git a/code/espurna/light.h b/code/espurna/light.h index 464a791dde..68f5bb4a7b 100644 --- a/code/espurna/light.h +++ b/code/espurna/light.h @@ -1,26 +1,48 @@ // ----------------------------------------------------------------------------- -// Light +// Lights // ----------------------------------------------------------------------------- #pragma once namespace Light { - constexpr const unsigned char VALUE_MIN = LIGHT_MIN_VALUE; - constexpr const unsigned char VALUE_MAX = LIGHT_MAX_VALUE; + constexpr const long VALUE_MIN = LIGHT_MIN_VALUE; + constexpr const long VALUE_MAX = LIGHT_MAX_VALUE; - constexpr const unsigned int BRIGHTNESS_MIN = LIGHT_MIN_BRIGHTNESS; - constexpr const unsigned int BRIGHTNESS_MAX = LIGHT_MAX_BRIGHTNESS; + constexpr const long BRIGHTNESS_MIN = LIGHT_MIN_BRIGHTNESS; + constexpr const long BRIGHTNESS_MAX = LIGHT_MAX_BRIGHTNESS; // Default to the Philips Hue value that HA also use. // https://developers.meethue.com/documentation/core-concepts - constexpr const unsigned int MIREDS_COLDWHITE = LIGHT_COLDWHITE_MIRED; - constexpr const unsigned int MIREDS_WARMWHITE = LIGHT_WARMWHITE_MIRED; + constexpr const long MIREDS_COLDWHITE = LIGHT_COLDWHITE_MIRED; + constexpr const long MIREDS_WARMWHITE = LIGHT_WARMWHITE_MIRED; - constexpr const unsigned int KELVIN_WARMWHITE = LIGHT_WARMWHITE_KELVIN; - constexpr const unsigned int KELVIN_COLDWHITE = LIGHT_COLDWHITE_KELVIN; + constexpr const long KELVIN_WARMWHITE = LIGHT_WARMWHITE_KELVIN; + constexpr const long KELVIN_COLDWHITE = LIGHT_COLDWHITE_KELVIN; - constexpr const unsigned int PWM_MIN = LIGHT_MIN_PWM; - constexpr const unsigned int PWM_MAX = LIGHT_MAX_PWM; - constexpr const unsigned int PWM_LIMIT = LIGHT_LIMIT_PWM; + constexpr const long PWM_MIN = LIGHT_MIN_PWM; + constexpr const long PWM_MAX = LIGHT_MAX_PWM; + constexpr const long PWM_LIMIT = LIGHT_LIMIT_PWM; + + enum Communications : unsigned char { + COMMS_NONE = 0, + COMMS_NORMAL = 1 << 0, + COMMS_GROUP = 1 << 1 + }; } +size_t lightChannels(); + +void lightState(unsigned char i, bool state); +bool lightState(unsigned char i); + +void lightState(bool state); +bool lightState(); + +void lightBrightness(long brightness); +long lightBrightness(); + +long lightChannel(unsigned char id); +void lightChannel(unsigned char id, long value); + +void lightBrightnessStep(long steps, long multiplier = LIGHT_STEP); +void lightChannelStep(unsigned char id, long steps, long multiplier = LIGHT_STEP); diff --git a/code/espurna/light.ino b/code/espurna/light.ino index 037d0077aa..f3d7b73c0a 100644 --- a/code/espurna/light.ino +++ b/code/espurna/light.ino @@ -127,7 +127,7 @@ void _setCCTInputValue(unsigned char warm, unsigned char cold) { _setInputValue(1, constrain(cold, Light::VALUE_MIN, Light::VALUE_MAX)); } -void _lightApplyBrightness(unsigned char channels = lightChannels()) { +void _lightApplyBrightness(size_t channels = lightChannels()) { double brightness = static_cast(_light_brightness) / static_cast(Light::BRIGHTNESS_MAX); @@ -196,7 +196,7 @@ void _lightApplyBrightnessColor() { } String lightDesc(unsigned char id) { - if (id >= _light_channel.size()) return F("UNKNOWN"); + if (id >= _light_channel.size()) return FPSTR(pstr_unknown); const char tag = pgm_read_byte(&_light_channel_desc[_light_channel.size() - 1][id]); switch (tag) { @@ -208,7 +208,7 @@ String lightDesc(unsigned char id) { default: break; } - return F("UNKNOWN"); + return FPSTR(pstr_unknown); } // ----------------------------------------------------------------------------- @@ -218,53 +218,39 @@ String lightDesc(unsigned char id) { void _fromLong(unsigned long value, bool brightness) { if (brightness) { _setRGBInputValue((value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF); - _light_brightness = (value & 0xFF) * Light::BRIGHTNESS_MAX / 255; + lightBrightness((value & 0xFF) * Light::BRIGHTNESS_MAX / 255); } else { _setRGBInputValue((value >> 16) & 0xFF, (value >> 8) & 0xFF, (value) & 0xFF); } } void _fromRGB(const char * rgb) { - char * p = (char *) rgb; - if (strlen(p) == 0) return; + // 9 char #........ , 11 char ...,...,... + if (!_light_has_color) return; + if (!rgb || (strlen(rgb) == 0)) return; - switch (p[0]) { - case '#': // HEX Value - if (_light_has_color) { - ++p; - unsigned long value = strtoul(p, NULL, 16); - // RGBA values are interpreted like RGB + brightness - _fromLong(value, strlen(p) > 7); - } - break; - case 'M': // Mired Value - _fromMireds(atol(p + 1)); - break; - case 'K': // Kelvin Value - _fromKelvin(atol(p + 1)); - break; - default: // assume decimal values separated by commas - char * tok; + // HEX value is always prefixed, like CSS + // values are interpreted like RGB + optional brightness + if (rgb[0] == '#') { + _fromLong(strtoul(rgb + 1, nullptr, 16), strlen(rgb + 1) > 7); + // With comma separated string, assume decimal values + } else { + const auto channels = _light_channel.size(); unsigned char count = 0; - unsigned char channels = _light_channel.size(); - tok = strtok(p, ","); + char buf[16] = {0}; + strncpy(buf, rgb, sizeof(buf) - 1); + char *tok = strtok(buf, ","); while (tok != NULL) { _setInputValue(count, atoi(tok)); if (++count == channels) break; tok = strtok(NULL, ","); } - // RGB but less than 3 values received, assume it is 0 - if (_light_has_color && (count < 3)) { - // check channel 1 and 2: - for (int i = 1; i <= 2; i++) { - if (count < (i+1)) { - _setInputValue(i, 0); - } - } - } - break; + // If less than 3 values received, set the rest to 0 + if (count < 2) _setInputValue(1, 0); + if (count < 3) _setInputValue(2, 0); + return; } } @@ -273,16 +259,16 @@ void _fromRGB(const char * rgb) { // 0 <= S <= 100 // 0 <= V <= 100 void _fromHSV(const char * hsv) { - - char * ptr = (char *) hsv; - if (strlen(ptr) == 0) return; if (!_light_has_color) return; + if (strlen(hsv) == 0) return; + + char buf[16] = {0}; + strncpy(buf, hsv, sizeof(buf) - 1); - char * tok; unsigned char count = 0; unsigned int value[3] = {0}; - tok = strtok(ptr, ","); + char * tok = strtok(buf, ","); while (tok != NULL) { value[count] = atoi(tok); if (++count == 3) break; @@ -296,14 +282,14 @@ void _fromHSV(const char * hsv) { //IS: [145,0,0] //SHOULD: [255,0,0] - double h = (value[0] == 360) ? 0 : (double) value[0] / 60.0; - double f = (h - floor(h)); - double s = (double) value[1] / 100.0; + const double h = (value[0] == 360) ? 0 : (double) value[0] / 60.0; + const double f = (h - floor(h)); + const double s = (double) value[1] / 100.0; _light_brightness = lround((double) value[2] * (static_cast(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))); + const unsigned char p = lround(Light::VALUE_MAX * (1.0 - s)); + const unsigned char q = lround(Light::VALUE_MAX * (1.0 - s * f)); + const unsigned char t = lround(Light::VALUE_MAX * (1.0 - s * (1.0 - f))); switch (int(h)) { case 0: @@ -332,25 +318,39 @@ void _fromHSV(const char * hsv) { // Thanks to Sacha Telgenhof for sharing this code in his AiLight library // https://github.com/stelgenhof/AiLight -void _fromKelvin(unsigned long kelvin) { +// Color temperature is measured in mireds (kelvin = 1e6/mired) +long _toKelvin(const long mireds) { + return constrain(static_cast(1000000L / mireds), Light::KELVIN_WARMWHITE, Light::KELVIN_COLDWHITE); +} - if (!_light_has_color) { +long _toMireds(const long kelvin) { + return constrain(static_cast(lround(1000000L / kelvin)), Light::MIREDS_COLDWHITE, Light::MIREDS_WARMWHITE); +} - if(!_light_use_cct) return; +void _lightMireds(const long kelvin) { + _light_mireds = _toMireds(kelvin); +} - _light_mireds = constrain(static_cast(lround(1000000UL / kelvin)), Light::MIREDS_COLDWHITE, Light::MIREDS_WARMWHITE); +void _lightMiredsCCT(const long kelvin) { + _lightMireds(kelvin); - // 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::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); + // This change the range from 153-500 to 0-347 so we get a value between 0 and 1 in the end. + const double factor = ((double) _light_mireds - (double) Light::MIREDS_COLDWHITE)/((double) Light::MIREDS_WARMWHITE - (double) Light::MIREDS_COLDWHITE); + _setCCTInputValue( + lround(factor * Light::VALUE_MAX), + lround(((double) 1.0 - factor) * Light::VALUE_MAX) + ); +} - _setCCTInputValue(warm, cold); +void _fromKelvin(long kelvin) { - return; + if (!_light_has_color) { + if (!_light_use_cct) return; + _lightMiredsCCT(kelvin); + return; } - _light_mireds = constrain(static_cast(lround(1000000UL / kelvin)), Light::MIREDS_COLDWHITE, Light::MIREDS_WARMWHITE); + _lightMireds(kelvin); if (_light_use_cct) { _setRGBInputValue(Light::VALUE_MAX, Light::VALUE_MAX, Light::VALUE_MAX); @@ -359,13 +359,13 @@ void _fromKelvin(unsigned long kelvin) { // Calculate colors kelvin /= 100; - unsigned int red = (kelvin <= 66) + const unsigned int red = (kelvin <= 66) ? Light::VALUE_MAX : 329.698727446 * fs_pow((double) (kelvin - 60), -0.1332047592); - unsigned int green = (kelvin <= 66) + const unsigned int green = (kelvin <= 66) ? 99.4708025861 * fs_log(kelvin) - 161.1195681661 : 288.1221695283 * fs_pow((double) kelvin, -0.0755148492); - unsigned int blue = (kelvin >= 66) + const unsigned int blue = (kelvin >= 66) ? Light::VALUE_MAX : ((kelvin <= 19) ? 0 @@ -375,10 +375,8 @@ 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(1000000UL / mireds), Light::KELVIN_WARMWHITE, Light::KELVIN_COLDWHITE); - _fromKelvin(kelvin); +void _fromMireds(const long mireds) { + _fromKelvin(_toKelvin(mireds)); } // ----------------------------------------------------------------------------- @@ -455,19 +453,18 @@ 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]; - float b = applyBrightness ? (float) _light_brightness / Light::BRIGHTNESS_MAX : 1; - for (unsigned char i=0; i<_light_channel.size(); i++) { - itoa((target ? _light_channel[i].target : _light_channel[i].inputValue) * b, num, 10); - if (i>0) strncat(buffer, ",", len--); - strncat(buffer, num, len); - len = len - strlen(num); +String _toCSV(bool target) { + const auto channels = lightChannels(); + + String result; + result.reserve(4 * channels); + + for (auto& channel : _light_channel) { + if (result.length()) result += ','; + result += String(target ? channel.target : channel.inputValue); } -} -void _toCSV(char * buffer, size_t len, bool applyBrightness) { - _toCSV(buffer, len, applyBrightness, false); + return result; } // See cores/esp8266/WMath.cpp::map @@ -480,6 +477,35 @@ template T _lightMap(T x, Tin in_min, return (x - in_min) * (out_max - out_min) / divisor + out_min; } +int _lightAdjustValue(const int& value, const String& operation) { + if (!operation.length()) return value; + + // if prefixed with a sign, treat expression as numerical operation + // otherwise, use as the new value + int updated = operation.toInt(); + if (operation[0] == '+' || operation[0] == '-') { + updated = value + updated; + } + + return updated; +} + +void _lightAdjustBrightness(const char *payload) { + lightBrightness(_lightAdjustValue(lightBrightness(), payload)); +} + +void _lightAdjustChannel(unsigned char id, const char *payload) { + lightChannel(id, _lightAdjustValue(lightChannel(id), payload)); +} + +void _lightAdjustKelvin(const char *payload) { + _fromKelvin(_lightAdjustValue(_toKelvin(_light_mireds), payload)); +} + +void _lightAdjustMireds(const char *payload) { + _fromMireds(_lightAdjustValue(_light_mireds, payload)); +} + // ----------------------------------------------------------------------------- // PROVIDER // ----------------------------------------------------------------------------- @@ -646,7 +672,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl if (type == MQTT_MESSAGE_EVENT) { // Group color - if ((mqtt_group_color.length() > 0) & (mqtt_group_color.equals(topic))) { + if ((mqtt_group_color.length() > 0) && (mqtt_group_color.equals(topic))) { lightColor(payload, true); lightUpdate(true, mqttForward(), false); return; @@ -657,14 +683,14 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl // Color temperature in mireds if (t.equals(MQTT_TOPIC_MIRED)) { - _fromMireds(atol(payload)); + _lightAdjustMireds(payload); lightUpdate(true, mqttForward()); return; } // Color temperature in kelvins if (t.equals(MQTT_TOPIC_KELVIN)) { - _fromKelvin(atol(payload)); + _lightAdjustKelvin(payload); lightUpdate(true, mqttForward()); return; } @@ -683,7 +709,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl // Brightness if (t.equals(MQTT_TOPIC_BRIGHTNESS)) { - lightBrightness(atoi(payload)); + _lightAdjustBrightness(payload); lightUpdate(true, mqttForward()); return; } @@ -701,7 +727,7 @@ void _lightMQTTCallback(unsigned int type, const char * topic, const char * payl DEBUG_MSG_P(PSTR("[LIGHT] Wrong channelID (%d)\n"), channelID); return; } - lightChannel(channelID, atoi(payload)); + _lightAdjustChannel(channelID, payload); lightUpdate(true, mqttForward()); return; } @@ -750,11 +776,9 @@ void lightMQTT() { } void lightMQTTGroup() { - String mqtt_group_color = getSetting("mqttGroupColor"); - if (mqtt_group_color.length()>0) { - char buffer[20]; - _toCSV(buffer, sizeof(buffer), true); - mqttSendRaw(mqtt_group_color.c_str(), buffer); + const String mqtt_group_color = getSetting("mqttGroupColor"); + if (mqtt_group_color.length()) { + mqttSendRaw(mqtt_group_color.c_str(), _toCSV(false).c_str()); } } @@ -780,7 +804,7 @@ void lightBroker() { // API // ----------------------------------------------------------------------------- -unsigned char lightChannels() { +size_t lightChannels() { return _light_channel.size(); } @@ -792,12 +816,12 @@ bool lightUseCCT() { return _light_use_cct; } -void _lightComms(unsigned char mask) { +void _lightComms(const unsigned char mask) { - // Report color & brightness to MQTT broker + // Report color and brightness to MQTT broker #if MQTT_SUPPORT - if (mask & 0x01) lightMQTT(); - if (mask & 0x02) lightMQTTGroup(); + if (mask & Light::COMMS_NORMAL) lightMQTT(); + if (mask & Light::COMMS_GROUP) lightMQTTGroup(); #endif // Report color to WS clients (using current brightness setting) @@ -829,13 +853,13 @@ void lightUpdate(bool save, bool forward, bool group_forward) { // Channel transition will be handled by the provider function // User can configure total transition time, step time is a fixed value - unsigned long steps = _light_use_transitions ? _light_transition_time / LIGHT_TRANSITION_STEP : 1; + const unsigned long steps = _light_use_transitions ? _light_transition_time / LIGHT_TRANSITION_STEP : 1; _light_transition_ticker.once_ms(LIGHT_TRANSITION_STEP, _lightProviderScheduleUpdate, steps); // Delay every communication 100ms to avoid jamming - unsigned char mask = 0; - if (forward) mask += 1; - if (group_forward) mask += 2; + const unsigned char mask = + ((forward) ? Light::COMMS_NORMAL : Light::COMMS_NONE) | + ((group_forward) ? Light::COMMS_GROUP : Light::COMMS_NONE); _light_comms_ticker.once_ms(LIGHT_COMMS_DELAY, _lightComms, mask); _lightSaveRtcmem(); @@ -910,33 +934,32 @@ String lightColor() { return lightColor(true); } -unsigned int lightChannel(unsigned char id) { +long lightChannel(unsigned char id) { if (id <= _light_channel.size()) { return _light_channel[id].inputValue; } return 0; } -void lightChannel(unsigned char id, unsigned char value) { - if (id <= _light_channel.size()) { - _setInputValue(id, constrain(value, Light::VALUE_MIN, Light::VALUE_MAX)); - } +void lightChannel(unsigned char id, long value) { + if (id > _light_channel.size()) return; + _setInputValue(id, constrain(value, Light::VALUE_MIN, Light::VALUE_MAX)); } -void lightChannelStep(unsigned char id, int steps) { - lightChannel(id, lightChannel(id) + steps * LIGHT_STEP); +void lightChannelStep(unsigned char id, long steps, long multiplier) { + lightChannel(id, static_cast(lightChannel(id)) + (steps * multiplier)); } -unsigned int lightBrightness() { +long lightBrightness() { return _light_brightness; } -void lightBrightness(unsigned int brightness) { +void lightBrightness(long brightness) { _light_brightness = constrain(brightness, Light::BRIGHTNESS_MIN, Light::BRIGHTNESS_MAX); } -void lightBrightnessStep(int steps) { - lightBrightness(_light_brightness + steps * LIGHT_STEP); +void lightBrightnessStep(long steps, long multiplier) { + lightBrightness(static_cast(_light_brightness) + (steps * multiplier)); } unsigned int lightTransitionTime() { @@ -1032,14 +1055,14 @@ void _lightWebSocketOnAction(uint32_t client_id, const char * action, JsonObject if (strcmp(action, "channel") == 0) { if (data.containsKey("id") && data.containsKey("value")) { - lightChannel(data["id"], data["value"]); + lightChannel(data["id"].as(), data["value"].as()); lightUpdate(true, true); } } if (strcmp(action, "brightness") == 0) { if (data.containsKey("value")) { - lightBrightness(data["value"]); + lightBrightness(data["value"].as()); lightUpdate(true, true); } } @@ -1081,7 +1104,7 @@ void _lightAPISetup() { apiRegister(MQTT_TOPIC_KELVIN, [](char * buffer, size_t len) {}, [](const char * payload) { - _fromKelvin(atol(payload)); + _lightAdjustKelvin(payload); lightUpdate(true, true); } ); @@ -1089,7 +1112,7 @@ void _lightAPISetup() { apiRegister(MQTT_TOPIC_MIRED, [](char * buffer, size_t len) {}, [](const char * payload) { - _fromMireds(atol(payload)); + _lightAdjustMireds(payload); lightUpdate(true, true); } ); @@ -1105,7 +1128,7 @@ void _lightAPISetup() { snprintf_P(buffer, len, PSTR("%d"), _light_channel[id].target); }, [id](const char * payload) { - lightChannel(id, atoi(payload)); + _lightAdjustChannel(id, payload); lightUpdate(true, true); } ); @@ -1126,7 +1149,7 @@ void _lightAPISetup() { snprintf_P(buffer, len, PSTR("%d"), _light_brightness); }, [](const char * payload) { - lightBrightness(atoi(payload)); + _lightAdjustBrightness(payload); lightUpdate(true, true); } ); @@ -1141,38 +1164,37 @@ void _lightInitCommands() { terminalRegisterCommand(F("BRIGHTNESS"), [](Embedis* e) { if (e->argc > 1) { - const String value(e->argv[1]); - if( value.length() > 0 ) { - if( value[0] == '+' || value[0] == '-' ) { - lightBrightness(lightBrightness()+String(e->argv[1]).toInt()); - } else { - lightBrightness(String(e->argv[1]).toInt()); - } - lightUpdate(true, true); - } + _lightAdjustBrightness(e->argv[1]); + lightUpdate(true, true); } - DEBUG_MSG_P(PSTR("Brightness: %d\n"), lightBrightness()); + DEBUG_MSG_P(PSTR("Brightness: %u\n"), lightBrightness()); terminalOK(); }); terminalRegisterCommand(F("CHANNEL"), [](Embedis* e) { if (e->argc < 2) { - terminalError(F("Wrong arguments")); + terminalError(F("CHANNEL []")); + return; } - int id = String(e->argv[1]).toInt(); + + const int id = String(e->argv[1]).toInt(); + if (id < 0 || id >= lightChannels()) { + terminalError(F("Channel value out of range")); + return; + } + if (e->argc > 2) { - int value = String(e->argv[2]).toInt(); - lightChannel(id, value); + _lightAdjustChannel(id, e->argv[2]); lightUpdate(true, true); } - DEBUG_MSG_P(PSTR("Channel #%d (%s): %d\n"), id, lightDesc(id).c_str(), lightChannel(id)); + + DEBUG_MSG_P(PSTR("Channel #%u (%s): %d\n"), id, lightDesc(id).c_str(), lightChannel(id)); terminalOK(); }); terminalRegisterCommand(F("COLOR"), [](Embedis* e) { if (e->argc > 1) { - String color = String(e->argv[1]); - lightColor(color.c_str()); + lightColor(e->argv[1]); lightUpdate(true, true); } DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); @@ -1181,8 +1203,7 @@ void _lightInitCommands() { terminalRegisterCommand(F("KELVIN"), [](Embedis* e) { if (e->argc > 1) { - String color = String("K") + String(e->argv[1]); - lightColor(color.c_str()); + _lightAdjustKelvin(e->argv[1]); lightUpdate(true, true); } DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); @@ -1191,17 +1212,8 @@ void _lightInitCommands() { terminalRegisterCommand(F("MIRED"), [](Embedis* e) { if (e->argc > 1) { - const String value(e->argv[1]); - String color = String("M"); - if( value.length() > 0 ) { - if( value[0] == '+' || value[0] == '-' ) { - color += String(_light_mireds + String(e->argv[1]).toInt()); - } else { - color += String(e->argv[1]); - } - lightColor(color.c_str()); - lightUpdate(true, true); - } + _lightAdjustMireds(e->argv[1]); + lightUpdate(true, true); } DEBUG_MSG_P(PSTR("Color: %s\n"), lightColor().c_str()); terminalOK();