From cf350dc58444339b12d98e1f9f3efa6f46710061 Mon Sep 17 00:00:00 2001 From: arendst Date: Wed, 25 Oct 2017 14:27:30 +0200 Subject: [PATCH] v5.8.0o - Add VEML6070 and more light schemes 5.8.0o * Remove max string length of 14 for Domoticz sensor descriptions * Add light scheme options (Color cycle Up, Down, Random) and moving WS2812 schemes up by 3 * Add support for VEML6070 I2C Ultra Violet level sensor (#1053) --- README.md | 2 +- sonoff/_releasenotes.ino | 8 +- sonoff/language/de-DE.h | 4 +- sonoff/language/en-GB.h | 4 +- sonoff/language/nl-NL.h | 4 +- sonoff/language/pl-PL.h | 4 +- sonoff/sonoff.h | 3 + sonoff/sonoff.ino | 26 +++-- sonoff/support.ino | 21 ++++ sonoff/user_config.h | 3 +- sonoff/webserver.ino | 115 +++++++++++----------- sonoff/xdrv_domoticz.ino | 28 ++---- sonoff/xdrv_ir_send.ino | 23 ++--- sonoff/xdrv_snfled.ino | 206 ++++++++++++++++++++++++++++----------- sonoff/xdrv_wemohue.ino | 148 ++++++++++++++-------------- sonoff/xdrv_ws2812.ino | 22 ++--- sonoff/xsns_veml6070.ino | 113 +++++++++++++++++++++ 17 files changed, 472 insertions(+), 262 deletions(-) create mode 100644 sonoff/xsns_veml6070.ino diff --git a/README.md b/README.md index 5d8361776..7f2f0b2f0 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 **5.8.0n** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.8.0o** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. ### ATTENTION All versions diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 82a039fe1..878898d39 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,8 +1,14 @@ -/* 5.8.0n +/* 5.8.0o + * Remove max string length of 14 for Domoticz sensor descriptions + * Add light scheme options (Color cycle Up, Down, Random) and moving WS2812 schemes up by 3 + * Add support for VEML6070 I2C Ultra Violet level sensor (#1053) + * + * 5.8.0n * Fix minimum TelePeriod of 10 seconds set by web page * Shrink information web page by 1k code space * Removed Arduino IDE version too low warning as it interferes with platformio.ini platform = espressif8266_stage * Add commands Color2, Color3, Color4, Width2, Width3, Width4 and SetOption16 to set Ws2812 Clock parameters (#1019) + * Fix Color3 and Color4 (#1019) * Add Polish language file (#1044, #1047) * Add support for KMC 70011 Power Monitoring Smart Plug (#1045) * Corrected German language file (#1054) diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index feccbf958..b6f450330 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -188,8 +188,9 @@ #define D_UPGRADE "upgrade" #define D_UPLOAD "upload" #define D_UPTIME "Laufzeit" -#define D_UTC_TIME "UTC" #define D_USER "Benutzer" +#define D_UTC_TIME "UTC" +#define D_UV_LEVEL "UV Level" #define D_VCC "VCC" #define D_VERSION "Version" #define D_VOLTAGE "Spannung" @@ -373,7 +374,6 @@ #define D_DOMOTICZ_KEY_IDX "Key idx" #define D_DOMOTICZ_SWITCH_IDX "Switch idx" #define D_DOMOTICZ_SENSOR_IDX "Sensor idx" - #define DOMOTICZ_SENSORS_MAX_STRING_LENGTH 14 #define D_DOMOTICZ_TEMP "Temp" #define D_DOMOTICZ_TEMP_HUM "Temp,Hum" #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 82f49cee6..2d7689338 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -188,8 +188,9 @@ #define D_UPGRADE "upgrade" #define D_UPLOAD "Upload" #define D_UPTIME "Uptime" -#define D_UTC_TIME "UTC" #define D_USER "User" +#define D_UTC_TIME "UTC" +#define D_UV_LEVEL "UV Level" #define D_VCC "Vcc" #define D_VERSION "Version" #define D_VOLTAGE "Voltage" @@ -373,7 +374,6 @@ #define D_DOMOTICZ_KEY_IDX "Key idx" #define D_DOMOTICZ_SWITCH_IDX "Switch idx" #define D_DOMOTICZ_SENSOR_IDX "Sensor idx" - #define DOMOTICZ_SENSORS_MAX_STRING_LENGTH 14 #define D_DOMOTICZ_TEMP "Temp" #define D_DOMOTICZ_TEMP_HUM "Temp,Hum" #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 30aba2e1e..e7fb40fd9 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -188,8 +188,9 @@ #define D_UPGRADE "opwaarderen" #define D_UPLOAD "Verzenden" #define D_UPTIME "Bedrijfstijd" -#define D_UTC_TIME "UTC" #define D_USER "Gebruiker" +#define D_UTC_TIME "UTC" +#define D_UV_LEVEL "UV niveau" #define D_VCC "Vcc" #define D_VERSION "Versie" #define D_VOLTAGE "Spanning" @@ -373,7 +374,6 @@ #define D_DOMOTICZ_KEY_IDX "Toets idx" #define D_DOMOTICZ_SWITCH_IDX "Schakelaar idx" #define D_DOMOTICZ_SENSOR_IDX "Sensor idx" - #define DOMOTICZ_SENSORS_MAX_STRING_LENGTH 14 #define D_DOMOTICZ_TEMP "Temp" #define D_DOMOTICZ_TEMP_HUM "Temp,Hum" #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Hum,Baro" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 8c2b8ccc7..0e41849f5 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -188,8 +188,9 @@ #define D_UPGRADE "Aktualizacji" #define D_UPLOAD "Wgraj" #define D_UPTIME "Uptime" -#define D_UTC_TIME "UTC" #define D_USER "Uzytkownik" +#define D_UTC_TIME "UTC" +#define D_UV_LEVEL "UV Level" #define D_VCC "VCC" #define D_VERSION "Wersja" #define D_VOLTAGE "Napiecie" @@ -373,7 +374,6 @@ #define D_DOMOTICZ_KEY_IDX "Key idx" #define D_DOMOTICZ_SWITCH_IDX "Przelacznik idx" #define D_DOMOTICZ_SENSOR_IDX "Sensor idx" - #define DOMOTICZ_SENSORS_MAX_STRING_LENGTH 14 #define D_DOMOTICZ_TEMP "Temp" #define D_DOMOTICZ_TEMP_HUM "Temp,Wilg" #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Wilg,Cis" diff --git a/sonoff/sonoff.h b/sonoff/sonoff.h index 4d0982816..6259a1c1d 100644 --- a/sonoff/sonoff.h +++ b/sonoff/sonoff.h @@ -107,5 +107,8 @@ enum ButtonStates {PRESSED, NOT_PRESSED}; enum SettingsParmaIndex {P_HOLD_TIME, P_MAX_POWER_RETRY, P_MAX_PARAM8}; enum Ws2812ClockIndex {WS_SECOND, WS_MINUTE, WS_HOUR}; enum Ws2812Color {WS_RED, WS_GREEN, WS_BLUE}; +enum LightTypes {LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7, LT_NU8, LT_NU9, LT_NU10, LT_WS2812, LT_RGBW, LT_RGBWC}; +enum LichtSubtypes {LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC}; +enum LichtSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX}; #endif // _SONOFF_H_ \ No newline at end of file diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 1caf50d4c..84df3e318 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x0508000E // 5.8.0n +#define VERSION 0x0508000F // 5.8.0o // Location specific includes #include "sonoff.h" // Enumaration used in user_config.h @@ -1792,7 +1792,10 @@ void MqttShowSensor(uint8_t* djson) #ifdef USE_BH1750 MqttShowBh1750(djson); #endif // USE_BH1750 - } +#ifdef USE_VEML6070 + MqttShowVeml6070(djson); +#endif // USE_VEML6070 +} #endif // USE_I2C if (strstr_P(mqtt_data, PSTR(D_TEMPERATURE))) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"" D_TEMPERATURE_UNIT "\":\"%c\""), mqtt_data, TempUnit()); @@ -1878,7 +1881,10 @@ void PerformEverySecond() #ifdef USE_BH1750 Bh1750Detect(); #endif // USE_BH1750 - } +#ifdef USE_VEML6070 + Veml6070Detect(); +#endif // USE_VEML6070 +} #endif // USE_I2C } if (tele_period >= Settings.tele_period) { @@ -2532,7 +2538,7 @@ void GpioInit() devices_present = 1; if (Settings.flag.pwm_control) { - light_type = 0; + light_type = LT_BASIC; for (byte i = 0; i < MAX_PWMS; i++) { if (pin[GPIO_PWM1 +i] < 99) { light_type++; // Use Dimmer/Color control for all PWM as SetOption15 = 1 @@ -2556,20 +2562,20 @@ void GpioInit() } else if ((H801 == Settings.module) || (MAGICHOME == Settings.module)) { // PWM RGBCW led if (!Settings.flag.pwm_control) { - light_type = 0; // Use basic PWM control if SetOption15 = 0 + light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0 } } else if (SONOFF_BN == Settings.module) { // PWM Single color led (White) - light_type = 1; + light_type = LT_PWM1; } else if (SONOFF_LED == Settings.module) { // PWM Dual color led (White warm and cold) - light_type = 2; + light_type = LT_PWM2; } else if (AILIGHT == Settings.module) { // RGBW led - light_type = 12; + light_type = LT_RGBW; } else if (SONOFF_B1 == Settings.module) { // RGBWC led - light_type = 13; + light_type = LT_RGBWC; } else { if (!light_type) { @@ -2603,7 +2609,7 @@ void GpioInit() #ifdef USE_WS2812 if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led devices_present++; - light_type = 11; + light_type = LT_WS2812; } #endif // USE_WS2812 if (light_type) { // Any Led light under Dimmer/Color control diff --git a/sonoff/support.ino b/sonoff/support.ino index 6d8adecda..231b084cf 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -795,6 +795,17 @@ void I2cScan(char *devs, unsigned int devs_len) snprintf_P(devs, devs_len, PSTR("{\"" D_CMND_I2CSCAN "\":\"" D_I2CSCAN_NO_DEVICES_FOUND "\"}")); } } + +boolean I2cDevice(byte addr) +{ + for (byte address = 1; address <= 127; address++) { + Wire.beginTransmission(address); + if (!Wire.endTransmission() && (address == addr)) { + return true; + } + } + return false; +} #endif // USE_I2C /*********************************************************************************************\ @@ -1159,6 +1170,16 @@ double FastPrecisePow(double a, double b) return r * u.d; } +char* GetIndexedString(char* destination, const char* source, uint8_t index) +{ + strcpy_P(destination, source); // Copies Flash to Ram until end of string + char *indexed_string = strtok(destination, "|"); + while (index--) { + indexed_string = strtok(NULL, "|"); + } + return indexed_string; +} + /*********************************************************************************************\ * Syslog \*********************************************************************************************/ diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 4510e228f..2c08a975b 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -44,7 +44,7 @@ // -- Wifi ---------------------------------------- #define WIFI_IP_ADDRESS "0.0.0.0" // [IpAddress1] Set to 0.0.0.0 for using DHCP or IP address -#define WIFI_GATEWAY "192.168.2.254" // {IpAddress2] If not using DHCP set Gateway IP address +#define WIFI_GATEWAY "192.168.2.254" // [IpAddress2] If not using DHCP set Gateway IP address #define WIFI_SUBNETMASK "255.255.255.0" // [IpAddress3] If not using DHCP set Network mask #define WIFI_DNS "192.168.2.27" // [IpAddress4] If not using DHCP set DNS IP address (might be equal to WIFI_GATEWAY) @@ -167,6 +167,7 @@ #define USE_I2C // I2C using library wire (+10k code, 0.2k mem) - Disable by // #define USE_BH1750 // Add I2C code for BH1750 sensor +// #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0.5k code) #define USE_BMP // Add I2C code for BMP/BME280 sensor #define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor #define USE_SHT // Add I2C emulating code for SHT1X sensor diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index ff2d915fc..a03b5d821 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -94,7 +94,7 @@ const char HTTP_HEAD[] PROGMEM = #ifdef BE_MINIMAL "

" D_MINIMAL_FIRMWARE_PLEASE_UPGRADE "

" #endif - "

{ha} " D_MODULE "

{h}

"; + "

{ha " D_MODULE "

{h}

"; const char HTTP_SCRIPT_CONSOL[] PROGMEM = "var sn=0;" // Scroll position "var id=99;" // Get most of weblog initially @@ -193,7 +193,7 @@ const char HTTP_BTN_CONF[] PROGMEM = const char HTTP_FORM_MODULE[] PROGMEM = "
 " D_MODULE_PARAMETERS " 
" "" - "
" D_MODULE_TYPE " ({mt})

"; + "
" D_MODULE_TYPE " ({mt)

"; const char HTTP_LNK_ITEM[] PROGMEM = "
{v} {i} {r}%
"; const char HTTP_LNK_SCAN[] PROGMEM = @@ -201,26 +201,26 @@ const char HTTP_LNK_SCAN[] PROGMEM = const char HTTP_FORM_WIFI[] PROGMEM = "
 " D_WIFI_PARAMETERS " " "" - "
" D_AP1_SSID " (" STA_SSID1 ")

" - "
" D_AP1_PASSWORD "

" - "
" D_AP2_SSID " (" STA_SSID2 ")

" - "
" D_AP2_PASSWORD "

" - "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; + "
" D_AP1_SSID " (" STA_SSID1 ")

" + "
" D_AP1_PASSWORD "

" + "
" D_AP2_SSID " (" STA_SSID2 ")

" + "
" D_AP2_PASSWORD "

" + "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; const char HTTP_FORM_MQTT[] PROGMEM = "
 " D_MQTT_PARAMETERS " " "" - "
" D_HOST " (" MQTT_HOST ")

" - "
" D_PORT " (" STR(MQTT_PORT) ")

" - "
" D_CLIENT " ({m0})

" - "
" D_USER " (" MQTT_USER ")

" - "
" D_PASSWORD "

" - "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" - "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; + "
" D_HOST " (" MQTT_HOST ")

" + "
" D_PORT " (" STR(MQTT_PORT) ")

" + "
" D_CLIENT " ({m0)

" + "
" D_USER " (" MQTT_USER ")

" + "
" D_PASSWORD "

" + "
" D_TOPIC " = %topic% (" MQTT_TOPIC ")

" + "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; const char HTTP_FORM_LOG1[] PROGMEM = "
 " D_LOGGING_PARAMETERS " " ""; const char HTTP_FORM_LOG2[] PROGMEM = - "
{b0}" D_LOG_LEVEL " ({b1})
" "0 " D_NONE "" "1 " D_ERROR "" "2 " D_INFO "" @@ -228,14 +228,14 @@ const char HTTP_FORM_LOG2[] PROGMEM = "4 " D_MORE_DEBUG "" "
"; const char HTTP_FORM_LOG3[] PROGMEM = - "
" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" - "
" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" - "
" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; + "
" D_SYSLOG_HOST " (" SYS_LOG_HOST ")

" + "
" D_SYSLOG_PORT " (" STR(SYS_LOG_PORT) ")

" + "
" D_TELEMETRY_PERIOD " (" STR(TELE_PERIOD) ")

"; const char HTTP_FORM_OTHER[] PROGMEM = "
 " D_OTHER_PARAMETERS " " "" - "
" D_WEB_ADMIN_PASSWORD "

" - "
" D_MQTT_ENABLE "
"; + "
" D_WEB_ADMIN_PASSWORD "

" + "
" D_MQTT_ENABLE "
"; const char HTTP_FORM_OTHER2[] PROGMEM = "
" D_FRIENDLY_NAME " {1 ({2)

"; #ifdef USE_EMULATION @@ -253,14 +253,14 @@ const char HTTP_FORM_UPG[] PROGMEM = "
" "
 " D_UPGRADE_BY_WEBSERVER " " "" - "
" D_OTA_URL "

" + "
" D_OTA_URL "

" "
" "


" "
 " D_UPGRADE_BY_FILE_UPLOAD " "; const char HTTP_FORM_RST_UPG[] PROGMEM = "
" "

" - "
" + "
" "
" "
" ""; @@ -423,7 +423,7 @@ void ShowPage(String &page) if((HTTP_ADMIN == webserver_state) && (Settings.web_password[0] != 0) && !WebServer->authenticate(WEB_USERNAME, Settings.web_password)) { return WebServer->requestAuthentication(); } - page.replace(F("{ha}"), my_module.name); + page.replace(F("{ha"), my_module.name); page.replace(F("{h}"), Settings.friendlyname[0]); if (HTTP_MANAGER == webserver_state) { if (WifiConfigCounter()) { @@ -457,7 +457,7 @@ void HandleRoot() page += F("
"); if (devices_present) { if (light_type) { - if ((2 == (light_type &7)) || (5 == (light_type &7))) { + if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { snprintf_P(line, sizeof(line), HTTP_MSG_SLIDER1, LightGetColorTemp()); page += line; } @@ -563,7 +563,10 @@ void HandleAjaxStatusRefresh() #ifdef USE_BH1750 tpage += WebShowBh1750(); #endif - } +#ifdef USE_VEML6070 + tpage += WebShowVeml6070(); +#endif +} #endif // USE_I2C String page = ""; if (tpage.length() > 0) { @@ -693,7 +696,7 @@ void HandleModuleConfiguration() page.replace(F("{v}"), FPSTR(S_CONFIGURE_MODULE)); page += FPSTR(HTTP_FORM_MODULE); snprintf_P(stemp, sizeof(stemp), kModules[MODULE].name); - page.replace(F("{mt}"), stemp); + page.replace(F("{mt"), stemp); mytmplt cmodule; memcpy_P(&cmodule, &kModules[Settings.module], sizeof(cmodule)); @@ -836,11 +839,11 @@ void HandleWifi(boolean scan) } page += FPSTR(HTTP_FORM_WIFI); - page.replace(F("{h1}"), Settings.hostname); - page.replace(F("{s1}"), Settings.sta_ssid[0]); - page.replace(F("{p1}"), Settings.sta_pwd[0]); - page.replace(F("{s2}"), Settings.sta_ssid[1]); - page.replace(F("{p2}"), Settings.sta_pwd[1]); + page.replace(F("{h1"), Settings.hostname); + page.replace(F("{s1"), Settings.sta_ssid[0]); + page.replace(F("{p1"), Settings.sta_pwd[0]); + page.replace(F("{s2"), Settings.sta_ssid[1]); + page.replace(F("{p2"), Settings.sta_pwd[1]); page += FPSTR(HTTP_FORM_END); if (HTTP_MANAGER == webserver_state) { page += FPSTR(HTTP_BTN_RSTRT); @@ -862,14 +865,14 @@ void HandleMqttConfiguration() page += FPSTR(HTTP_FORM_MQTT); char str[sizeof(Settings.mqtt_client)]; GetMqttClient(str, MQTT_CLIENT_ID, sizeof(Settings.mqtt_client)); - page.replace(F("{m0}"), str); - page.replace(F("{m1}"), Settings.mqtt_host); - page.replace(F("{m2}"), String(Settings.mqtt_port)); - page.replace(F("{m3}"), Settings.mqtt_client); - page.replace(F("{m4}"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); - page.replace(F("{m5}"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); - page.replace(F("{m6}"), Settings.mqtt_topic); - page.replace(F("{m7}"), Settings.mqtt_fulltopic); + page.replace(F("{m0"), str); + page.replace(F("{m1"), Settings.mqtt_host); + page.replace(F("{m2"), String(Settings.mqtt_port)); + page.replace(F("{m3"), Settings.mqtt_client); + page.replace(F("{m4"), (Settings.mqtt_user[0] == '\0')?"0":Settings.mqtt_user); + page.replace(F("{m5"), (Settings.mqtt_pwd[0] == '\0')?"0":Settings.mqtt_pwd); + page.replace(F("{m6"), Settings.mqtt_topic); + page.replace(F("{m7"), Settings.mqtt_fulltopic); page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_BTN_CONF); ShowPage(page); @@ -889,25 +892,25 @@ void HandleLoggingConfiguration() page += FPSTR(HTTP_FORM_LOG2); switch (idx) { case 0: - page.replace(F("{b0}"), F(D_SERIAL " ")); - page.replace(F("{b1}"), STR(SERIAL_LOG_LEVEL)); - page.replace(F("{b2}"), F("ls")); + page.replace(F("{b0"), F(D_SERIAL " ")); + page.replace(F("{b1"), STR(SERIAL_LOG_LEVEL)); + page.replace(F("{b2"), F("ls")); for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { page.replace("{a" + String(i), (i == Settings.seriallog_level) ? F(" selected ") : F(" ")); } break; case 1: - page.replace(F("{b0}"), F(D_WEB " ")); - page.replace(F("{b1}"), STR(WEB_LOG_LEVEL)); - page.replace(F("{b2}"), F("lw")); + page.replace(F("{b0"), F(D_WEB " ")); + page.replace(F("{b1"), STR(WEB_LOG_LEVEL)); + page.replace(F("{b2"), F("lw")); for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { page.replace("{a" + String(i), (i == Settings.weblog_level) ? F(" selected ") : F(" ")); } break; case 2: - page.replace(F("{b0}"), F(D_SYS)); - page.replace(F("{b1}"), STR(SYS_LOG_LEVEL)); - page.replace(F("{b2}"), F("ll")); + page.replace(F("{b0"), F(D_SYS)); + page.replace(F("{b1"), STR(SYS_LOG_LEVEL)); + page.replace(F("{b2"), F("ll")); for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { page.replace("{a" + String(i), (i == Settings.syslog_level) ? F(" selected ") : F(" ")); } @@ -915,9 +918,9 @@ void HandleLoggingConfiguration() } } page += FPSTR(HTTP_FORM_LOG3); - page.replace(F("{l2}"), Settings.syslog_host); - page.replace(F("{l3}"), String(Settings.syslog_port)); - page.replace(F("{l4}"), String(Settings.tele_period)); + page.replace(F("{l2"), Settings.syslog_host); + page.replace(F("{l3"), String(Settings.syslog_port)); + page.replace(F("{l4"), String(Settings.tele_period)); page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_BTN_CONF); ShowPage(page); @@ -934,8 +937,8 @@ void HandleOtherConfiguration() String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_OTHER)); page += FPSTR(HTTP_FORM_OTHER); - page.replace(F("{p1}"), Settings.web_password); - page.replace(F("{r1}"), (Settings.flag.mqtt_enabled) ? F(" checked") : F("")); + page.replace(F("{p1"), Settings.web_password); + page.replace(F("{r1"), (Settings.flag.mqtt_enabled) ? F(" checked") : F("")); page += FPSTR(HTTP_FORM_OTHER2); page.replace(F("{1"), F("1")); page.replace(F("{2"), FRIENDLY_NAME); @@ -1157,7 +1160,7 @@ void HandleRestoreConfiguration() page.replace(F("{v}"), FPSTR(S_RESTORE_CONFIGURATION)); page += FPSTR(HTTP_FORM_RST); page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1}"), F(D_RESTORE)); + page.replace(F("{r1"), F(D_RESTORE)); page += FPSTR(HTTP_BTN_CONF); ShowPage(page); @@ -1175,9 +1178,9 @@ void HandleUpgradeFirmware() String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_FIRMWARE_UPGRADE)); page += FPSTR(HTTP_FORM_UPG); - page.replace(F("{o1}"), Settings.ota_url); + page.replace(F("{o1"), Settings.ota_url); page += FPSTR(HTTP_FORM_RST_UPG); - page.replace(F("{r1}"), F(D_UPGRADE)); + page.replace(F("{r1"), F(D_UPGRADE)); page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index 0f2f8f003..2f58bd1c0 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -35,26 +35,10 @@ const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = "" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")"; #endif // USE_WEBSERVER -enum DomoticzSensors { - DZ_TEMP, - DZ_TEMP_HUM, - DZ_TEMP_HUM_BARO, - DZ_POWER_ENERGY, - DZ_ILLUMINANCE, - DZ_COUNT, - DZ_VOLTAGE, - DZ_CURRENT, - DZ_MAX_SENSORS }; +enum DomoticzSensors {DZ_TEMP, DZ_TEMP_HUM, DZ_TEMP_HUM_BARO, DZ_POWER_ENERGY, DZ_ILLUMINANCE, DZ_COUNT, DZ_VOLTAGE, DZ_CURRENT, DZ_MAX_SENSORS}; -const char kDomoticzSensors[DZ_MAX_SENSORS][DOMOTICZ_SENSORS_MAX_STRING_LENGTH] PROGMEM = { - D_DOMOTICZ_TEMP, - D_DOMOTICZ_TEMP_HUM, - D_DOMOTICZ_TEMP_HUM_BARO, - D_DOMOTICZ_POWER_ENERGY, - D_DOMOTICZ_ILLUMINANCE, - D_DOMOTICZ_COUNT, - D_DOMOTICZ_VOLTAGE, - D_DOMOTICZ_CURRENT }; +const char kDomoticzSensors[] PROGMEM = + D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT ; char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; char domoticz_out_topic[] = DOMOTICZ_OUT_TOPIC; @@ -325,7 +309,8 @@ void HandleDomoticzConfiguration() } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); - char stemp[20]; + char stemp[sizeof(kDomoticzSensors)]; + char *sensortype; String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONFIGURE_DOMOTICZ)); @@ -345,8 +330,7 @@ void HandleDomoticzConfiguration() for (int i = 0; i < DZ_MAX_SENSORS; i++) { page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR); page.replace("{1", String(i +1)); - snprintf_P(stemp, sizeof(stemp), kDomoticzSensors[i]); - page.replace("{2", stemp); + page.replace("{2", GetIndexedString(stemp, kDomoticzSensors, i)); page.replace("{5", String((int)Settings.domoticz_sensor_idx[i])); } page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER); diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index 5a185836a..f1642eec4 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -66,6 +66,10 @@ void IrSendInit(void) #define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds +// Based on IRremoteESP8266.h enum decode_type_t +const char kIrReceiveProtocols[] PROGMEM = + "UNKNOWN|RC5|RC6|NEC|SONY|PANASONIC|JVC|SAMSUNG|WHYNTER|AIWA_RC_T501|LG|SANYO|MITSUBISHI|DISH|SHARP"; + IRrecv *irrecv = NULL; unsigned long ir_lasttime = 0; @@ -79,10 +83,8 @@ void IrReceiveInit(void) void IrReceiveCheck() { - char sirtype[100]; - char *protocol; + char sirtype[sizeof(kIrReceiveProtocols)]; int8_t iridx = 0; - uint8_t diridx = 0; decode_results results; @@ -100,21 +102,12 @@ void IrReceiveCheck() if ((iridx < 0) || (iridx > 14)) { iridx = 0; } - diridx = iridx; - // Based on IRremoteESP8266.h enum decode_type_t - snprintf_P(sirtype, sizeof(sirtype), PSTR("UNKNOWN RC5 RC6 NEC SONY PANASONIC JVC SAMSUNG WHYNTER AIWA_RC_T501 LG SANYO MITSUBISHI DISH SHARP")); - protocol = strtok(sirtype, " "); - while (iridx) { - iridx--; - protocol = strtok(NULL, " "); - } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_IRRECEIVED "\":{\"" D_IR_PROTOCOL "\":\"%s\", \"" D_IR_BITS "\":%d, \"" D_IR_DATA "\":\"%X\"}}"), - protocol, results.bits, results.value); + GetIndexedString(sirtype, kIrReceiveProtocols, iridx), results.bits, results.value); MqttPublishPrefixTopic_P(6, PSTR(D_IRRECEIVED)); #ifdef USE_DOMOTICZ - unsigned long value = results.value | (diridx << 28); // [Protocol:4, Data:28] - DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value + unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28] + DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value #endif // USE_DOMOTICZ } diff --git a/sonoff/xdrv_snfled.ino b/sonoff/xdrv_snfled.ino index 312e8067f..121dcda1a 100644 --- a/sonoff/xdrv_snfled.ino +++ b/sonoff/xdrv_snfled.ino @@ -69,6 +69,7 @@ uint8_t light_current_color[5]; uint8_t light_new_color[5]; uint8_t light_last_color[5]; +uint8_t light_wheel = 0; uint8_t light_subtype = 0; uint8_t light_power = 0; uint8_t light_update = 1; @@ -159,11 +160,13 @@ void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t dut void LightInit(void) { - if (light_type < 6) { // PWM + uint8_t max_scheme = LS_MAX -1; + + if (light_type < LT_PWM6) { // PWM for (byte i = 0; i < light_type; i++) { Settings.pwm_value[i] = 0; // Disable direct PWM control } - if (1 == light_type) { + if (LT_PWM1 == light_type) { Settings.led_color[0] = 255; // One PWM channel only supports Dimmer but needs max color } if (SONOFF_LED == Settings.module) { // Fix Sonoff Led instabilities @@ -180,14 +183,11 @@ void LightInit(void) digitalWrite(14, LOW); } } - Settings.led_scheme = 0; } #ifdef USE_WS2812 // ************************************************************************ - else if (11 == light_type) { + else if (LT_WS2812 == light_type) { Ws2812Init(); - if (1 == Settings.led_scheme) { - Settings.led_scheme = 0; - } + max_scheme += 8; } #endif // USE_WS2812 ************************************************************************ else { @@ -200,7 +200,10 @@ void LightInit(void) digitalWrite(light_pdcki_pin, LOW); LightMy92x1Init(); - Settings.led_scheme = 0; + } + + if ((LS_WAKEUP == Settings.led_scheme) || (Settings.led_scheme > max_scheme)) { + Settings.led_scheme = LS_POWER; } light_subtype = light_type &7; @@ -222,7 +225,7 @@ void LightSetColorTemp(uint16_t ct) } uint16_t icold = (100 * (347 - my_ct)) / 136; uint16_t iwarm = (100 * my_ct) / 136; - if (5 == light_subtype) { + if (LST_RGBWC == light_subtype) { Settings.led_color[0] = 0; Settings.led_color[1] = 0; Settings.led_color[2] = 0; @@ -237,7 +240,7 @@ void LightSetColorTemp(uint16_t ct) uint16_t LightGetColorTemp() { uint8_t ct_idx = 0; - if (5 == light_subtype) { + if (LST_RGBWC == light_subtype) { ct_idx = 3; } uint16_t my_ct = Settings.led_color[ct_idx +1]; @@ -266,7 +269,6 @@ void LightSetDimmer(uint8_t myDimmer) void LightSetColor() { uint8_t highest = 0; - float temp; for (byte i = 0; i < light_subtype; i++) { if (highest < light_current_color[i]) { @@ -277,7 +279,7 @@ void LightSetColor() Settings.led_dimmer = (uint8_t)mDim; float dimmer = 100 / mDim; for (byte i = 0; i < light_subtype; i++) { - temp = (float)light_current_color[i] * dimmer; + float temp = (float)light_current_color[i] * dimmer; Settings.led_color[i] = (uint8_t)temp; } } @@ -296,6 +298,13 @@ char* LightGetColor(uint8_t type, char* scolor) return scolor; } +void LightPowerOn() +{ + if (Settings.led_dimmer && !(light_power)) { + ExecuteCommandPower(devices_present, 1); + } +} + void LightPreparePower() { char scolor[25]; @@ -313,7 +322,7 @@ void LightPreparePower() #endif // USE_DOMOTICZ GetPowerDevice(scommand, devices_present, sizeof(scommand)); - if (light_subtype > 1) { + if (light_subtype > LST_SINGLE) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\", \"" D_CMND_DIMMER "\":%d, \"" D_CMND_COLOR "\":\"%s\"}"), scommand, GetStateText(light_power), Settings.led_dimmer, LightGetColor(0, scolor)); } else { @@ -322,6 +331,85 @@ void LightPreparePower() } } +void LightFade() +{ + if (0 == Settings.led_fade) { + for (byte i = 0; i < light_subtype; i++) { + light_new_color[i] = light_current_color[i]; + } + } else { + uint8_t shift = Settings.led_speed; + if (Settings.led_speed > 6) { + shift = (strip_timer_counter % (Settings.led_speed -6)) ? 0 : 8; + } + if (shift) { + for (byte i = 0; i < light_subtype; i++) { + if (light_new_color[i] != light_current_color[i]) { + if (light_new_color[i] < light_current_color[i]) { + light_new_color[i] += ((light_current_color[i] - light_new_color[i]) >> shift) +1; + } + if (light_new_color[i] > light_current_color[i]) { + light_new_color[i] -= ((light_new_color[i] - light_current_color[i]) >> shift) +1; + } + } + } + } + } +} + +void LightWheel(uint8_t wheel_pos) +{ + wheel_pos = 255 - wheel_pos; + if (wheel_pos < 85) { + light_entry_color[0] = 255 - wheel_pos * 3; + light_entry_color[1] = 0; + light_entry_color[2] = wheel_pos * 3; + } else if (wheel_pos < 170) { + wheel_pos -= 85; + light_entry_color[0] = 0; + light_entry_color[1] = wheel_pos * 3; + light_entry_color[2] = 255 - wheel_pos * 3; + } else { + wheel_pos -= 170; + light_entry_color[0] = wheel_pos * 3; + light_entry_color[1] = 255 - wheel_pos * 3; + light_entry_color[2] = 0; + } + light_entry_color[3] = 0; + light_entry_color[4] = 0; + float dimmer = 100 / (float)Settings.led_dimmer; + for (byte i = 0; i < LST_RGB; i++) { + float temp = (float)light_entry_color[i] / dimmer; + light_entry_color[i] = (uint8_t)temp; + } +} + +void LightCycleColor(int8_t direction) +{ + if (strip_timer_counter % (Settings.led_speed * 2)) { + return; + } + light_wheel += direction; + LightWheel(light_wheel); + memcpy(light_new_color, light_entry_color, sizeof(light_new_color)); +} + +void LightRandomColor() +{ + uint8_t light_update = 0; + for (byte i = 0; i < LST_RGB; i++) { + if (light_new_color[i] != light_current_color[i]) { + light_update = 1; + } + } + if (!light_update) { + light_wheel = random(255); + LightWheel(light_wheel); + memcpy(light_current_color, light_entry_color, sizeof(light_current_color)); + } + LightFade(); +} + void LightSetPower(uint8_t mpower) { light_power = mpower; @@ -336,7 +424,6 @@ void LightSetPower(uint8_t mpower) void LightAnimate() { - uint8_t fadeValue; uint8_t cur_col[5]; strip_timer_counter++; @@ -350,26 +437,11 @@ void LightAnimate() else { sleep = 0; switch (Settings.led_scheme) { - case 0: // Power On + case LS_POWER: LightSetDimmer(Settings.led_dimmer); - if (0 == Settings.led_fade) { - for (byte i = 0; i < light_subtype; i++) { - light_new_color[i] = light_current_color[i]; - } - } else { - for (byte i = 0; i < light_subtype; i++) { - if (light_new_color[i] != light_current_color[i]) { - if (light_new_color[i] < light_current_color[i]) { - light_new_color[i] += ((light_current_color[i] - light_new_color[i]) >> Settings.led_speed) +1; - } - if (light_new_color[i] > light_current_color[i]) { - light_new_color[i] -= ((light_new_color[i] - light_current_color[i]) >> Settings.led_speed) +1; - } - } - } - } + LightFade(); break; - case 1: // Power On using wake up duration + case LS_WAKEUP: if (2 == light_wakeup_active) { light_wakeup_active = 1; for (byte i = 0; i < light_subtype; i++) { @@ -391,20 +463,29 @@ void LightAnimate() snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WAKEUP "\":\"" D_DONE "\"}")); MqttPublishPrefixTopic_P(2, PSTR(D_CMND_WAKEUP)); light_wakeup_active = 0; - Settings.led_scheme = 0; + Settings.led_scheme = LS_POWER; } } break; + case LS_CYCLEUP: + LightCycleColor(1); + break; + case LS_CYCLEDN: + LightCycleColor(-1); + break; + case LS_RANDOM: + LightRandomColor(); + break; #ifdef USE_WS2812 // ************************************************************************ default: - if (11 == light_type) { - Ws2812ShowScheme(Settings.led_scheme -2); + if (LT_WS2812 == light_type) { + Ws2812ShowScheme(Settings.led_scheme -LS_MAX); } #endif // USE_WS2812 ************************************************************************ } } - if ((Settings.led_scheme < 2) || !light_power) { + if ((Settings.led_scheme < LS_MAX) || !light_power) { for (byte i = 0; i < light_subtype; i++) { if (light_last_color[i] != light_new_color[i]) { light_update = 1; @@ -415,7 +496,7 @@ void LightAnimate() for (byte i = 0; i < light_subtype; i++) { light_last_color[i] = light_new_color[i]; cur_col[i] = (Settings.led_table) ? ledTable[light_last_color[i]] : light_last_color[i]; - if (light_type < 6) { + if (light_type < LT_PWM6) { if (pin[GPIO_PWM1 +i] < 99) { uint16_t curcol = cur_col[i] * (Settings.pwm_range / 255); // snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "Cur_Col%d %d, CurCol %d"), i, cur_col[i], curcol); @@ -425,11 +506,11 @@ void LightAnimate() } } #ifdef USE_WS2812 // ************************************************************************ - if (11 == light_type) { + if (LT_WS2812 == light_type) { Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2]); } #endif // USE_ES2812 ************************************************************************ - if (light_type > 11) { + if (light_type > LT_WS2812) { LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); } } @@ -543,7 +624,7 @@ void LightHsbToRgb() void LightReplaceHsb(String *response) { - if (light_subtype > 2) { + if (light_subtype > LST_COLDWARM) { LightRgbToHsb(); response->replace("{h}", String((uint16_t)(65535.0f * light_hue))); response->replace("{s}", String((uint8_t)(254.0f * light_saturation))); @@ -558,7 +639,7 @@ void LightReplaceHsb(String *response) void LightGetHsb(float *hue, float *sat, float *bri) { - if (light_subtype > 2) { + if (light_subtype > LST_COLDWARM) { LightRgbToHsb(); *hue = light_hue; *sat = light_saturation; @@ -573,8 +654,8 @@ void LightGetHsb(float *hue, float *sat, float *bri) void LightSetHsb(float hue, float sat, float bri, uint16_t ct) { - if (light_type > 2) { - if ((5 == light_subtype) && (ct > 0)) { + if (light_subtype > LST_COLDWARM) { + if ((LST_RGBWC == light_subtype) && (ct > 0)) { LightSetColorTemp(ct); } else { light_hue = hue; @@ -588,7 +669,7 @@ void LightSetHsb(float hue, float sat, float bri, uint16_t ct) } else { uint8_t tmp = (uint8_t)(bri * 100); Settings.led_dimmer = tmp; - if (2 == light_subtype) { + if (LST_COLDWARM == light_subtype) { if (ct > 0) { LightSetColorTemp(ct); } @@ -645,7 +726,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le boolean valid_entry = false; char scolor[25]; - if ((light_subtype > 1) && !strcasecmp_P(type, PSTR(D_CMND_COLOR)) && (index > 0) && (index <= 4)) { + if ((light_subtype > LST_SINGLE) && !strcasecmp_P(type, PSTR(D_CMND_COLOR)) && (index > 0) && (index <= 4)) { if (data_len > 0) { valid_entry = LightColorEntry(dataBuf, data_len); if (valid_entry) { @@ -657,7 +738,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le LightSetColor(); coldim = true; } else { // Color2, 3 and 4 - for (byte i = 0; i < 3; i++) { + for (byte i = 0; i < LST_RGB; i++) { Settings.ws_color[index -2][i] = light_entry_color[i]; } } @@ -668,7 +749,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } if (index > 1) { scolor[0] = '\0'; - for (byte i = 0; i < 3; i++) { + for (byte i = 0; i < LST_RGB; i++) { if (Settings.flag.decimal_text) { snprintf_P(scolor, 25, PSTR("%s%s%d"), scolor, (i > 0) ? "," : "", Settings.ws_color[index -2][i]); } else { @@ -679,7 +760,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } } #ifdef USE_WS2812 // *********************************************************************** - else if ((11 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_LED)) && (index > 0) && (index <= Settings.led_pixels)) { + else if ((LT_WS2812 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_LED)) && (index > 0) && (index <= Settings.led_pixels)) { if (data_len > 0) { if (LightColorEntry(dataBuf, data_len)) { Ws2812SetColor(index, light_entry_color[0], light_entry_color[1], light_entry_color[2]); @@ -687,7 +768,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_LED "%d\":\"%s\"}"), index, Ws2812GetColor(index, scolor)); } - else if ((11 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_PIXELS))) { + else if ((LT_WS2812 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_PIXELS))) { if ((payload > 0) && (payload <= WS2812_MAX_LEDS)) { Settings.led_pixels = payload; Ws2812Clear(); @@ -695,7 +776,7 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_PIXELS "\":%d}"), Settings.led_pixels); } - else if ((11 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_WIDTH)) && (index > 0) && (index <= 4)) { + else if ((LT_WS2812 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_WIDTH)) && (index > 0) && (index <= 4)) { if (1 == index) { if ((payload >= 0) && (payload <= 4)) { Settings.led_width = payload; @@ -708,25 +789,32 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WIDTH "%d\":%d}"), index, Settings.ws_width[index -2]); } } - else if ((11 == light_type) && !strcasecmp_P(type, PSTR(D_CMND_SCHEME))) { - if ((payload >= 0) && (payload <= 9)) { +#endif // USE_WS2812 ************************************************************************ + else if (!strcasecmp_P(type, PSTR(D_CMND_SCHEME))) { + uint8_t max_scheme = LS_WAKEUP; + if (light_subtype >= LST_RGB) { + max_scheme = LS_MAX -1; + } + if (LT_WS2812 == light_type) { + max_scheme += 8; + } + if ((payload >= 0) && (payload <= max_scheme)) { Settings.led_scheme = payload; - if (1 == Settings.led_scheme) { + if (LS_WAKEUP == Settings.led_scheme) { light_wakeup_active = 3; } - ExecuteCommandPower(devices_present, 1); + LightPowerOn(); strip_timer_counter = 0; } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_SCHEME "\":%d}"), Settings.led_scheme); } -#endif // USE_WS2812 ************************************************************************ else if (!strcasecmp_P(type, PSTR(D_CMND_WAKEUP))) { if ((payload >= 0) && (payload <= 100)) { Settings.led_dimmer = payload; } light_wakeup_active = 3; - Settings.led_scheme = 1; - ExecuteCommandPower(devices_present, 1); + Settings.led_scheme = LS_WAKEUP; + LightPowerOn(); snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_WAKEUP "\":\"" D_STARTED "\"}")); } else if (!strcasecmp_P(type, PSTR(D_CMND_COLORTEMPERATURE)) && ((2 == light_subtype) || (5 == light_subtype))) { // ColorTemp @@ -772,8 +860,8 @@ boolean LightCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_le } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_FADE "\":\"%s\"}"), GetStateText(Settings.led_fade)); } - else if (!strcasecmp_P(type, PSTR(D_CMND_SPEED))) { // 1 - fast, 8 - slow - if ((payload > 0) && (payload <= 8)) { + else if (!strcasecmp_P(type, PSTR(D_CMND_SPEED))) { // 1 - fast, 20 - very slow + if ((payload > 0) && (payload <= STATES)) { Settings.led_speed = payload; } snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_SPEED "\":%d}"), Settings.led_speed); diff --git a/sonoff/xdrv_wemohue.ino b/sonoff/xdrv_wemohue.ino index d5a2fbd92..73b8d4f3a 100755 --- a/sonoff/xdrv_wemohue.ino +++ b/sonoff/xdrv_wemohue.ino @@ -40,12 +40,12 @@ const char WEMO_MSEARCH[] PROGMEM = "CACHE-CONTROL: max-age=86400\r\n" "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" "EXT:\r\n" - "LOCATION: http://{r1}:80/setup.xml\r\n" + "LOCATION: http://{r1:80/setup.xml\r\n" "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" "ST: urn:Belkin:device:**\r\n" - "USN: uuid:{r2}::urn:Belkin:device:**\r\n" + "USN: uuid:{r2::urn:Belkin:device:**\r\n" "X-User-Agent: redsonic\r\n" "\r\n"; @@ -71,8 +71,8 @@ void WemoRespondToMSearch() if (PortUdp.beginPacket(PortUdp.remoteIP(), PortUdp.remotePort())) { String response = FPSTR(WEMO_MSEARCH); - response.replace("{r1}", WiFi.localIP().toString()); - response.replace("{r2}", WemoUuid()); + response.replace("{r1", WiFi.localIP().toString()); + response.replace("{r2", WemoUuid()); PortUdp.write(response.c_str()); PortUdp.endPacket(); snprintf_P(message, sizeof(message), PSTR(D_RESPONSE_SENT)); @@ -97,20 +97,20 @@ const char HUE_RESPONSE[] PROGMEM = "HOST: 239.255.255.250:1900\r\n" "CACHE-CONTROL: max-age=100\r\n" "EXT:\r\n" - "LOCATION: http://{r1}:80/description.xml\r\n" + "LOCATION: http://{r1:80/description.xml\r\n" "SERVER: Linux/3.14.0 UPnP/1.0 IpBridge/1.17.0\r\n" - "hue-bridgeid: {r2}\r\n"; + "hue-bridgeid: {r2\r\n"; const char HUE_ST1[] PROGMEM = "ST: upnp:rootdevice\r\n" - "USN: uuid:{r3}::upnp:rootdevice\r\n" + "USN: uuid:{r3::upnp:rootdevice\r\n" "\r\n"; const char HUE_ST2[] PROGMEM = - "ST: uuid:{r3}\r\n" - "USN: uuid:{r3}\r\n" + "ST: uuid:{r3\r\n" + "USN: uuid:{r3\r\n" "\r\n"; const char HUE_ST3[] PROGMEM = "ST: urn:schemas-upnp-org:device:basic:1\r\n" - "USN: uuid:{r3}\r\n" + "USN: uuid:{r3\r\n" "\r\n"; String HueBridgeId() @@ -142,24 +142,24 @@ void HueRespondToMSearch() if (PortUdp.beginPacket(PortUdp.remoteIP(), PortUdp.remotePort())) { String response1 = FPSTR(HUE_RESPONSE); - response1.replace("{r1}", WiFi.localIP().toString()); - response1.replace("{r2}", HueBridgeId()); + response1.replace("{r1", WiFi.localIP().toString()); + response1.replace("{r2", HueBridgeId()); String response = response1; response += FPSTR(HUE_ST1); - response.replace("{r3}", HueUuid()); + response.replace("{r3", HueUuid()); PortUdp.write(response.c_str()); PortUdp.endPacket(); response = response1; response += FPSTR(HUE_ST2); - response.replace("{r3}", HueUuid()); + response.replace("{r3", HueUuid()); PortUdp.write(response.c_str()); PortUdp.endPacket(); response = response1; response += FPSTR(HUE_ST3); - response.replace("{r3}", HueUuid()); + response.replace("{r3", HueUuid()); PortUdp.write(response.c_str()); PortUdp.endPacket(); @@ -273,12 +273,12 @@ const char WEMO_SETUP_XML[] PROGMEM = "" "" "urn:Belkin:device:controllee:1" - "{x1}" + "{x1" "Belkin International Inc." "Sonoff Socket" "3.1415" - "uuid:{x2}" - "{x3}" + "uuid:{x2" + "{x3" "0" "" "" @@ -321,9 +321,9 @@ void HandleUpnpSetupWemo() AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_WEMO_SETUP)); String setup_xml = FPSTR(WEMO_SETUP_XML); - setup_xml.replace("{x1}", Settings.friendlyname[0]); - setup_xml.replace("{x2}", WemoUuid()); - setup_xml.replace("{x3}", WemoSerialnumber()); + setup_xml.replace("{x1", Settings.friendlyname[0]); + setup_xml.replace("{x2", WemoUuid()); + setup_xml.replace("{x3", WemoSerialnumber()); WebServer->send(200, FPSTR(HDR_CTYPE_XML), setup_xml); } @@ -338,18 +338,18 @@ const char HUE_DESCRIPTION_XML[] PROGMEM = "1" "0" "" -// "http://{x1}/" - "http://{x1}:80/" +// "http://{x1/" + "http://{x1:80/" "" "urn:schemas-upnp-org:device:Basic:1" - "Amazon-Echo-HA-Bridge ({x1})" -// "Philips hue ({x1})" + "Amazon-Echo-HA-Bridge ({x1)" +// "Philips hue ({x1)" "Royal Philips Electronics" "Philips hue Personal Wireless Lighting" "Philips hue bridge 2012" "929000226503" - "{x3}" - "uuid:{x2}" + "{x3" + "uuid:{x2" "" "\r\n" "\r\n"; @@ -366,31 +366,31 @@ const char HueLightStatus_JSON[] PROGMEM = "\"reachable\":true"; const char HUE_LIGHTS_STATUS_JSON[] PROGMEM = "\"type\":\"Extended color light\"," - "\"name\":\"{j1}\"," + "\"name\":\"{j1\"," "\"modelid\":\"LCT007\"," - "\"uniqueid\":\"{j2}\"," + "\"uniqueid\":\"{j2\"," "\"swversion\":\"5.50.1.19085\"" "}"; const char HUE_GROUP0_STATUS_JSON[] PROGMEM = "{\"name\":\"Group 0\"," - "\"lights\":[{l1}]," + "\"lights\":[{l1]," "\"type\":\"LightGroup\"," "\"action\":{"; // "\"scene\":\"none\","; const char HueConfigResponse_JSON[] PROGMEM = "{\"name\":\"Philips hue\"," - "\"mac\":\"{mac}\"," + "\"mac\":\"{ma\"," "\"dhcp\":true," - "\"ipaddress\":\"{ip}\"," - "\"netmask\":\"{mask}\"," - "\"gateway\":\"{gw}\"," + "\"ipaddress\":\"{ip\"," + "\"netmask\":\"{ms\"," + "\"gateway\":\"{gw\"," "\"proxyaddress\":\"none\"," "\"proxyport\":0," - "\"bridgeid\":\"{bid}\"," - "\"UTC\":\"{dt}\"," - "\"whitelist\":{\"{id}\":{" - "\"last use date\":\"{dt}\"," - "\"create date\":\"{dt}\"," + "\"bridgeid\":\"{br\"," + "\"UTC\":\"{dt\"," + "\"whitelist\":{\"{id\":{" + "\"last use date\":\"{dt\"," + "\"create date\":\"{dt\"," "\"name\":\"Remote\"}}," "\"swversion\":\"01039019\"," "\"apiversion\":\"1.17.0\"," @@ -399,7 +399,7 @@ const char HueConfigResponse_JSON[] PROGMEM = "\"portalservices\":false" "}"; const char HUE_LIGHT_RESPONSE_JSON[] PROGMEM = - "{\"success\":{\"/lights/{id}/state/{cmd}\":{res}}}"; + "{\"success\":{\"/lights/{id/state/{cm\":{re}}"; const char HUE_ERROR_JSON[] PROGMEM = "[{\"error\":{\"type\":901,\"address\":\"/\",\"description\":\"Internal Error\"}}]"; @@ -424,9 +424,9 @@ void HandleUpnpSetupHue() { AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, PSTR(D_HUE_BRIDGE_SETUP)); String description_xml = FPSTR(HUE_DESCRIPTION_XML); - description_xml.replace("{x1}", WiFi.localIP().toString()); - description_xml.replace("{x2}", HueUuid()); - description_xml.replace("{x3}", HueSerialnumber()); + description_xml.replace("{x1", WiFi.localIP().toString()); + description_xml.replace("{x2", HueUuid()); + description_xml.replace("{x3", HueSerialnumber()); WebServer->send(200, FPSTR(HDR_CTYPE_XML), description_xml); } @@ -441,13 +441,13 @@ void HueNotImplemented(String *path) void HueConfigResponse(String *response) { *response += FPSTR(HueConfigResponse_JSON); - response->replace("{mac}", WiFi.macAddress()); - response->replace("{ip}", WiFi.localIP().toString()); - response->replace("{mask}", WiFi.subnetMask().toString()); - response->replace("{gw}", WiFi.gatewayIP().toString()); - response->replace("{bid}", HueBridgeId()); - response->replace("{dt}", GetUtcDateAndTime()); - response->replace("{id}", GetHueUserId()); + response->replace("{ma", WiFi.macAddress()); + response->replace("{ip", WiFi.localIP().toString()); + response->replace("{ms", WiFi.subnetMask().toString()); + response->replace("{gw", WiFi.gatewayIP().toString()); + response->replace("{br", HueBridgeId()); + response->replace("{dt", GetUtcDateAndTime()); + response->replace("{id", GetHueUserId()); } void HueConfig(String *path) @@ -484,8 +484,8 @@ void HueGlobalConfig(String *path) HueLightStatus(i, &response); response += "},"; response += FPSTR(HUE_LIGHTS_STATUS_JSON); - response.replace("{j1}", Settings.friendlyname[i-1]); - response.replace("{j2}", GetHueDeviceId(i)); + response.replace("{j1", Settings.friendlyname[i-1]); + response.replace("{j2", GetHueDeviceId(i)); if (i < maxhue) { response += ",\""; } @@ -532,8 +532,8 @@ void HueLights(String *path) HueLightStatus(i, &response); response += "},"; response += FPSTR(HUE_LIGHTS_STATUS_JSON); - response.replace("{j1}", Settings.friendlyname[i-1]); - response.replace("{j2}", GetHueDeviceId(i)); + response.replace("{j1", Settings.friendlyname[i-1]); + response.replace("{j2", GetHueDeviceId(i)); if (i < maxhue) { response += ",\""; } @@ -556,19 +556,19 @@ void HueLights(String *path) if (hue_json.containsKey("on")) { response += FPSTR(HUE_LIGHT_RESPONSE_JSON); - response.replace("{id}", String(device)); - response.replace("{cmd}", "on"); + response.replace("{id", String(device)); + response.replace("{cm", "on"); on = hue_json["on"]; switch(on) { case false : ExecuteCommandPower(device, 0); - response.replace("{res}", "false"); + response.replace("{re", "false"); break; case true : ExecuteCommandPower(device, 1); - response.replace("{res}", "true"); + response.replace("{re", "true"); break; - default : response.replace("{res}", (power & (1 << (device-1))) ? "true" : "false"); + default : response.replace("{re", (power & (1 << (device-1))) ? "true" : "false"); break; } resp = true; @@ -585,9 +585,9 @@ void HueLights(String *path) response += ","; } response += FPSTR(HUE_LIGHT_RESPONSE_JSON); - response.replace("{id}", String(device)); - response.replace("{cmd}", "bri"); - response.replace("{res}", String(tmp)); + response.replace("{id", String(device)); + response.replace("{cm", "bri"); + response.replace("{re", String(tmp)); resp = true; change = true; } @@ -598,9 +598,9 @@ void HueLights(String *path) response += ","; } response += FPSTR(HUE_LIGHT_RESPONSE_JSON); - response.replace("{id}", String(device)); - response.replace("{cmd}", "hue"); - response.replace("{res}", String(tmp)); + response.replace("{id", String(device)); + response.replace("{cm", "hue"); + response.replace("{re", String(tmp)); resp = true; change = true; } @@ -611,9 +611,9 @@ void HueLights(String *path) response += ","; } response += FPSTR(HUE_LIGHT_RESPONSE_JSON); - response.replace("{id}", String(device)); - response.replace("{cmd}", "sat"); - response.replace("{res}", String(tmp)); + response.replace("{id", String(device)); + response.replace("{cm", "sat"); + response.replace("{re", String(tmp)); change = true; } if (hue_json.containsKey("ct")) { // Color temperature 153 (Cold) to 500 (Warm) @@ -622,9 +622,9 @@ void HueLights(String *path) response += ","; } response += FPSTR(HUE_LIGHT_RESPONSE_JSON); - response.replace("{id}", String(device)); - response.replace("{cmd}", "ct"); - response.replace("{res}", String(ct)); + response.replace("{id", String(device)); + response.replace("{cm", "ct"); + response.replace("{re", String(ct)); change = true; } if (change) { @@ -654,8 +654,8 @@ void HueLights(String *path) HueLightStatus(device, &response); response += "},"; response += FPSTR(HUE_LIGHTS_STATUS_JSON); - response.replace("{j1}", Settings.friendlyname[device-1]); - response.replace("{j2}", GetHueDeviceId(device)); + response.replace("{j1", Settings.friendlyname[device-1]); + response.replace("{j2", GetHueDeviceId(device)); WebServer->send(200, FPSTR(HDR_CTYPE_JSON), response); } else { @@ -677,7 +677,7 @@ void HueGroups(String *path) for (uint8_t i = 2; i <= maxhue; i++) { lights += ",\"" + String(i) + "\""; } - response.replace("{l1}", lights); + response.replace("{l1", lights); HueLightStatus(1, &response); response += F("}}"); } diff --git a/sonoff/xdrv_ws2812.ino b/sonoff/xdrv_ws2812.ino index 8366411f6..cfa5ea3f0 100644 --- a/sonoff/xdrv_ws2812.ino +++ b/sonoff/xdrv_ws2812.ino @@ -75,16 +75,6 @@ uint8_t kRepeat[5] = { 4, // Large 2, // Largest 1 }; // All -uint8_t kSpeed[9] = { - 0, // None - 1 * (STATES / 10), // Fastest - 3 * (STATES / 10), - 5 * (STATES / 10), // Fast - 7 * (STATES / 10), - 9 * (STATES / 10), - 11 * (STATES / 10), // Slow - 13 * (STATES / 10), - 15 * (STATES / 10) }; // Slowest uint8_t ws_show_next = 1; @@ -195,7 +185,8 @@ void Ws2812Gradient(uint8_t schemenr) uint8_t repeat = kRepeat[Settings.led_width]; // number of scheme.count per ledcount uint16_t range = (uint16_t)ceil((float)Settings.led_pixels / (float)repeat); uint16_t gradRange = (uint16_t)ceil((float)range / (float)(scheme.count - 1)); - uint16_t offset = kSpeed[Settings.led_speed] > 0 ? strip_timer_counter / kSpeed[Settings.led_speed] : 0; + uint16_t speed = ((Settings.led_speed * 2) -1) * (STATES / 10); + uint16_t offset = speed > 0 ? strip_timer_counter / speed : 0; WsColor oldColor, currentColor; Ws2812GradientColor(schemenr, &oldColor, range, gradRange, offset); @@ -206,9 +197,9 @@ void Ws2812Gradient(uint8_t schemenr) } if (Settings.led_speed > 0) { // Blend old and current color based on time for smooth movement. - c.R = map(strip_timer_counter % kSpeed[Settings.led_speed], 0, kSpeed[Settings.led_speed], oldColor.red, currentColor.red); - c.G = map(strip_timer_counter % kSpeed[Settings.led_speed], 0, kSpeed[Settings.led_speed], oldColor.green, currentColor.green); - c.B = map(strip_timer_counter % kSpeed[Settings.led_speed], 0, kSpeed[Settings.led_speed], oldColor.blue, currentColor.blue); + c.R = map(strip_timer_counter % speed, 0, speed, oldColor.red, currentColor.red); + c.G = map(strip_timer_counter % speed, 0, speed, oldColor.green, currentColor.green); + c.B = map(strip_timer_counter % speed, 0, speed, oldColor.blue, currentColor.blue); } else { // No animation, just use the current color. @@ -239,7 +230,8 @@ void Ws2812Bars(uint8_t schemenr) maxSize = 0; } - uint8_t offset = kSpeed[Settings.led_speed] > 0 ? strip_timer_counter / kSpeed[Settings.led_speed] : 0; + uint16_t speed = ((Settings.led_speed * 2) -1) * (STATES / 10); + uint8_t offset = speed > 0 ? strip_timer_counter / speed : 0; WsColor mcolor[scheme.count]; memcpy(mcolor, scheme.colors, sizeof(mcolor)); diff --git a/sonoff/xsns_veml6070.ino b/sonoff/xsns_veml6070.ino new file mode 100644 index 000000000..0a62a7737 --- /dev/null +++ b/sonoff/xsns_veml6070.ino @@ -0,0 +1,113 @@ +/* + xsns_veml6070.ino - VEML6070 ultra violet light sensor support for Sonoff-Tasmota + + Copyright (C) 2017 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_VEML6070 +/*********************************************************************************************\ + * VEML6070 - Ultra Violet Light Intensity +\*********************************************************************************************/ + +#define VEML6070_ADDR_H 0x39 +#define VEML6070_ADDR_L 0x38 + +#define VEML6070_INTEGRATION_TIME 3 // 500msec integration time + +uint8_t veml6070_address; +uint8_t veml6070_type = 0; +char veml6070_types[9]; + +uint16_t Veml6070ReadUv() +{ + if (Wire.requestFrom(VEML6070_ADDR_H, 1) != 1) { + return -1; + } + uint16_t uvi = Wire.read(); + uvi <<= 8; + if (Wire.requestFrom(VEML6070_ADDR_L, 1) != 1) { + return -1; + } + uvi |= Wire.read(); + + return uvi; +} + +boolean Veml6070Detect() +{ + if (veml6070_type) { + return true; + } + + uint8_t status; + uint8_t itime = VEML6070_INTEGRATION_TIME; + boolean success = false; + + veml6070_address = VEML6070_ADDR_L; + Wire.beginTransmission(veml6070_address); + Wire.write((itime << 2) | 0x02); + status = Wire.endTransmission(); + if (!status) { + success = true; + veml6070_type = 1; + strcpy_P(veml6070_types, PSTR("VEML6070")); + } + if (success) { + snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_I2C "%s " D_FOUND_AT " 0x%x"), veml6070_types, veml6070_address); + AddLog(LOG_LEVEL_DEBUG); + } else { + veml6070_type = 0; + } + return success; +} + +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +void MqttShowVeml6070(uint8_t* djson) +{ + if (!veml6070_type) { + return; + } + + uint16_t uv = Veml6070ReadUv(); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s, \"%s\":{\"" D_UV_LEVEL "\":%d}"), mqtt_data, veml6070_types, uv); + *djson = 1; +#ifdef USE_DOMOTICZ + DomoticzSensor(DZ_ILLUMINANCE, uv); +#endif // USE_DOMOTICZ +} + +#ifdef USE_WEBSERVER +const char HTTP_SNS_ULTRAVIOLET[] PROGMEM = + "VEML6070 " D_UV_LEVEL "%d"; + +String WebShowVeml6070() +{ + String page = ""; + if (veml6070_type) { + char sensor[80]; + snprintf_P(sensor, sizeof(sensor), HTTP_SNS_ULTRAVIOLET, Veml6070ReadUv()); + page += sensor; + } + return page; +} +#endif // USE_WEBSERVER +#endif // USE_VEML6070 +#endif // USE_I2C +