From 18aaf056224421ee45c9ae6e14f5ac9f9ae5b05d Mon Sep 17 00:00:00 2001 From: arendst Date: Sun, 19 Feb 2017 17:49:17 +0100 Subject: [PATCH] v3.9.19 3.9.19 20170219 * Sonoff Led: Made GPIO04, 05 and 15 available for user * Sonoff Led: Add commands Fade, Speed, WakupDuration, Wakeup and LedTable --- README.md | 2 +- api/arduino/sonoff.ino.bin | Bin 467968 -> 468928 bytes sonoff/_releasenotes.ino | 6 +- sonoff/settings.h | 188 +++++++++++ sonoff/settings.ino | 632 +++++++++++++++++++++++++++++++++++ sonoff/sonoff.ino | 653 +------------------------------------ sonoff/sonoff_template.h | 6 +- sonoff/support.ino | 286 ---------------- sonoff/webserver.ino | 4 +- sonoff/xdrv_ir_send.ino | 4 +- sonoff/xdrv_snfled.ino | 278 ++++++++++++++++ sonoff/xdrv_ws2812.ino | 4 +- 12 files changed, 1128 insertions(+), 935 deletions(-) create mode 100644 sonoff/settings.h create mode 100644 sonoff/settings.ino create mode 100644 sonoff/xdrv_snfled.ino diff --git a/README.md b/README.md index 681caed8f..7fdfadb54 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **3.9.18** - See ```sonoff/_releasenotes.ino``` for change information. +Current version is **3.9.19** - See ```sonoff/_releasenotes.ino``` for change information. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index cbce9d36f81d9e6c57dcecfe338983963078a317..391f562b6a11035f35f7c367ed68cf6e548983b8 100644 GIT binary patch delta 82462 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 eAacsdHh$L5(2gX#65r9^0<^v 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℞U2U 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ò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 diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 99e30fbf8..23df798ff 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,8 @@ -/* 3.9.18 20170218 +/* 3.9.19 20170219 + * Sonoff Led: Made GPIO04, 05 and 15 available for user + * Sonoff Led: Add commands Fade, Speed, WakupDuration, Wakeup and LedTable + * + * 3.9.18 20170218 * Fix ledstate 0 to turn off led * Fix Sonoff Led dimmer range (#16) * Change Sonoff Led command Dimmer to act on both cold and warm color diff --git a/sonoff/settings.h b/sonoff/settings.h new file mode 100644 index 000000000..049cb3410 --- /dev/null +++ b/sonoff/settings.h @@ -0,0 +1,188 @@ +/*********************************************************************************************\ + * Config settings +\*********************************************************************************************/ + +struct SYSCFG2 { // Version 2.x (old) + unsigned long cfg_holder; + unsigned long saveFlag; + unsigned long version; + byte seriallog_level; + byte syslog_level; + char syslog_host[32]; + char sta_ssid1[32]; + char sta_pwd1[64]; + char otaUrl[80]; + char mqtt_host[32]; + char mqtt_grptopic[32]; + char mqtt_topic[32]; + char mqtt_topic2[32]; + char mqtt_subtopic[32]; + int8_t timezone; + uint8_t power; + uint8_t ledstate; + uint16_t mqtt_port; + char mqtt_client[33]; + char mqtt_user[33]; + char mqtt_pwd[33]; + uint8_t webserver; + unsigned long bootcount; + char hostname[33]; + uint16_t syslog_port; + byte weblog_level; + uint16_t tele_period; + uint8_t sta_config; + int16_t savedata; + byte model; + byte mqtt_retain; + byte savestate; + unsigned long hlw_pcal; + unsigned long hlw_ucal; + unsigned long hlw_ical; + unsigned long hlw_kWhyesterday; + byte value_units; + uint16_t hlw_pmin; + uint16_t hlw_pmax; + uint16_t hlw_umin; + uint16_t hlw_umax; + uint16_t hlw_imin; + uint16_t hlw_imax; + uint16_t hlw_mpl; // MaxPowerLimit + uint16_t hlw_mplh; // MaxPowerLimitHold + uint16_t hlw_mplw; // MaxPowerLimitWindow + uint16_t hlw_mspl; // MaxSafePowerLimit + uint16_t hlw_msplh; // MaxSafePowerLimitHold + uint16_t hlw_msplw; // MaxSafePowerLimitWindow + uint16_t hlw_mkwh; // MaxEnergy + uint16_t hlw_mkwhs; // MaxEnergyStart + char domoticz_in_topic[33]; + char domoticz_out_topic[33]; + uint16_t domoticz_update_timer; + unsigned long domoticz_relay_idx[4]; + unsigned long domoticz_key_idx[4]; + byte message_format; // Not used since 3.2.6a + unsigned long hlw_kWhtoday; + uint16_t hlw_kWhdoy; + uint8_t switchmode; + char mqtt_fingerprint[60]; + byte sta_active; + char sta_ssid2[33]; + char sta_pwd2[65]; + +} sysCfg2; + +struct SYSCFG { + unsigned long cfg_holder; + unsigned long saveFlag; + unsigned long version; + unsigned long bootcount; + byte migflg; + int16_t savedata; + byte savestate; + byte model; + int8_t timezone; + char otaUrl[101]; + char ex_friendlyname[33]; // Not used since 3.2.5 - see below + + byte serial_enable; + byte seriallog_level; + uint8_t sta_config; + byte sta_active; + char sta_ssid[2][33]; + char sta_pwd[2][65]; + char hostname[33]; + char syslog_host[33]; + uint16_t syslog_port; + byte syslog_level; + uint8_t webserver; + byte weblog_level; + + char mqtt_fingerprint[60]; + char mqtt_host[33]; + uint16_t mqtt_port; + char mqtt_client[33]; + char mqtt_user[33]; + char mqtt_pwd[33]; + char mqtt_topic[33]; + char button_topic[33]; + char mqtt_grptopic[33]; + char mqtt_subtopic[33]; + byte mqtt_button_retain; + byte mqtt_power_retain; + byte value_units; + byte message_format; // Not used since 3.2.6a + uint16_t tele_period; + + uint8_t power; + uint8_t ledstate; + uint8_t switchmode; + + char domoticz_in_topic[33]; + char domoticz_out_topic[33]; + uint16_t domoticz_update_timer; + unsigned long domoticz_relay_idx[4]; + unsigned long domoticz_key_idx[4]; + + unsigned long hlw_pcal; + unsigned long hlw_ucal; + unsigned long hlw_ical; + unsigned long hlw_kWhtoday; + unsigned long hlw_kWhyesterday; + uint16_t hlw_kWhdoy; + uint16_t hlw_pmin; + uint16_t hlw_pmax; + uint16_t hlw_umin; + uint16_t hlw_umax; + uint16_t hlw_imin; + uint16_t hlw_imax; + uint16_t hlw_mpl; // MaxPowerLimit + uint16_t hlw_mplh; // MaxPowerLimitHold + uint16_t hlw_mplw; // MaxPowerLimitWindow + uint16_t hlw_mspl; // MaxSafePowerLimit + uint16_t hlw_msplh; // MaxSafePowerLimitHold + uint16_t hlw_msplw; // MaxSafePowerLimitWindow + uint16_t hlw_mkwh; // MaxEnergy + uint16_t hlw_mkwhs; // MaxEnergyStart + + uint16_t pulsetime; + uint8_t poweronstate; + uint16_t blinktime; + uint16_t blinkcount; + + uint16_t ws_pixels; + uint8_t ws_red; + uint8_t ws_green; + uint8_t ws_blue; + uint8_t ws_ledtable; + uint8_t ws_dimmer; + uint8_t ws_fade; + uint8_t ws_speed; + uint8_t ws_scheme; + uint8_t ws_width; + uint16_t ws_wakeup; + + char friendlyname[4][33]; + char switch_topic[33]; + byte mqtt_switch_retain; + uint8_t mqtt_enabled; + uint8_t sleep; + + uint16_t domoticz_switch_idx[4]; + uint16_t domoticz_sensor_idx[12]; + + uint8_t module; + mytmplt my_module; + + uint16_t led_pixels; + uint8_t led_color[5]; + uint8_t led_table; + uint8_t led_dimmer[3]; + uint8_t led_fade; + uint8_t led_speed; + uint8_t led_scheme; + uint8_t led_width; + uint16_t led_wakeup; + + uint8_t emulation; + +} sysCfg; + diff --git a/sonoff/settings.ino b/sonoff/settings.ino new file mode 100644 index 000000000..61f8f4e65 --- /dev/null +++ b/sonoff/settings.ino @@ -0,0 +1,632 @@ +/* +Copyright (c) 2017 Theo Arends. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/*********************************************************************************************\ + * Config - Flash or Spiffs +\*********************************************************************************************/ + +extern "C" { +#include "spi_flash.h" +} +#include "eboot_command.h" + +#define SPIFFS_START ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE +#define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE + +// Version 2.x config +#define SPIFFS_CONFIG2 "/config.ini" +#define CFG_LOCATION2 SPIFFS_END - 2 + +// Version 3.x config +#define SPIFFS_CONFIG "/cfg.ini" +#define CFG_LOCATION SPIFFS_END - 4 + +uint32_t _cfgHash = 0; +int spiffsflag = 0; + +/********************************************************************************************/ +/* + * Based on cores/esp8266/Updater.cpp + */ +void setFlashChipMode(byte option, byte mode) +{ + char log[LOGSZ]; + uint8_t *_buffer; + uint32_t address; + + if (option) { + eboot_command ebcmd; + eboot_command_read(&ebcmd); + address = ebcmd.args[0]; + } else { + address = 0; + } + _buffer = new uint8_t[FLASH_SECTOR_SIZE]; + if (spi_flash_read(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { + if (_buffer[2] != mode) { + _buffer[2] = mode &3; + noInterrupts(); + if (spi_flash_erase_sector(address / FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { + spi_flash_write(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); + } + interrupts(); + snprintf_P(log, sizeof(log), PSTR("FLSH: Updated Flash Chip Mode to %d"), (option) ? mode : ESP.getFlashChipMode()); + addLog(LOG_LEVEL_DEBUG, log); + } + } + delete[] _buffer; +} + +boolean spiffsPresent() +{ + return (SPIFFS_END - SPIFFS_START); +} + +uint32_t getHash() +{ + uint32_t hash = 0; + uint8_t *bytes = (uint8_t*)&sysCfg; + + for (uint16_t i = 0; i < sizeof(SYSCFG); i++) hash += bytes[i]*(i+1); + return hash; +} + +/*********************************************************************************************\ + * Config Save - Save parameters to Flash or Spiffs ONLY if any parameter has changed +\*********************************************************************************************/ + +void CFG_Save() +{ + char log[LOGSZ]; + + if ((getHash() != _cfgHash) && (spiffsPresent())) { + if (!spiffsflag) { +#ifdef USE_SPIFFS + sysCfg.saveFlag++; + File f = SPIFFS.open(SPIFFS_CONFIG, "r+"); + if (f) { + uint8_t *bytes = (uint8_t*)&sysCfg; + for (int i = 0; i < sizeof(SYSCFG); i++) f.write(bytes[i]); + f.close(); + snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to spiffs count %d"), sizeof(SYSCFG), sysCfg.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } else { + addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Saving configuration failed")); + } + } else { +#endif // USE_SPIFFS + if (sysCfg.module != SONOFF_LED) noInterrupts(); + if (sysCfg.saveFlag == 0) { // Handle default and rollover + spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); + spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + } + sysCfg.saveFlag++; + spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); + spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + if (sysCfg.module != SONOFF_LED) interrupts(); + snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to flash at %X and count %d"), sizeof(SYSCFG), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } + _cfgHash = getHash(); + } +} + +void CFG_Load() +{ + char log[LOGSZ]; + + if (spiffsPresent()) { + if (!spiffsflag) { +#ifdef USE_SPIFFS + File f = SPIFFS.open(SPIFFS_CONFIG, "r+"); + if (f) { + uint8_t *bytes = (uint8_t*)&sysCfg; + for (int i = 0; i < sizeof(SYSCFG); i++) bytes[i] = f.read(); + f.close(); + snprintf_P(log, sizeof(log), PSTR("Config: Loaded configuration from spiffs count %d"), sysCfg.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } else { + addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading configuration failed")); + } + } else { +#endif // USE_SPIFFS + struct SYSCFGH { + unsigned long cfg_holder; + unsigned long saveFlag; + } _sysCfgH; + + noInterrupts(); + spi_flash_read((CFG_LOCATION) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); + if (sysCfg.saveFlag < _sysCfgH.saveFlag) + spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); + interrupts(); + snprintf_P(log, sizeof(log), PSTR("Config: Loaded configuration from flash at %X and count %d"), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } + } +// snprintf_P(log, sizeof(log), PSTR("Config: Check 1 for migration (%08X)"), sysCfg.version); +// addLog(LOG_LEVEL_NONE, log); + if (sysCfg.cfg_holder != CFG_HOLDER) { + if ((sysCfg.version < 0x03000000) || (sysCfg.version > 0x73000000)) { + CFG_Migrate(); // Config may be present with versions below 3.0.0 + } else { + CFG_Default(); + } + } + _cfgHash = getHash(); +} + +void CFG_Migrate() +{ + char log[LOGSZ]; + + if (spiffsPresent()) { + if (!spiffsflag) { +#ifdef USE_SPIFFS + File f = SPIFFS.open(SPIFFS_CONFIG2, "r+"); + if (f) { + uint8_t *bytes = (uint8_t*)&sysCfg2; + for (int i = 0; i < sizeof(SYSCFG2); i++) bytes[i] = f.read(); + f.close(); + snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from spiffs count %d"), sysCfg2.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } else { + addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading previous configuration failed")); + } + } else { +#endif // USE_SPIFFS + struct SYSCFGH { + unsigned long cfg_holder; + unsigned long saveFlag; + } _sysCfgH; + + noInterrupts(); + spi_flash_read((CFG_LOCATION2) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2)); + spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); + if (sysCfg2.saveFlag < _sysCfgH.saveFlag) + spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2)); + interrupts(); + snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from flash at %X and count %d"), CFG_LOCATION2 + (sysCfg2.saveFlag &1), sysCfg2.saveFlag); + addLog(LOG_LEVEL_DEBUG, log); + } + } +// snprintf_P(log, sizeof(log), PSTR("Config: Check 2 for migration (%08X)"), sysCfg2.version); +// addLog(LOG_LEVEL_NONE, log); + if ((sysCfg2.version > 0x01000000) && (sysCfg2.version < 0x03000000)) { + CFG_Migrate_Part2(); // Config is present between version 1.0.0 and 3.0.0 + } else { + CFG_Default(); + } + _cfgHash = getHash(); +} + +void CFG_Erase() +{ + char log[LOGSZ]; + SpiFlashOpResult result; + + uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1; + uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; + boolean _serialoutput = (LOG_LEVEL_DEBUG_MORE <= seriallog_level); + + snprintf_P(log, sizeof(log), PSTR("Config: Erasing %d flash sectors"), _sectorEnd - _sectorStart); + addLog(LOG_LEVEL_DEBUG, log); + + for (uint32_t _sector = _sectorStart; _sector < _sectorEnd; _sector++) { + noInterrupts(); + result = spi_flash_erase_sector(_sector); + interrupts(); + if (_serialoutput) { + Serial.print(F("Flash: Erased sector ")); + Serial.print(_sector); + if (result == SPI_FLASH_RESULT_OK) { + Serial.println(F(" OK")); + } else { + Serial.println(F(" Error")); + } + delay(10); + } + } +} + +void CFG_Dump() +{ + #define CFG_COLS 16 + + char log[LOGSZ]; + uint16_t idx, maxrow, row, col; + + uint8_t *buffer = (uint8_t *) &sysCfg; + maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); + + for (row = 0; row < maxrow; row++) { + idx = row * CFG_COLS; + snprintf_P(log, sizeof(log), PSTR("%04X:"), idx); + for (col = 0; col < CFG_COLS; col++) { + if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + snprintf_P(log, sizeof(log), PSTR("%s %02X"), log, buffer[idx + col]); + } + snprintf_P(log, sizeof(log), PSTR("%s |"), log); + for (col = 0; col < CFG_COLS; col++) { +// if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + snprintf_P(log, sizeof(log), PSTR("%s%c"), log, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); + } + snprintf_P(log, sizeof(log), PSTR("%s|"), log); + addLog(LOG_LEVEL_INFO, log); + } +} + +#ifdef USE_SPIFFS +void initSpiffs() +{ + spiffsflag = 0; + if (!spiffsPresent()) { + spiffsflag = 1; + } else { + if (!SPIFFS.begin()) { + addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to mount file system. Will use flash")); + spiffsflag = 2; + } else { + addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Mount successful")); + File f = SPIFFS.open(SPIFFS_CONFIG, "r"); + if (!f) { + addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatting...")); + SPIFFS.format(); + addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatted")); + File f = SPIFFS.open(SPIFFS_CONFIG, "w"); + if (f) { + for (int i = 0; i < sizeof(SYSCFG); i++) f.write(0); + f.close(); + } else { + addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to init config file. Will use flash")); + spiffsflag = 3; + } + } + } + } +} +#endif // USE_SPIFFS + +/********************************************************************************************/ + +void CFG_DefaultSet1() +{ + memset(&sysCfg, 0x00, sizeof(SYSCFG)); + + sysCfg.cfg_holder = CFG_HOLDER; + sysCfg.saveFlag = 0; + sysCfg.version = VERSION; + sysCfg.bootcount = 0; +} + +void CFG_DefaultSet2() +{ + sysCfg.migflg = 0xA5; + sysCfg.savedata = SAVE_DATA; + sysCfg.savestate = SAVE_STATE; + sysCfg.module = MODULE; + sysCfg.model = 0; + sysCfg.timezone = APP_TIMEZONE; + strlcpy(sysCfg.otaUrl, OTA_URL, sizeof(sysCfg.otaUrl)); + strlcpy(sysCfg.ex_friendlyname, FRIENDLY_NAME, sizeof(sysCfg.ex_friendlyname)); + + sysCfg.seriallog_level = SERIAL_LOG_LEVEL; + sysCfg.sta_active = 0; + strlcpy(sysCfg.sta_ssid[0], STA_SSID1, sizeof(sysCfg.sta_ssid[0])); + strlcpy(sysCfg.sta_pwd[0], STA_PASS1, sizeof(sysCfg.sta_pwd[0])); + strlcpy(sysCfg.sta_ssid[1], STA_SSID2, sizeof(sysCfg.sta_ssid[1])); + strlcpy(sysCfg.sta_pwd[1], STA_PASS2, sizeof(sysCfg.sta_pwd[1])); + strlcpy(sysCfg.hostname, WIFI_HOSTNAME, sizeof(sysCfg.hostname)); + sysCfg.sta_config = WIFI_CONFIG_TOOL; + strlcpy(sysCfg.syslog_host, SYS_LOG_HOST, sizeof(sysCfg.syslog_host)); + sysCfg.syslog_port = SYS_LOG_PORT; + sysCfg.syslog_level = SYS_LOG_LEVEL; + sysCfg.webserver = WEB_SERVER; + sysCfg.weblog_level = WEB_LOG_LEVEL; + + strlcpy(sysCfg.mqtt_fingerprint, MQTT_FINGERPRINT, sizeof(sysCfg.mqtt_fingerprint)); + strlcpy(sysCfg.mqtt_host, MQTT_HOST, sizeof(sysCfg.mqtt_host)); + sysCfg.mqtt_port = MQTT_PORT; + strlcpy(sysCfg.mqtt_client, MQTT_CLIENT_ID, sizeof(sysCfg.mqtt_client)); + strlcpy(sysCfg.mqtt_user, MQTT_USER, sizeof(sysCfg.mqtt_user)); + strlcpy(sysCfg.mqtt_pwd, MQTT_PASS, sizeof(sysCfg.mqtt_pwd)); + strlcpy(sysCfg.mqtt_topic, MQTT_TOPIC, sizeof(sysCfg.mqtt_topic)); + strlcpy(sysCfg.button_topic, "0", sizeof(sysCfg.button_topic)); + strlcpy(sysCfg.mqtt_grptopic, MQTT_GRPTOPIC, sizeof(sysCfg.mqtt_grptopic)); + strlcpy(sysCfg.mqtt_subtopic, MQTT_SUBTOPIC, sizeof(sysCfg.mqtt_subtopic)); + sysCfg.mqtt_button_retain = MQTT_BUTTON_RETAIN; + sysCfg.mqtt_power_retain = MQTT_POWER_RETAIN; + sysCfg.value_units = VALUE_UNITS; + sysCfg.message_format = 0; + sysCfg.tele_period = TELE_PERIOD; + + sysCfg.power = APP_POWER; + sysCfg.poweronstate = APP_POWERON_STATE; + sysCfg.pulsetime = APP_PULSETIME; + sysCfg.ledstate = APP_LEDSTATE; + sysCfg.switchmode = SWITCH_MODE; + sysCfg.blinktime = APP_BLINKTIME; + sysCfg.blinkcount = APP_BLINKCOUNT; + sysCfg.sleep = APP_SLEEP; + + strlcpy(sysCfg.domoticz_in_topic, DOMOTICZ_IN_TOPIC, sizeof(sysCfg.domoticz_in_topic)); + strlcpy(sysCfg.domoticz_out_topic, DOMOTICZ_OUT_TOPIC, sizeof(sysCfg.domoticz_out_topic)); + sysCfg.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER; + for (byte i = 0; i < 4; i++) { + sysCfg.domoticz_relay_idx[i] = 0; + sysCfg.domoticz_key_idx[i] = 0; + sysCfg.domoticz_switch_idx[i] = 0; + } + for (byte i = 0; i < 12; i++) sysCfg.domoticz_sensor_idx[i] = 0; + + sysCfg.hlw_pcal = HLW_PREF_PULSE; + sysCfg.hlw_ucal = HLW_UREF_PULSE; + sysCfg.hlw_ical = HLW_IREF_PULSE; + sysCfg.hlw_kWhtoday = 0; + sysCfg.hlw_kWhyesterday = 0; + sysCfg.hlw_kWhdoy = 0; + sysCfg.hlw_pmin = 0; + sysCfg.hlw_pmax = 0; + sysCfg.hlw_umin = 0; + sysCfg.hlw_umax = 0; + sysCfg.hlw_imin = 0; + sysCfg.hlw_imax = 0; + sysCfg.hlw_mpl = 0; // MaxPowerLimit + sysCfg.hlw_mplh = MAX_POWER_HOLD; + sysCfg.hlw_mplw = MAX_POWER_WINDOW; + sysCfg.hlw_mspl = 0; // MaxSafePowerLimit + sysCfg.hlw_msplh = SAFE_POWER_HOLD; + sysCfg.hlw_msplw = SAFE_POWER_WINDOW; + sysCfg.hlw_mkwh = 0; // MaxEnergy + sysCfg.hlw_mkwhs = 0; // MaxEnergyStart + + sysCfg.ws_pixels = WS2812_LEDS; + sysCfg.ws_red = 255; + sysCfg.ws_green = 0; + sysCfg.ws_blue = 0; + sysCfg.ws_ledtable = 0; + sysCfg.ws_dimmer = 8; + sysCfg.ws_fade = 0; + sysCfg.ws_speed = 1; + sysCfg.ws_scheme = 0; + sysCfg.ws_width = 1; + sysCfg.ws_wakeup = 0; + + strlcpy(sysCfg.friendlyname[0], FRIENDLY_NAME, sizeof(sysCfg.friendlyname[0])); + strlcpy(sysCfg.friendlyname[1], FRIENDLY_NAME"2", sizeof(sysCfg.friendlyname[1])); + strlcpy(sysCfg.friendlyname[2], FRIENDLY_NAME"3", sizeof(sysCfg.friendlyname[2])); + strlcpy(sysCfg.friendlyname[3], FRIENDLY_NAME"4", sizeof(sysCfg.friendlyname[3])); + + for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + + sysCfg.led_pixels = 0; + for (byte i = 0; i < 5; i++) sysCfg.led_color[i] = 255; + sysCfg.led_table = 0; + for (byte i = 0; i < 3; i++) sysCfg.led_dimmer[i] = 10; + sysCfg.led_fade = 0; + sysCfg.led_speed = 0; + sysCfg.led_scheme = 0; + sysCfg.led_width = 0; + sysCfg.led_wakeup = 0; + + strlcpy(sysCfg.switch_topic, "0", sizeof(sysCfg.switch_topic)); + sysCfg.mqtt_switch_retain = MQTT_SWITCH_RETAIN; + sysCfg.mqtt_enabled = MQTT_USE; + + sysCfg.emulation = EMULATION; + +} + +void CFG_Default() +{ + addLog_P(LOG_LEVEL_NONE, PSTR("Config: Use default configuration")); + CFG_DefaultSet1(); + CFG_DefaultSet2(); + CFG_Save(); +} + +void CFG_Migrate_Part2() +{ + addLog_P(LOG_LEVEL_NONE, PSTR("Config: Migrating configuration")); + CFG_DefaultSet1(); + CFG_DefaultSet2(); + + sysCfg.seriallog_level = sysCfg2.seriallog_level; + sysCfg.syslog_level = sysCfg2.syslog_level; + strlcpy(sysCfg.syslog_host, sysCfg2.syslog_host, sizeof(sysCfg.syslog_host)); + strlcpy(sysCfg.sta_ssid[0], sysCfg2.sta_ssid1, sizeof(sysCfg.sta_ssid[0])); + strlcpy(sysCfg.sta_pwd[0], sysCfg2.sta_pwd1, sizeof(sysCfg.sta_pwd[0])); + strlcpy(sysCfg.otaUrl, sysCfg2.otaUrl, sizeof(sysCfg.otaUrl)); + strlcpy(sysCfg.mqtt_host, sysCfg2.mqtt_host, sizeof(sysCfg.mqtt_host)); + strlcpy(sysCfg.mqtt_grptopic, sysCfg2.mqtt_grptopic, sizeof(sysCfg.mqtt_grptopic)); + strlcpy(sysCfg.mqtt_topic, sysCfg2.mqtt_topic, sizeof(sysCfg.mqtt_topic)); + strlcpy(sysCfg.button_topic, sysCfg2.mqtt_topic2, sizeof(sysCfg.button_topic)); + strlcpy(sysCfg.mqtt_subtopic, sysCfg2.mqtt_subtopic, sizeof(sysCfg.mqtt_subtopic)); + sysCfg.timezone = sysCfg2.timezone; + sysCfg.power = sysCfg2.power; + if (sysCfg2.version >= 0x01000D00) { // 1.0.13 + sysCfg.ledstate = sysCfg2.ledstate; + } + if (sysCfg2.version >= 0x01001600) { // 1.0.22 + sysCfg.mqtt_port = sysCfg2.mqtt_port; + strlcpy(sysCfg.mqtt_client, sysCfg2.mqtt_client, sizeof(sysCfg.mqtt_client)); + strlcpy(sysCfg.mqtt_user, sysCfg2.mqtt_user, sizeof(sysCfg.mqtt_user)); + strlcpy(sysCfg.mqtt_pwd, sysCfg2.mqtt_pwd, sizeof(sysCfg.mqtt_pwd)); + strlcpy(sysCfg.ex_friendlyname, sysCfg2.mqtt_client, sizeof(sysCfg.ex_friendlyname)); + } + if (sysCfg2.version >= 0x01001700) { // 1.0.23 + sysCfg.webserver = sysCfg2.webserver; + } + if (sysCfg2.version >= 0x01001A00) { // 1.0.26 + sysCfg.bootcount = sysCfg2.bootcount; + strlcpy(sysCfg.hostname, sysCfg2.hostname, sizeof(sysCfg.hostname)); + sysCfg.syslog_port = sysCfg2.syslog_port; + } + if (sysCfg2.version >= 0x01001B00) { // 1.0.27 + sysCfg.weblog_level = sysCfg2.weblog_level; + } + if (sysCfg2.version >= 0x01001C00) { // 1.0.28 + sysCfg.tele_period = sysCfg2.tele_period; + if ((sysCfg.tele_period > 0) && (sysCfg.tele_period < 10)) sysCfg.tele_period = 10; // Do not allow periods < 10 seconds + } + if (sysCfg2.version >= 0x01002000) { // 1.0.32 + sysCfg.sta_config = sysCfg2.sta_config; + } + if (sysCfg2.version >= 0x01002300) { // 1.0.35 + sysCfg.savedata = sysCfg2.savedata; + } + if (sysCfg2.version >= 0x02000000) { // 2.0.0 + sysCfg.model = sysCfg2.model; + } + if (sysCfg2.version >= 0x02000300) { // 2.0.3 + sysCfg.mqtt_button_retain = sysCfg2.mqtt_retain; + sysCfg.savestate = sysCfg2.savestate; + } + if (sysCfg2.version >= 0x02000500) { // 2.0.5 + sysCfg.hlw_pcal = sysCfg2.hlw_pcal; + sysCfg.hlw_ucal = sysCfg2.hlw_ucal; + sysCfg.hlw_ical = sysCfg2.hlw_ical; + sysCfg.hlw_kWhyesterday = sysCfg2.hlw_kWhyesterday; + sysCfg.value_units = sysCfg2.value_units; + } + if (sysCfg2.version >= 0x02000600) { // 2.0.6 + sysCfg.hlw_pmin = sysCfg2.hlw_pmin; + sysCfg.hlw_pmax = sysCfg2.hlw_pmax; + sysCfg.hlw_umin = sysCfg2.hlw_umin; + sysCfg.hlw_umax = sysCfg2.hlw_umax; + sysCfg.hlw_imin = sysCfg2.hlw_imin; + sysCfg.hlw_imax = sysCfg2.hlw_imax; + } + if (sysCfg2.version >= 0x02000700) { // 2.0.7 + sysCfg.message_format = 0; + strlcpy(sysCfg.domoticz_in_topic, sysCfg2.domoticz_in_topic, sizeof(sysCfg.domoticz_in_topic)); + strlcpy(sysCfg.domoticz_out_topic, sysCfg2.domoticz_out_topic, sizeof(sysCfg.domoticz_out_topic)); + sysCfg.domoticz_update_timer = sysCfg2.domoticz_update_timer; + for (byte i = 0; i < 4; i++) { + sysCfg.domoticz_relay_idx[i] = sysCfg2.domoticz_relay_idx[i]; + sysCfg.domoticz_key_idx[i] = sysCfg2.domoticz_key_idx[i]; + } + + sysCfg.hlw_mpl = sysCfg2.hlw_mpl; // MaxPowerLimit + sysCfg.hlw_mplh = sysCfg2.hlw_mplh; + sysCfg.hlw_mplw = sysCfg2.hlw_mplw; + sysCfg.hlw_mspl = sysCfg2.hlw_mspl; // MaxSafePowerLimit + sysCfg.hlw_msplh = sysCfg2.hlw_msplh; + sysCfg.hlw_msplw = sysCfg2.hlw_msplw; + sysCfg.hlw_mkwh = sysCfg2.hlw_mkwh; // MaxEnergy + sysCfg.hlw_mkwhs = sysCfg2.hlw_mkwhs; // MaxEnergyStart + } + if (sysCfg2.version >= 0x02001000) { // 2.0.16 + sysCfg.hlw_kWhtoday = sysCfg2.hlw_kWhtoday; + sysCfg.hlw_kWhdoy = sysCfg2.hlw_kWhdoy; + } + if (sysCfg2.version >= 0x02001200) { // 2.0.18 + sysCfg.switchmode = sysCfg2.switchmode; + } + if (sysCfg2.version >= 0x02010000) { // 2.1.0 + strlcpy(sysCfg.mqtt_fingerprint, sysCfg2.mqtt_fingerprint, sizeof(sysCfg.mqtt_fingerprint)); + } + if (sysCfg2.version >= 0x02010200) { // 2.1.2 + sysCfg.sta_active = sysCfg2.sta_active; + strlcpy(sysCfg.sta_ssid[1], sysCfg2.sta_ssid2, sizeof(sysCfg.sta_ssid[1])); + strlcpy(sysCfg.sta_pwd[1], sysCfg2.sta_pwd2, sizeof(sysCfg.sta_pwd[1])); + } + CFG_Save(); +} + +/********************************************************************************************/ + +void CFG_Delta() +{ + if (sysCfg.version != VERSION) { // Fix version dependent changes + if (sysCfg.version < 0x03000600) { // 3.0.6 - Add parameter + sysCfg.pulsetime = APP_PULSETIME; + } + if (sysCfg.version < 0x03010100) { // 3.1.1 - Add parameter + sysCfg.poweronstate = APP_POWERON_STATE; + } + if (sysCfg.version < 0x03010200) { // 3.1.2 - Add parameter + if (sysCfg.poweronstate == 2) sysCfg.poweronstate = 3; + } + if (sysCfg.version < 0x03010600) { // 3.1.6 - Add parameter + sysCfg.blinktime = APP_BLINKTIME; + sysCfg.blinkcount = APP_BLINKCOUNT; + } + if (sysCfg.version < 0x03011000) { // 3.1.16 - Add parameter + getClient(sysCfg.ex_friendlyname, sysCfg.mqtt_client, sizeof(sysCfg.ex_friendlyname)); + } + if (sysCfg.version < 0x03020400) { // 3.2.4 - Add parameter + sysCfg.ws_pixels = WS2812_LEDS; + sysCfg.ws_red = 255; + sysCfg.ws_green = 0; + sysCfg.ws_blue = 0; + sysCfg.ws_ledtable = 0; + sysCfg.ws_dimmer = 8; + sysCfg.ws_fade = 0; + sysCfg.ws_speed = 1; + sysCfg.ws_scheme = 0; + sysCfg.ws_width = 1; + sysCfg.ws_wakeup = 0; + } + if (sysCfg.version < 0x03020500) { // 3.2.5 - Add parameter + strlcpy(sysCfg.friendlyname[0], sysCfg.ex_friendlyname, sizeof(sysCfg.friendlyname[0])); + strlcpy(sysCfg.friendlyname[1], FRIENDLY_NAME"2", sizeof(sysCfg.friendlyname[1])); + strlcpy(sysCfg.friendlyname[2], FRIENDLY_NAME"3", sizeof(sysCfg.friendlyname[2])); + strlcpy(sysCfg.friendlyname[3], FRIENDLY_NAME"4", sizeof(sysCfg.friendlyname[3])); + } + if (sysCfg.version < 0x03020800) { // 3.2.8 - Add parameter + strlcpy(sysCfg.switch_topic, sysCfg.button_topic, sizeof(sysCfg.switch_topic)); + sysCfg.mqtt_switch_retain = MQTT_SWITCH_RETAIN; + sysCfg.mqtt_enabled = MQTT_USE; + } + if (sysCfg.version < 0x03020C00) { // 3.2.12 - Add parameter + sysCfg.sleep = APP_SLEEP; + } + if (sysCfg.version < 0x03090204) { // 3.9.2d - Add parameter + for (byte i = 0; i < 4; i++) sysCfg.domoticz_switch_idx[i] = 0; + for (byte i = 0; i < 12; i++) sysCfg.domoticz_sensor_idx[i] = 0; + + sysCfg.module = MODULE; + for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + + sysCfg.led_pixels = 0; + for (byte i = 0; i < 5; i++) sysCfg.led_color[i] = 255; + sysCfg.led_table = 0; + for (byte i = 0; i < 3; i++) sysCfg.led_dimmer[i] = 10; + sysCfg.led_fade = 0; + sysCfg.led_speed = 0; + sysCfg.led_scheme = 0; + sysCfg.led_width = 0; + sysCfg.led_wakeup = 0; + } + if (sysCfg.version < 0x03090700) { // 3.9.7 - Add parameter + sysCfg.emulation = EMULATION; + } + + sysCfg.version = VERSION; + } +} + diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index cb85376b4..318f3f633 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x03091200 // 3.9.18 +#define VERSION 0x03091300 // 3.9.19 //#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k) // To be used as step 1. Next step is compile and use desired version @@ -155,6 +155,7 @@ enum butt_t {PRESSED, NOT_PRESSED}; #ifdef USE_I2C #include // I2C support library #endif // USE_I2C +#include "settings.h" typedef void (*rtcCallback)(); @@ -171,190 +172,6 @@ const char commands[MAX_BUTTON_COMMANDS][14] PROGMEM = { const char wificfg[5][12] PROGMEM = { "Restart", "Smartconfig", "Wifimanager", "WPSconfig", "Retry" }; -struct SYSCFG2 { // Version 2.x (old) - unsigned long cfg_holder; - unsigned long saveFlag; - unsigned long version; - byte seriallog_level; - byte syslog_level; - char syslog_host[32]; - char sta_ssid1[32]; - char sta_pwd1[64]; - char otaUrl[80]; - char mqtt_host[32]; - char mqtt_grptopic[32]; - char mqtt_topic[32]; - char mqtt_topic2[32]; - char mqtt_subtopic[32]; - int8_t timezone; - uint8_t power; - uint8_t ledstate; - uint16_t mqtt_port; - char mqtt_client[33]; - char mqtt_user[33]; - char mqtt_pwd[33]; - uint8_t webserver; - unsigned long bootcount; - char hostname[33]; - uint16_t syslog_port; - byte weblog_level; - uint16_t tele_period; - uint8_t sta_config; - int16_t savedata; - byte model; - byte mqtt_retain; - byte savestate; - unsigned long hlw_pcal; - unsigned long hlw_ucal; - unsigned long hlw_ical; - unsigned long hlw_kWhyesterday; - byte value_units; - uint16_t hlw_pmin; - uint16_t hlw_pmax; - uint16_t hlw_umin; - uint16_t hlw_umax; - uint16_t hlw_imin; - uint16_t hlw_imax; - uint16_t hlw_mpl; // MaxPowerLimit - uint16_t hlw_mplh; // MaxPowerLimitHold - uint16_t hlw_mplw; // MaxPowerLimitWindow - uint16_t hlw_mspl; // MaxSafePowerLimit - uint16_t hlw_msplh; // MaxSafePowerLimitHold - uint16_t hlw_msplw; // MaxSafePowerLimitWindow - uint16_t hlw_mkwh; // MaxEnergy - uint16_t hlw_mkwhs; // MaxEnergyStart - char domoticz_in_topic[33]; - char domoticz_out_topic[33]; - uint16_t domoticz_update_timer; - unsigned long domoticz_relay_idx[4]; - unsigned long domoticz_key_idx[4]; - byte message_format; // Not used since 3.2.6a - unsigned long hlw_kWhtoday; - uint16_t hlw_kWhdoy; - uint8_t switchmode; - char mqtt_fingerprint[60]; - byte sta_active; - char sta_ssid2[33]; - char sta_pwd2[65]; - -} sysCfg2; - -struct SYSCFG { - unsigned long cfg_holder; - unsigned long saveFlag; - unsigned long version; - unsigned long bootcount; - byte migflg; - int16_t savedata; - byte savestate; - byte model; - int8_t timezone; - char otaUrl[101]; - char ex_friendlyname[33]; // Not used since 3.2.5 - see below - - byte serial_enable; - byte seriallog_level; - uint8_t sta_config; - byte sta_active; - char sta_ssid[2][33]; - char sta_pwd[2][65]; - char hostname[33]; - char syslog_host[33]; - uint16_t syslog_port; - byte syslog_level; - uint8_t webserver; - byte weblog_level; - - char mqtt_fingerprint[60]; - char mqtt_host[33]; - uint16_t mqtt_port; - char mqtt_client[33]; - char mqtt_user[33]; - char mqtt_pwd[33]; - char mqtt_topic[33]; - char button_topic[33]; - char mqtt_grptopic[33]; - char mqtt_subtopic[33]; - byte mqtt_button_retain; - byte mqtt_power_retain; - byte value_units; - byte message_format; // Not used since 3.2.6a - uint16_t tele_period; - - uint8_t power; - uint8_t ledstate; - uint8_t switchmode; - - char domoticz_in_topic[33]; - char domoticz_out_topic[33]; - uint16_t domoticz_update_timer; - unsigned long domoticz_relay_idx[4]; - unsigned long domoticz_key_idx[4]; - - unsigned long hlw_pcal; - unsigned long hlw_ucal; - unsigned long hlw_ical; - unsigned long hlw_kWhtoday; - unsigned long hlw_kWhyesterday; - uint16_t hlw_kWhdoy; - uint16_t hlw_pmin; - uint16_t hlw_pmax; - uint16_t hlw_umin; - uint16_t hlw_umax; - uint16_t hlw_imin; - uint16_t hlw_imax; - uint16_t hlw_mpl; // MaxPowerLimit - uint16_t hlw_mplh; // MaxPowerLimitHold - uint16_t hlw_mplw; // MaxPowerLimitWindow - uint16_t hlw_mspl; // MaxSafePowerLimit - uint16_t hlw_msplh; // MaxSafePowerLimitHold - uint16_t hlw_msplw; // MaxSafePowerLimitWindow - uint16_t hlw_mkwh; // MaxEnergy - uint16_t hlw_mkwhs; // MaxEnergyStart - - uint16_t pulsetime; - uint8_t poweronstate; - uint16_t blinktime; - uint16_t blinkcount; - - uint16_t ws_pixels; - uint8_t ws_red; - uint8_t ws_green; - uint8_t ws_blue; - uint8_t ws_ledtable; - uint8_t ws_dimmer; - uint8_t ws_fade; - uint8_t ws_speed; - uint8_t ws_scheme; - uint8_t ws_width; - uint16_t ws_wakeup; - - char friendlyname[4][33]; - char switch_topic[33]; - byte mqtt_switch_retain; - uint8_t mqtt_enabled; - uint8_t sleep; - - uint16_t domoticz_switch_idx[4]; - uint16_t domoticz_sensor_idx[12]; - - uint8_t module; - mytmplt my_module; - - uint16_t led_pixels; - uint8_t led_color[5]; - uint8_t led_table; - uint8_t led_dimmer[3]; - uint8_t led_fade; - uint8_t led_speed; - uint8_t led_scheme; - uint8_t led_width; - uint16_t led_wakeup; - - uint8_t emulation; - -} sysCfg; - struct TIME_T { uint8_t Second; uint8_t Minute; @@ -451,324 +268,6 @@ boolean mDNSbegun = false; /********************************************************************************************/ -void CFG_DefaultSet1() -{ - memset(&sysCfg, 0x00, sizeof(SYSCFG)); - - sysCfg.cfg_holder = CFG_HOLDER; - sysCfg.saveFlag = 0; - sysCfg.version = VERSION; - sysCfg.bootcount = 0; -} - -void CFG_DefaultSet2() -{ - sysCfg.migflg = 0xA5; - sysCfg.savedata = SAVE_DATA; - sysCfg.savestate = SAVE_STATE; - sysCfg.module = MODULE; - sysCfg.model = 0; - sysCfg.timezone = APP_TIMEZONE; - strlcpy(sysCfg.otaUrl, OTA_URL, sizeof(sysCfg.otaUrl)); - strlcpy(sysCfg.ex_friendlyname, FRIENDLY_NAME, sizeof(sysCfg.ex_friendlyname)); - - sysCfg.seriallog_level = SERIAL_LOG_LEVEL; - sysCfg.sta_active = 0; - strlcpy(sysCfg.sta_ssid[0], STA_SSID1, sizeof(sysCfg.sta_ssid[0])); - strlcpy(sysCfg.sta_pwd[0], STA_PASS1, sizeof(sysCfg.sta_pwd[0])); - strlcpy(sysCfg.sta_ssid[1], STA_SSID2, sizeof(sysCfg.sta_ssid[1])); - strlcpy(sysCfg.sta_pwd[1], STA_PASS2, sizeof(sysCfg.sta_pwd[1])); - strlcpy(sysCfg.hostname, WIFI_HOSTNAME, sizeof(sysCfg.hostname)); - sysCfg.sta_config = WIFI_CONFIG_TOOL; - strlcpy(sysCfg.syslog_host, SYS_LOG_HOST, sizeof(sysCfg.syslog_host)); - sysCfg.syslog_port = SYS_LOG_PORT; - sysCfg.syslog_level = SYS_LOG_LEVEL; - sysCfg.webserver = WEB_SERVER; - sysCfg.weblog_level = WEB_LOG_LEVEL; - - strlcpy(sysCfg.mqtt_fingerprint, MQTT_FINGERPRINT, sizeof(sysCfg.mqtt_fingerprint)); - strlcpy(sysCfg.mqtt_host, MQTT_HOST, sizeof(sysCfg.mqtt_host)); - sysCfg.mqtt_port = MQTT_PORT; - strlcpy(sysCfg.mqtt_client, MQTT_CLIENT_ID, sizeof(sysCfg.mqtt_client)); - strlcpy(sysCfg.mqtt_user, MQTT_USER, sizeof(sysCfg.mqtt_user)); - strlcpy(sysCfg.mqtt_pwd, MQTT_PASS, sizeof(sysCfg.mqtt_pwd)); - strlcpy(sysCfg.mqtt_topic, MQTT_TOPIC, sizeof(sysCfg.mqtt_topic)); - strlcpy(sysCfg.button_topic, "0", sizeof(sysCfg.button_topic)); - strlcpy(sysCfg.mqtt_grptopic, MQTT_GRPTOPIC, sizeof(sysCfg.mqtt_grptopic)); - strlcpy(sysCfg.mqtt_subtopic, MQTT_SUBTOPIC, sizeof(sysCfg.mqtt_subtopic)); - sysCfg.mqtt_button_retain = MQTT_BUTTON_RETAIN; - sysCfg.mqtt_power_retain = MQTT_POWER_RETAIN; - sysCfg.value_units = VALUE_UNITS; - sysCfg.message_format = 0; - sysCfg.tele_period = TELE_PERIOD; - - sysCfg.power = APP_POWER; - sysCfg.poweronstate = APP_POWERON_STATE; - sysCfg.pulsetime = APP_PULSETIME; - sysCfg.ledstate = APP_LEDSTATE; - sysCfg.switchmode = SWITCH_MODE; - sysCfg.blinktime = APP_BLINKTIME; - sysCfg.blinkcount = APP_BLINKCOUNT; - sysCfg.sleep = APP_SLEEP; - - strlcpy(sysCfg.domoticz_in_topic, DOMOTICZ_IN_TOPIC, sizeof(sysCfg.domoticz_in_topic)); - strlcpy(sysCfg.domoticz_out_topic, DOMOTICZ_OUT_TOPIC, sizeof(sysCfg.domoticz_out_topic)); - sysCfg.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER; - for (byte i = 0; i < 4; i++) { - sysCfg.domoticz_relay_idx[i] = 0; - sysCfg.domoticz_key_idx[i] = 0; - sysCfg.domoticz_switch_idx[i] = 0; - } - for (byte i = 0; i < 12; i++) sysCfg.domoticz_sensor_idx[i] = 0; - - sysCfg.hlw_pcal = HLW_PREF_PULSE; - sysCfg.hlw_ucal = HLW_UREF_PULSE; - sysCfg.hlw_ical = HLW_IREF_PULSE; - sysCfg.hlw_kWhtoday = 0; - sysCfg.hlw_kWhyesterday = 0; - sysCfg.hlw_kWhdoy = 0; - sysCfg.hlw_pmin = 0; - sysCfg.hlw_pmax = 0; - sysCfg.hlw_umin = 0; - sysCfg.hlw_umax = 0; - sysCfg.hlw_imin = 0; - sysCfg.hlw_imax = 0; - sysCfg.hlw_mpl = 0; // MaxPowerLimit - sysCfg.hlw_mplh = MAX_POWER_HOLD; - sysCfg.hlw_mplw = MAX_POWER_WINDOW; - sysCfg.hlw_mspl = 0; // MaxSafePowerLimit - sysCfg.hlw_msplh = SAFE_POWER_HOLD; - sysCfg.hlw_msplw = SAFE_POWER_WINDOW; - sysCfg.hlw_mkwh = 0; // MaxEnergy - sysCfg.hlw_mkwhs = 0; // MaxEnergyStart - - sysCfg.ws_pixels = WS2812_LEDS; - sysCfg.ws_red = 255; - sysCfg.ws_green = 0; - sysCfg.ws_blue = 0; - sysCfg.ws_ledtable = 0; - sysCfg.ws_dimmer = 8; - sysCfg.ws_fade = 0; - sysCfg.ws_speed = 1; - sysCfg.ws_scheme = 0; - sysCfg.ws_width = 1; - sysCfg.ws_wakeup = 0; - - strlcpy(sysCfg.friendlyname[0], FRIENDLY_NAME, sizeof(sysCfg.friendlyname[0])); - strlcpy(sysCfg.friendlyname[1], FRIENDLY_NAME"2", sizeof(sysCfg.friendlyname[1])); - strlcpy(sysCfg.friendlyname[2], FRIENDLY_NAME"3", sizeof(sysCfg.friendlyname[2])); - strlcpy(sysCfg.friendlyname[3], FRIENDLY_NAME"4", sizeof(sysCfg.friendlyname[3])); - - for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; - - sysCfg.led_pixels = 0; - for (byte i = 0; i < 5; i++) sysCfg.led_color[i] = 255; - sysCfg.led_table = 0; - for (byte i = 0; i < 3; i++) sysCfg.led_dimmer[i] = 10; - sysCfg.led_fade = 0; - sysCfg.led_speed = 0; - sysCfg.led_scheme = 0; - sysCfg.led_width = 0; - sysCfg.led_wakeup = 0; - - strlcpy(sysCfg.switch_topic, "0", sizeof(sysCfg.switch_topic)); - sysCfg.mqtt_switch_retain = MQTT_SWITCH_RETAIN; - sysCfg.mqtt_enabled = MQTT_USE; - - sysCfg.emulation = EMULATION; - -} - -void CFG_Default() -{ - addLog_P(LOG_LEVEL_NONE, PSTR("Config: Use default configuration")); - CFG_DefaultSet1(); - CFG_DefaultSet2(); - CFG_Save(); -} - -void CFG_Migrate_Part2() -{ - addLog_P(LOG_LEVEL_NONE, PSTR("Config: Migrating configuration")); - CFG_DefaultSet1(); - CFG_DefaultSet2(); - - sysCfg.seriallog_level = sysCfg2.seriallog_level; - sysCfg.syslog_level = sysCfg2.syslog_level; - strlcpy(sysCfg.syslog_host, sysCfg2.syslog_host, sizeof(sysCfg.syslog_host)); - strlcpy(sysCfg.sta_ssid[0], sysCfg2.sta_ssid1, sizeof(sysCfg.sta_ssid[0])); - strlcpy(sysCfg.sta_pwd[0], sysCfg2.sta_pwd1, sizeof(sysCfg.sta_pwd[0])); - strlcpy(sysCfg.otaUrl, sysCfg2.otaUrl, sizeof(sysCfg.otaUrl)); - strlcpy(sysCfg.mqtt_host, sysCfg2.mqtt_host, sizeof(sysCfg.mqtt_host)); - strlcpy(sysCfg.mqtt_grptopic, sysCfg2.mqtt_grptopic, sizeof(sysCfg.mqtt_grptopic)); - strlcpy(sysCfg.mqtt_topic, sysCfg2.mqtt_topic, sizeof(sysCfg.mqtt_topic)); - strlcpy(sysCfg.button_topic, sysCfg2.mqtt_topic2, sizeof(sysCfg.button_topic)); - strlcpy(sysCfg.mqtt_subtopic, sysCfg2.mqtt_subtopic, sizeof(sysCfg.mqtt_subtopic)); - sysCfg.timezone = sysCfg2.timezone; - sysCfg.power = sysCfg2.power; - if (sysCfg2.version >= 0x01000D00) { // 1.0.13 - sysCfg.ledstate = sysCfg2.ledstate; - } - if (sysCfg2.version >= 0x01001600) { // 1.0.22 - sysCfg.mqtt_port = sysCfg2.mqtt_port; - strlcpy(sysCfg.mqtt_client, sysCfg2.mqtt_client, sizeof(sysCfg.mqtt_client)); - strlcpy(sysCfg.mqtt_user, sysCfg2.mqtt_user, sizeof(sysCfg.mqtt_user)); - strlcpy(sysCfg.mqtt_pwd, sysCfg2.mqtt_pwd, sizeof(sysCfg.mqtt_pwd)); - strlcpy(sysCfg.ex_friendlyname, sysCfg2.mqtt_client, sizeof(sysCfg.ex_friendlyname)); - } - if (sysCfg2.version >= 0x01001700) { // 1.0.23 - sysCfg.webserver = sysCfg2.webserver; - } - if (sysCfg2.version >= 0x01001A00) { // 1.0.26 - sysCfg.bootcount = sysCfg2.bootcount; - strlcpy(sysCfg.hostname, sysCfg2.hostname, sizeof(sysCfg.hostname)); - sysCfg.syslog_port = sysCfg2.syslog_port; - } - if (sysCfg2.version >= 0x01001B00) { // 1.0.27 - sysCfg.weblog_level = sysCfg2.weblog_level; - } - if (sysCfg2.version >= 0x01001C00) { // 1.0.28 - sysCfg.tele_period = sysCfg2.tele_period; - if ((sysCfg.tele_period > 0) && (sysCfg.tele_period < 10)) sysCfg.tele_period = 10; // Do not allow periods < 10 seconds - } - if (sysCfg2.version >= 0x01002000) { // 1.0.32 - sysCfg.sta_config = sysCfg2.sta_config; - } - if (sysCfg2.version >= 0x01002300) { // 1.0.35 - sysCfg.savedata = sysCfg2.savedata; - } - if (sysCfg2.version >= 0x02000000) { // 2.0.0 - sysCfg.model = sysCfg2.model; - } - if (sysCfg2.version >= 0x02000300) { // 2.0.3 - sysCfg.mqtt_button_retain = sysCfg2.mqtt_retain; - sysCfg.savestate = sysCfg2.savestate; - } - if (sysCfg2.version >= 0x02000500) { // 2.0.5 - sysCfg.hlw_pcal = sysCfg2.hlw_pcal; - sysCfg.hlw_ucal = sysCfg2.hlw_ucal; - sysCfg.hlw_ical = sysCfg2.hlw_ical; - sysCfg.hlw_kWhyesterday = sysCfg2.hlw_kWhyesterday; - sysCfg.value_units = sysCfg2.value_units; - } - if (sysCfg2.version >= 0x02000600) { // 2.0.6 - sysCfg.hlw_pmin = sysCfg2.hlw_pmin; - sysCfg.hlw_pmax = sysCfg2.hlw_pmax; - sysCfg.hlw_umin = sysCfg2.hlw_umin; - sysCfg.hlw_umax = sysCfg2.hlw_umax; - sysCfg.hlw_imin = sysCfg2.hlw_imin; - sysCfg.hlw_imax = sysCfg2.hlw_imax; - } - if (sysCfg2.version >= 0x02000700) { // 2.0.7 - sysCfg.message_format = 0; - strlcpy(sysCfg.domoticz_in_topic, sysCfg2.domoticz_in_topic, sizeof(sysCfg.domoticz_in_topic)); - strlcpy(sysCfg.domoticz_out_topic, sysCfg2.domoticz_out_topic, sizeof(sysCfg.domoticz_out_topic)); - sysCfg.domoticz_update_timer = sysCfg2.domoticz_update_timer; - for (byte i = 0; i < 4; i++) { - sysCfg.domoticz_relay_idx[i] = sysCfg2.domoticz_relay_idx[i]; - sysCfg.domoticz_key_idx[i] = sysCfg2.domoticz_key_idx[i]; - } - - sysCfg.hlw_mpl = sysCfg2.hlw_mpl; // MaxPowerLimit - sysCfg.hlw_mplh = sysCfg2.hlw_mplh; - sysCfg.hlw_mplw = sysCfg2.hlw_mplw; - sysCfg.hlw_mspl = sysCfg2.hlw_mspl; // MaxSafePowerLimit - sysCfg.hlw_msplh = sysCfg2.hlw_msplh; - sysCfg.hlw_msplw = sysCfg2.hlw_msplw; - sysCfg.hlw_mkwh = sysCfg2.hlw_mkwh; // MaxEnergy - sysCfg.hlw_mkwhs = sysCfg2.hlw_mkwhs; // MaxEnergyStart - } - if (sysCfg2.version >= 0x02001000) { // 2.0.16 - sysCfg.hlw_kWhtoday = sysCfg2.hlw_kWhtoday; - sysCfg.hlw_kWhdoy = sysCfg2.hlw_kWhdoy; - } - if (sysCfg2.version >= 0x02001200) { // 2.0.18 - sysCfg.switchmode = sysCfg2.switchmode; - } - if (sysCfg2.version >= 0x02010000) { // 2.1.0 - strlcpy(sysCfg.mqtt_fingerprint, sysCfg2.mqtt_fingerprint, sizeof(sysCfg.mqtt_fingerprint)); - } - if (sysCfg2.version >= 0x02010200) { // 2.1.2 - sysCfg.sta_active = sysCfg2.sta_active; - strlcpy(sysCfg.sta_ssid[1], sysCfg2.sta_ssid2, sizeof(sysCfg.sta_ssid[1])); - strlcpy(sysCfg.sta_pwd[1], sysCfg2.sta_pwd2, sizeof(sysCfg.sta_pwd[1])); - } - CFG_Save(); -} - -void CFG_Delta() -{ - if (sysCfg.version != VERSION) { // Fix version dependent changes - if (sysCfg.version < 0x03000600) { // 3.0.6 - Add parameter - sysCfg.pulsetime = APP_PULSETIME; - } - if (sysCfg.version < 0x03010100) { // 3.1.1 - Add parameter - sysCfg.poweronstate = APP_POWERON_STATE; - } - if (sysCfg.version < 0x03010200) { // 3.1.2 - Add parameter - if (sysCfg.poweronstate == 2) sysCfg.poweronstate = 3; - } - if (sysCfg.version < 0x03010600) { // 3.1.6 - Add parameter - sysCfg.blinktime = APP_BLINKTIME; - sysCfg.blinkcount = APP_BLINKCOUNT; - } - if (sysCfg.version < 0x03011000) { // 3.1.16 - Add parameter - getClient(sysCfg.ex_friendlyname, sysCfg.mqtt_client, sizeof(sysCfg.ex_friendlyname)); - } - if (sysCfg.version < 0x03020400) { // 3.2.4 - Add parameter - sysCfg.ws_pixels = WS2812_LEDS; - sysCfg.ws_red = 255; - sysCfg.ws_green = 0; - sysCfg.ws_blue = 0; - sysCfg.ws_ledtable = 0; - sysCfg.ws_dimmer = 8; - sysCfg.ws_fade = 0; - sysCfg.ws_speed = 1; - sysCfg.ws_scheme = 0; - sysCfg.ws_width = 1; - sysCfg.ws_wakeup = 0; - } - if (sysCfg.version < 0x03020500) { // 3.2.5 - Add parameter - strlcpy(sysCfg.friendlyname[0], sysCfg.ex_friendlyname, sizeof(sysCfg.friendlyname[0])); - strlcpy(sysCfg.friendlyname[1], FRIENDLY_NAME"2", sizeof(sysCfg.friendlyname[1])); - strlcpy(sysCfg.friendlyname[2], FRIENDLY_NAME"3", sizeof(sysCfg.friendlyname[2])); - strlcpy(sysCfg.friendlyname[3], FRIENDLY_NAME"4", sizeof(sysCfg.friendlyname[3])); - } - if (sysCfg.version < 0x03020800) { // 3.2.8 - Add parameter - strlcpy(sysCfg.switch_topic, sysCfg.button_topic, sizeof(sysCfg.switch_topic)); - sysCfg.mqtt_switch_retain = MQTT_SWITCH_RETAIN; - sysCfg.mqtt_enabled = MQTT_USE; - } - if (sysCfg.version < 0x03020C00) { // 3.2.12 - Add parameter - sysCfg.sleep = APP_SLEEP; - } - if (sysCfg.version < 0x03090204) { // 3.9.2d - Add parameter - for (byte i = 0; i < 4; i++) sysCfg.domoticz_switch_idx[i] = 0; - for (byte i = 0; i < 12; i++) sysCfg.domoticz_sensor_idx[i] = 0; - - sysCfg.module = MODULE; - for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; - - sysCfg.led_pixels = 0; - for (byte i = 0; i < 5; i++) sysCfg.led_color[i] = 255; - sysCfg.led_table = 0; - for (byte i = 0; i < 3; i++) sysCfg.led_dimmer[i] = 10; - sysCfg.led_fade = 0; - sysCfg.led_speed = 0; - sysCfg.led_scheme = 0; - sysCfg.led_width = 0; - sysCfg.led_wakeup = 0; - } - if (sysCfg.version < 0x03090700) { // 3.9.7 - Add parameter - sysCfg.emulation = EMULATION; - } - - sysCfg.version = VERSION; - } -} - -/********************************************************************************************/ - void getClient(char* output, const char* input, byte size) { char *token; @@ -821,7 +320,7 @@ void setRelay(uint8_t power) Serial.flush(); } else if (sysCfg.module == SONOFF_LED) { - sl_setColor(power &1); + sl_setPower(power &1); } else if (sysCfg.module == EXS_RELAY) { setLatchingRelay(power, 1); @@ -844,68 +343,6 @@ void setLed(uint8_t state) /********************************************************************************************/ -void sl_setDim(uint8_t *my_color) -{ - float newDim, fmyCld, fmyWrm, fmyRed, fmyGrn, fmyBlu; - - newDim = 100 / (float)sysCfg.led_dimmer[0]; - fmyCld = (float)sysCfg.led_color[0] / newDim; - fmyWrm = (float)sysCfg.led_color[1] / newDim; - fmyRed = (float)sysCfg.led_color[2] / newDim; - fmyGrn = (float)sysCfg.led_color[3] / newDim; - fmyBlu = (float)sysCfg.led_color[4] / newDim; - my_color[0] = (uint8_t)fmyCld; - my_color[1] = (uint8_t)fmyWrm; - my_color[2] = (uint8_t)fmyRed; - my_color[3] = (uint8_t)fmyGrn; - my_color[4] = (uint8_t)fmyBlu; -} - -void sl_setColor(byte type) -{ -// 0 = Off -// 1 = On -// 2 = Dim cold/warm -// 3 = Dim color - - uint8_t my_color[5]; - - sl_setDim(my_color); - if (type == 0) { - for (byte i = 0; i < 5; i++) { - if (pin[GPIO_PWM0 +i] < 99) analogWrite(pin[GPIO_PWM0 +i], 0); - } - } - else if (type == 1) { - for (byte i = 0; i < 5; i++) { - if (pin[GPIO_PWM0 +i] < 99) analogWrite(pin[GPIO_PWM0 +i], my_color[i]); - } - } - else if (type == 2) { // Cold/Warm - for (byte i = 0; i < 2; i++) { - if (pin[GPIO_PWM0 +i] < 99) analogWrite(pin[GPIO_PWM0 +i], my_color[i]); - } - } - else if (type == 3) { // Color - for (byte i = 2; i < 5; i++) { - if (pin[GPIO_PWM0 +i] < 99) analogWrite(pin[GPIO_PWM0 +i], my_color[i]); - } - } -} - -void sl_blank(byte state) -{ - if (sysCfg.module == SONOFF_LED) { - if (state) { - if (power &1) sl_setColor(1); - } else { - sl_setColor(0); - } - } -} - -/********************************************************************************************/ - void json2legacy(char* stopic, char* svalue) { char *p, *token; @@ -951,24 +388,6 @@ void json2legacy(char* stopic, char* svalue) } } -uint32_t Atoh(char *s) -{ - uint32_t value = 0, digit; - int8_t c; - - while((c = *s++)){ - if('0' <= c && c <= '9') - digit = c - '0'; - else if('A' <= c && c <= 'F') - digit = c - 'A' + 10; - else if('a' <= c && c<= 'f') - digit = c - 'a' + 10; - else break; - value = (value << 4) | digit; - } - return value; -} - /********************************************************************************************/ void mqtt_publish_sec(const char* topic, const char* data, boolean retained) @@ -1150,6 +569,8 @@ void mqtt_reconnect() } } +/********************************************************************************************/ + void mqttDataCb(char* topic, byte* data, unsigned int data_len) { char *str; @@ -1262,53 +683,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"BlinkCount\":%d}"), sysCfg.blinkcount); } - -/*** Sonoff Led Commands *********************************************************************/ - - else if ((sysCfg.module == SONOFF_LED) && !strcmp(type,"COLOR")) { - uint8_t my_color[5]; - if (data_len == 4) { - char ccold[3], cwarm[3]; - memcpy(ccold, dataBufUc, 2); - ccold[2] = '\0'; - memcpy(cwarm, dataBufUc + 2, 2); - cwarm[2] = '\0'; - my_color[0] = Atoh(ccold); - my_color[1] = Atoh(cwarm); - uint16_t temp = my_color[0]; - if (temp < my_color[1]) temp = my_color[1]; - float mDim = (float)temp / 2.55; - sysCfg.led_dimmer[0] = (uint8_t)mDim; - float newDim = 100 / mDim; - float fmyCold = (float)my_color[0] * newDim; - float fmyWarm = (float)my_color[1] * newDim; - sysCfg.led_color[0] = (uint8_t)fmyCold; - sysCfg.led_color[1] = (uint8_t)fmyWarm; - power = 1; -#ifdef USE_DOMOTICZ - mqtt_publishDomoticzPowerState(index); -#endif // USE_DOMOTICZ - sl_setColor(2); - } - sl_setDim(my_color); - uint16_t color = (uint16_t)my_color[0] << 8; - color += (uint16_t)my_color[1]; - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Color\":\"%04X\"}"), color); + else if ((sysCfg.module == SONOFF_LED) && sl_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) { + // Serviced } - else if ((sysCfg.module == SONOFF_LED) && !strcmp(type,"DIMMER")) { - if ((data_len > 0) && (payload >= 0) && (payload <= 100)) { - sysCfg.led_dimmer[0] = payload; - power = 1; -#ifdef USE_DOMOTICZ - mqtt_publishDomoticzPowerState(index); -#endif // USE_DOMOTICZ - sl_setColor(2); - } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Dimmer\":%d}"), sysCfg.led_dimmer[0]); - } - -/*********************************************************************************************/ - else if (!strcmp(type,"SAVEDATA")) { if ((data_len > 0) && (payload >= 0) && (payload <= 3600)) { sysCfg.savedata = payload; @@ -1803,8 +1180,9 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) #ifdef USE_I2C if (i2c_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, I2CScan"), svalue); #endif // USE_I2C + if (sysCfg.module == SONOFF_LED) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Color, Dimmer, Fade, Speed, Wakeup, WakeupDuration, LedTable"), svalue); #ifdef USE_WS2812 - if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Pixels, Led, Color, Dimmer, Scheme, Fade, Speed, Width, Wakeup, LedTable"), svalue); + if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Color, Dimmer, Fade, Speed, Wakeup, LedTable, Pixels, Led, Width, Scheme"), svalue); #endif #ifdef USE_IR_REMOTE if (pin[GPIO_IRSEND] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, IRSend"), svalue); @@ -2211,6 +1589,8 @@ void stateloop() } } + if (sysCfg.module == SONOFF_LED) sl_animate(); + #ifdef USE_WS2812 if (pin[GPIO_WS2812] < 99) ws2812_animate(); #endif // USE_WS2812 @@ -2343,7 +1723,7 @@ void stateloop() if (otaflag <= 0) { otaflag = 12; ESPhttpUpdate.rebootOnUpdate(false); - sl_blank(0); + sl_blank(1); // Try multiple times to get the update, in case we have a transient issue. // e.g. Someone issued "cmnd/sonoffs/update 1" and all the devices // are hammering the OTAURL. @@ -2361,7 +1741,7 @@ void stateloop() snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting")); restartflag = 2; } else { - sl_blank(1); + sl_blank(0); snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str()); } mqtt_publish_topic_P(0, PSTR("UPGRADE"), svalue); @@ -2536,11 +1916,8 @@ void GPIO_init() Baudrate = 19200; } else if (sysCfg.module == SONOFF_LED) { - analogWriteRange(255); // Default is 1023 (Arduino.h) - analogWriteFreq(200); // Default is 1000 (core_esp8266_wiring_pwm.c) - Try to lower flicker - for (byte i = 0; i < 5; i++) { - if (pin[GPIO_PWM0 +i] < 99) pinMode(pin[GPIO_PWM0 +i], OUTPUT); - } + pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led + sl_init(); } else { for (byte i = 0; i < 4; i++) { diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 34b9bac74..b8c0f64b1 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -212,13 +212,13 @@ const mytmplt modules[MAXMODULE] PROGMEM = { { "Sonoff LED", // Sonoff LED GPIO_KEY1, // GPIO00 Button 0, 0, 0, - GPIO_PWM3, // GPIO04 Green light - GPIO_PWM2, // GPIO05 Red light + GPIO_USER, // GPIO04 Optional sensor (PWM3 Green) + GPIO_USER, // GPIO05 Optional sensor (PWM2 Red) 0, 0, 0, 0, 0, 0, GPIO_PWM0, // GPIO12 Cold light GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_PWM1, // GPIO14 Warm light - GPIO_PWM4, // GPIO15 Blue light + GPIO_USER, // GPIO15 Optional sensor (PWM4 Blue) 0 }, { "1 Channel", // 1 Channel Inching/Latching Relay diff --git a/sonoff/support.ino b/sonoff/support.ino index d8e6ed707..a13c74447 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -23,292 +23,6 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*********************************************************************************************\ - * Config - Flash or Spiffs -\*********************************************************************************************/ - -extern "C" { -#include "spi_flash.h" -} - -#define SPIFFS_START ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE -#define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE - -// Version 2.x config -#define SPIFFS_CONFIG2 "/config.ini" -#define CFG_LOCATION2 SPIFFS_END - 2 - -// Version 3.x config -#define SPIFFS_CONFIG "/cfg.ini" -#define CFG_LOCATION SPIFFS_END - 4 - -uint32_t _cfgHash = 0; -int spiffsflag = 0; - -boolean spiffsPresent() -{ - return (SPIFFS_END - SPIFFS_START); -} - -uint32_t getHash() -{ - uint32_t hash = 0; - uint8_t *bytes = (uint8_t*)&sysCfg; - - for (uint16_t i = 0; i < sizeof(SYSCFG); i++) hash += bytes[i]*(i+1); - return hash; -} - -/*********************************************************************************************\ - * Config Save - Save parameters to Flash or Spiffs ONLY if any parameter has changed -\*********************************************************************************************/ -void CFG_Save() -{ - char log[LOGSZ]; - - if ((getHash() != _cfgHash) && (spiffsPresent())) { - if (!spiffsflag) { -#ifdef USE_SPIFFS - sysCfg.saveFlag++; - File f = SPIFFS.open(SPIFFS_CONFIG, "r+"); - if (f) { - uint8_t *bytes = (uint8_t*)&sysCfg; - for (int i = 0; i < sizeof(SYSCFG); i++) f.write(bytes[i]); - f.close(); - snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to spiffs count %d"), sizeof(SYSCFG), sysCfg.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } else { - addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Saving configuration failed")); - } - } else { -#endif // USE_SPIFFS - if (sysCfg.module != SONOFF_LED) noInterrupts(); - if (sysCfg.saveFlag == 0) { // Handle default and rollover - spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); - spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - } - sysCfg.saveFlag++; - spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); - spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - if (sysCfg.module != SONOFF_LED) interrupts(); - snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to flash at %X and count %d"), sizeof(SYSCFG), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } - _cfgHash = getHash(); - } -} - -void CFG_Load() -{ - char log[LOGSZ]; - - if (spiffsPresent()) { - if (!spiffsflag) { -#ifdef USE_SPIFFS - File f = SPIFFS.open(SPIFFS_CONFIG, "r+"); - if (f) { - uint8_t *bytes = (uint8_t*)&sysCfg; - for (int i = 0; i < sizeof(SYSCFG); i++) bytes[i] = f.read(); - f.close(); - snprintf_P(log, sizeof(log), PSTR("Config: Loaded configuration from spiffs count %d"), sysCfg.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } else { - addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading configuration failed")); - } - } else { -#endif // USE_SPIFFS - struct SYSCFGH { - unsigned long cfg_holder; - unsigned long saveFlag; - } _sysCfgH; - - noInterrupts(); - spi_flash_read((CFG_LOCATION) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); - if (sysCfg.saveFlag < _sysCfgH.saveFlag) - spi_flash_read((CFG_LOCATION + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); - interrupts(); - snprintf_P(log, sizeof(log), PSTR("Config: Loaded configuration from flash at %X and count %d"), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } - } -// snprintf_P(log, sizeof(log), PSTR("Config: Check 1 for migration (%08X)"), sysCfg.version); -// addLog(LOG_LEVEL_NONE, log); - if (sysCfg.cfg_holder != CFG_HOLDER) { - if ((sysCfg.version < 0x03000000) || (sysCfg.version > 0x73000000)) { - CFG_Migrate(); // Config may be present with versions below 3.0.0 - } else { - CFG_Default(); - } - } - _cfgHash = getHash(); -} - -void CFG_Migrate() -{ - char log[LOGSZ]; - - if (spiffsPresent()) { - if (!spiffsflag) { -#ifdef USE_SPIFFS - File f = SPIFFS.open(SPIFFS_CONFIG2, "r+"); - if (f) { - uint8_t *bytes = (uint8_t*)&sysCfg2; - for (int i = 0; i < sizeof(SYSCFG2); i++) bytes[i] = f.read(); - f.close(); - snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from spiffs count %d"), sysCfg2.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } else { - addLog_P(LOG_LEVEL_ERROR, PSTR("Config: ERROR - Loading previous configuration failed")); - } - } else { -#endif // USE_SPIFFS - struct SYSCFGH { - unsigned long cfg_holder; - unsigned long saveFlag; - } _sysCfgH; - - noInterrupts(); - spi_flash_read((CFG_LOCATION2) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2)); - spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&_sysCfgH, sizeof(SYSCFGH)); - if (sysCfg2.saveFlag < _sysCfgH.saveFlag) - spi_flash_read((CFG_LOCATION2 + 1) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg2, sizeof(SYSCFG2)); - interrupts(); - snprintf_P(log, sizeof(log), PSTR("Config: Loaded previous configuration from flash at %X and count %d"), CFG_LOCATION2 + (sysCfg2.saveFlag &1), sysCfg2.saveFlag); - addLog(LOG_LEVEL_DEBUG, log); - } - } -// snprintf_P(log, sizeof(log), PSTR("Config: Check 2 for migration (%08X)"), sysCfg2.version); -// addLog(LOG_LEVEL_NONE, log); - if ((sysCfg2.version > 0x01000000) && (sysCfg2.version < 0x03000000)) { - CFG_Migrate_Part2(); // Config is present between version 1.0.0 and 3.0.0 - } else { - CFG_Default(); - } - _cfgHash = getHash(); -} - -void CFG_Erase() -{ - char log[LOGSZ]; - SpiFlashOpResult result; - - uint32_t _sectorStart = (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 1; - uint32_t _sectorEnd = ESP.getFlashChipRealSize() / SPI_FLASH_SEC_SIZE; - boolean _serialoutput = (LOG_LEVEL_DEBUG_MORE <= seriallog_level); - - snprintf_P(log, sizeof(log), PSTR("Config: Erasing %d flash sectors"), _sectorEnd - _sectorStart); - addLog(LOG_LEVEL_DEBUG, log); - - for (uint32_t _sector = _sectorStart; _sector < _sectorEnd; _sector++) { - noInterrupts(); - result = spi_flash_erase_sector(_sector); - interrupts(); - if (_serialoutput) { - Serial.print(F("Flash: Erased sector ")); - Serial.print(_sector); - if (result == SPI_FLASH_RESULT_OK) { - Serial.println(F(" OK")); - } else { - Serial.println(F(" Error")); - } - delay(10); - } - } -} - -void CFG_Dump() -{ - #define CFG_COLS 16 - - char log[LOGSZ]; - uint16_t idx, maxrow, row, col; - - uint8_t *buffer = (uint8_t *) &sysCfg; - maxrow = ((sizeof(SYSCFG)+CFG_COLS)/CFG_COLS); - - for (row = 0; row < maxrow; row++) { - idx = row * CFG_COLS; - snprintf_P(log, sizeof(log), PSTR("%04X:"), idx); - for (col = 0; col < CFG_COLS; col++) { - if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); - snprintf_P(log, sizeof(log), PSTR("%s %02X"), log, buffer[idx + col]); - } - snprintf_P(log, sizeof(log), PSTR("%s |"), log); - for (col = 0; col < CFG_COLS; col++) { -// if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); - snprintf_P(log, sizeof(log), PSTR("%s%c"), log, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); - } - snprintf_P(log, sizeof(log), PSTR("%s|"), log); - addLog(LOG_LEVEL_INFO, log); - } -} - -#ifdef USE_SPIFFS -void initSpiffs() -{ - spiffsflag = 0; - if (!spiffsPresent()) { - spiffsflag = 1; - } else { - if (!SPIFFS.begin()) { - addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to mount file system. Will use flash")); - spiffsflag = 2; - } else { - addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Mount successful")); - File f = SPIFFS.open(SPIFFS_CONFIG, "r"); - if (!f) { - addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatting...")); - SPIFFS.format(); - addLog_P(LOG_LEVEL_DEBUG, PSTR("SPIFFS: Formatted")); - File f = SPIFFS.open(SPIFFS_CONFIG, "w"); - if (f) { - for (int i = 0; i < sizeof(SYSCFG); i++) f.write(0); - f.close(); - } else { - addLog_P(LOG_LEVEL_ERROR, PSTR("SPIFFS: WARNING - Failed to init config file. Will use flash")); - spiffsflag = 3; - } - } - } - } -} -#endif // USE_SPIFFS - -#include "eboot_command.h" - -/* - * Based on cores/esp8266/Updater.cpp - */ -void setFlashChipMode(byte option, byte mode) -{ - char log[LOGSZ]; - uint8_t *_buffer; - uint32_t address; - - if (option) { - eboot_command ebcmd; - eboot_command_read(&ebcmd); - address = ebcmd.args[0]; - } else { - address = 0; - } - _buffer = new uint8_t[FLASH_SECTOR_SIZE]; - if (spi_flash_read(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { - if (_buffer[2] != mode) { - _buffer[2] = mode &3; - noInterrupts(); - if (spi_flash_erase_sector(address / FLASH_SECTOR_SIZE) == SPI_FLASH_RESULT_OK) { - spi_flash_write(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); - } - interrupts(); - snprintf_P(log, sizeof(log), PSTR("FLSH: Updated Flash Chip Mode to %d"), (option) ? mode : ESP.getFlashChipMode()); - addLog(LOG_LEVEL_DEBUG, log); - } - } - delete[] _buffer; -} - /*********************************************************************************************\ * Wifi \*********************************************************************************************/ diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index f70f59891..25080590c 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -1054,7 +1054,7 @@ void handleUploadDone() } snprintf_P(log, sizeof(log), PSTR("Upload: Error - %s"), error.c_str()); addLog(LOG_LEVEL_DEBUG, log); - sl_blank(1); + sl_blank(0); } else { page += F("successful

Device will restart in a few seconds"); restartflag = 2; @@ -1099,7 +1099,7 @@ void handleUploadLoop() return; } } - sl_blank(0); + sl_blank(1); _colcount = 0; } else if (!_uploaderror && (upload.status == UPLOAD_FILE_WRITE)) { if (upload.totalSize == 0) diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index 3b26c6818..f0177d297 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -47,7 +47,7 @@ void ir_send_init(void) { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 } */ -boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) +boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) { boolean serviced = true; boolean error = false; @@ -58,7 +58,7 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBuf, uint16_t data if (!strcmp(type,"IRSEND")) { if (data_len) { StaticJsonBuffer<128> jsonBuf; - JsonObject &ir_json = jsonBuf.parseObject(dataBuf); + JsonObject &ir_json = jsonBuf.parseObject(dataBufUc); if (!ir_json.success()) { snprintf_P(svalue, ssvalue, PSTR("{\"IRSend\":\"Invalid JSON\"}")); // JSON decode failed } else { diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino new file mode 100644 index 000000000..56ea47059 --- /dev/null +++ b/sonoff/xdrv_snfled.ino @@ -0,0 +1,278 @@ +/* +Copyright (c) 2017 Theo Arends. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/*********************************************************************************************\ + * Sonoff Led +\*********************************************************************************************/ + +uint8_t ledTable[] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, + 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 22, + 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32, + 33, 33, 34, 35, 36, 36, 37, 38, 39, 40, 40, 41, 42, 43, 44, 45, + 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 67, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, + 80, 81, 82, 83, 85, 86, 87, 89, 90, 91, 93, 94, 95, 97, 98, 99, + 101,102,104,105,107,108,110,111,113,114,116,117,119,121,122,124, + 125,127,129,130,132,134,135,137,139,141,142,144,146,148,150,151, + 153,155,157,159,161,163,165,166,168,170,172,174,176,178,180,182, + 184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217, + 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; + +uint8_t sl_dcolor[2], sl_tcolor[2], sl_lcolor[2]; + +uint8_t sl_power; +uint8_t sl_blankv; +uint8_t sl_any; +uint8_t sl_wakeupActive = 0; +uint8_t sl_wakeupDimmer = 0; +uint16_t sl_wakeupCntr = 0; + +uint32_t Atoh(char *s) +{ + uint32_t value = 0, digit; + int8_t c; + + while((c = *s++)){ + if('0' <= c && c <= '9') + digit = c - '0'; + else if('A' <= c && c <= 'F') + digit = c - 'A' + 10; + else if('a' <= c && c<= 'f') + digit = c - 'a' + 10; + else break; + value = (value << 4) | digit; + } + return value; +} + +void sl_setDim(uint8_t myDimmer) +{ + float newDim, fmyCld, fmyWrm; + + newDim = 100 / (float)myDimmer; + fmyCld = (float)sysCfg.led_color[0] / newDim; + fmyWrm = (float)sysCfg.led_color[1] / newDim; + sl_dcolor[0] = (uint8_t)fmyCld; + sl_dcolor[1] = (uint8_t)fmyWrm; +} + +/********************************************************************************************/ + +void sl_init(void) +{ + analogWriteRange(255); // Default is 1023 (Arduino.h) + analogWriteFreq(200); // Default is 1000 (core_esp8266_wiring_pwm.c) - Try to lower flicker + sl_blankv = 0; + sl_power = 0; + sl_any = 0; + sl_wakeupActive = 0; +} + +void sl_blank(byte state) +/* + * Called by interrupt disabling routines like OTA or web upload + * state = 0: No blank + * 1: Blank led to solve flicker + */ +{ + if (sysCfg.module == SONOFF_LED) { + sl_blankv = state; + sl_wakeupActive = 0; + sl_animate(); + } +} + +void sl_setPower(uint8_t power) +{ + sl_blankv = 0; + sl_power = power &1; + sl_wakeupActive = 0; + sl_animate(); +} + +void sl_animate() +{ + char svalue[MESSZ]; + uint8_t fadeValue; + + if ((sl_power == 0) || sl_blankv) { // Power Off + sl_tcolor[0] = 0; + sl_tcolor[1] = 0; + } + else { + if (!sl_wakeupActive) { // Power On + sl_setDim(sysCfg.led_dimmer[0]); + if (sysCfg.led_fade == 0) { + sl_tcolor[0] = sl_dcolor[0]; + sl_tcolor[1] = sl_dcolor[1]; + } else { + if ((sl_tcolor[0] != sl_dcolor[0]) || (sl_tcolor[1] != sl_dcolor[1])) { + if (sl_tcolor[0] < sl_dcolor[0]) sl_tcolor[0] += ((sl_dcolor[0] - sl_tcolor[0]) >> sysCfg.led_speed) +1; + if (sl_tcolor[1] < sl_dcolor[1]) sl_tcolor[1] += ((sl_dcolor[1] - sl_tcolor[1]) >> sysCfg.led_speed) +1; + if (sl_tcolor[0] > sl_dcolor[0]) sl_tcolor[0] -= ((sl_tcolor[0] - sl_dcolor[0]) >> sysCfg.led_speed) +1; + if (sl_tcolor[1] > sl_dcolor[1]) sl_tcolor[1] -= ((sl_tcolor[1] - sl_dcolor[1]) >> sysCfg.led_speed) +1; + } + } + } else { // Power On using wak up duration + if (sl_wakeupActive == 1) { + sl_wakeupActive = 2; + sl_tcolor[0] = 0; + sl_tcolor[1] = 0; + sl_wakeupCntr = 0; + sl_wakeupDimmer = 0; + } + sl_wakeupCntr++; + if (sl_wakeupCntr > ((sysCfg.led_wakeup * STATES) / sysCfg.led_dimmer[0])) { + sl_wakeupCntr = 0; + sl_wakeupDimmer++; + if (sl_wakeupDimmer <= sysCfg.led_dimmer[0]) { + sl_setDim(sl_wakeupDimmer); + sl_tcolor[0] = sl_dcolor[0]; + sl_tcolor[1] = sl_dcolor[1]; + } else { + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Wakeup\":\"Done\"}")); + mqtt_publish_topic_P(1, PSTR("WAKEUP"), svalue); + sl_wakeupActive = 0; + } + } + } + } + if ((sl_lcolor[0] != sl_tcolor[0]) || (sl_lcolor[1] != sl_tcolor[1]) || sl_any) { + sl_any = 0; + sl_lcolor[0] = sl_tcolor[0]; + sl_lcolor[1] = sl_tcolor[1]; + for (byte i = 0; i < 2; i++) { + if (pin[GPIO_PWM0 +i] < 99) { + analogWrite(pin[GPIO_PWM0 +i], (sysCfg.led_table) ? ledTable[sl_lcolor[i]] : sl_lcolor[i]); + } + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +boolean sl_command(char *type, uint16_t index, char *dataBufUc, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) +{ + boolean serviced = true; + + if (!strcmp(type,"COLOR")) { + uint8_t my_color[5]; + if (data_len == 4) { + char ccold[3], cwarm[3]; + memcpy(ccold, dataBufUc, 2); + ccold[2] = '\0'; + memcpy(cwarm, dataBufUc + 2, 2); + cwarm[2] = '\0'; + my_color[0] = Atoh(ccold); + my_color[1] = Atoh(cwarm); + uint16_t temp = my_color[0]; + if (temp < my_color[1]) temp = my_color[1]; + float mDim = (float)temp / 2.55; + sysCfg.led_dimmer[0] = (uint8_t)mDim; + float newDim = 100 / mDim; + float fmyCold = (float)my_color[0] * newDim; + float fmyWarm = (float)my_color[1] * newDim; + sysCfg.led_color[0] = (uint8_t)fmyCold; + sysCfg.led_color[1] = (uint8_t)fmyWarm; + do_cmnd_power(index, 1); +#ifdef USE_DOMOTICZ + mqtt_publishDomoticzPowerState(index); +#endif // USE_DOMOTICZ + } + sl_setDim(sysCfg.led_dimmer[0]); + uint16_t color = (uint16_t)sl_dcolor[0] << 8; + color += (uint16_t)sl_dcolor[1]; + snprintf_P(svalue, ssvalue, PSTR("{\"Color\":\"%04X\"}"), color); + } + else if (!strcmp(type,"DIMMER")) { + if ((data_len > 0) && (payload >= 0) && (payload <= 100)) { + sysCfg.led_dimmer[0] = payload; + do_cmnd_power(index, 1); +#ifdef USE_DOMOTICZ + mqtt_publishDomoticzPowerState(index); +#endif // USE_DOMOTICZ + } + snprintf_P(svalue, ssvalue, PSTR("{\"Dimmer\":%d}"), sysCfg.led_dimmer[0]); + } + else if (!strcmp(type,"LEDTABLE")) { + if ((data_len > 0) && (payload >= 0) && (payload <= 2)) { + switch (payload) { + case 0: // Off + case 1: // On + sysCfg.led_table = payload; + break; + case 2: // Toggle + sysCfg.led_table ^= 1; + break; + } + sl_any = 1; + } + snprintf_P(svalue, ssvalue, PSTR("{\"LedTable\":\"%s\"}"), (sysCfg.led_table) ? MQTT_STATUS_ON : MQTT_STATUS_OFF); + } + else if (!strcmp(type,"FADE")) { + if ((data_len > 0) && (payload >= 0) && (payload <= 2)) { + switch (payload) { + case 0: // Off + case 1: // On + sysCfg.led_fade = payload; + break; + case 2: // Toggle + sysCfg.led_fade ^= 1; + break; + } + } + snprintf_P(svalue, ssvalue, PSTR("{\"Fade\":\"%s\"}"), (sysCfg.led_fade) ? MQTT_STATUS_ON : MQTT_STATUS_OFF); + } + else if (!strcmp(type,"SPEED")) { // 1 - fast, 8 - slow + if ((data_len > 0) && (payload > 0) && (payload <= 8)) { + sysCfg.led_speed = payload; + } + snprintf_P(svalue, ssvalue, PSTR("{\"Speed\":%d}"), sysCfg.led_speed); + } + else if (!strcmp(type,"WAKEUPDURATION")) { + if ((data_len > 0) && (payload > 0) && (payload < 3601)) { + sysCfg.led_wakeup = payload; + sl_wakeupActive = 0; + } + snprintf_P(svalue, ssvalue, PSTR("{\"WakeUpDuration\":%d}"), sysCfg.led_wakeup); + } + else if (!strcmp(type,"WAKEUP")) { + do_cmnd_power(index, 1); + sl_wakeupActive = 1; + snprintf_P(svalue, ssvalue, PSTR("{\"Wakeup\":\"Started\"}")); + } + else { + serviced = false; // Unknown command + } + return serviced; +} + diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index d1f3c94f7..0f6efd765 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -90,7 +90,7 @@ uint8_t speedValues[6] = { 10, // Slow 6, // Fast 2 }; // Fastest - +/* uint8_t ledTable[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -108,7 +108,7 @@ uint8_t ledTable[] = { 153,155,157,159,161,163,165,166,168,170,172,174,176,178,180,182, 184,186,189,191,193,195,197,199,201,204,206,208,210,212,215,217, 219,221,224,226,228,231,233,235,238,240,243,245,248,250,253,255 }; - +*/ uint8_t lany = 0; RgbColor dcolor, tcolor, lcolor;