diff --git a/README.md b/README.md index dda9b6227..579263ec5 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,8 @@ People helping to keep the show on the road: - Andre Thomas for providing [thehackbox](http://thehackbox.org/tasmota/) OTA support and daily development builds - Joel Stein and digiblur for their Tuya research and driver - Frogmore42 and Jason2866 for providing many issue answers -- Many more providing Tips, Pocs or PRs +- Blakadder for editing the wiki and providing template management +- Many more providing Tips, Wips, Pocs or PRs ### License diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index d3b6fa238..0214da3cd 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.4.1.19 20190222 * Add command SetOption37 for RGBCW color mapping (#5326) * Add Korean language translations (#5344) + * Fix Energy TotalStartTime when commands EnergyReset0 and/or EnergyReset3 used (#5373) * * 6.4.1.18 20190221 * Fix some exceptions and watchdogs due to lack of stack space - part 1 (#5215) diff --git a/sonoff/settings.h b/sonoff/settings.h index 447db10c0..342ff1612 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -25,54 +25,54 @@ typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption struct { // SetOption0 .. SetOption31 - uint32_t save_state : 1; // bit 0 - uint32_t button_restrict : 1; // bit 1 - uint32_t value_units : 1; // bit 2 - uint32_t mqtt_enabled : 1; // bit 3 - uint32_t mqtt_response : 1; // bit 4 - uint32_t mqtt_power_retain : 1; // CMND_POWERRETAIN - uint32_t mqtt_button_retain : 1; // CMND_BUTTONRETAIN - uint32_t mqtt_switch_retain : 1; // CMND_SWITCHRETAIN - uint32_t temperature_conversion : 1; // bit 8 - uint32_t mqtt_sensor_retain : 1; // CMND_SENSORRETAIN - uint32_t mqtt_offline : 1; // bit 10 - uint32_t button_swap : 1; // bit 11 (v5.1.6) - uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - uint32_t button_single : 1; // bit 13 (v5.4.0) - uint32_t interlock : 1; // bit 14 (v5.6.0) - uint32_t pwm_control : 1; // bit 15 (v5.8.1) - uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - uint32_t decimal_text : 1; // bit 17 (v5.8.1) - uint32_t light_signal : 1; // bit 18 (v5.10.0c) - uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - uint32_t mqtt_serial_raw : 1; // bit 23 (v6.1.1c) // Was rules_enabled until 5.14.0b - uint32_t pressure_conversion : 1; // bit 24 (v6.3.0.2) // Was rules_once until 5.14.0b - uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) KNX - uint32_t device_index_enable : 1; // bit 26 (v5.13.1a) - uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) KNX - uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a) - uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a) - uint32_t hass_light : 1; // bit 30 (v6.0.0b) - uint32_t global_state : 1; // bit 31 (v6.1.0) + uint32_t save_state : 1; // bit 0 - SetOption0 - Save power state and use after restart + uint32_t button_restrict : 1; // bit 1 - SetOption1 - Control button multipress + uint32_t value_units : 1; // bit 2 - SetOption2 - Add units to JSON status messages + uint32_t mqtt_enabled : 1; // bit 3 - SetOption3 - Control MQTT + uint32_t mqtt_response : 1; // bit 4 - SetOption4 - Switch between MQTT RESULT or COMMAND + uint32_t mqtt_power_retain : 1; // bit 5 - CMND_POWERRETAIN + uint32_t mqtt_button_retain : 1; // bit 6 - CMND_BUTTONRETAIN + uint32_t mqtt_switch_retain : 1; // bit 7 - CMND_SWITCHRETAIN + uint32_t temperature_conversion : 1; // bit 8 - SetOption8 - Switch between Celsius or Fahrenheit + uint32_t mqtt_sensor_retain : 1; // bit 9 - CMND_SENSORRETAIN + uint32_t mqtt_offline : 1; // bit 10 - SetOption10 - Control MQTT LWT message format + uint32_t button_swap : 1; // bit 11 (v5.1.6) - SetOption11 - Swap button single and double press functionality + uint32_t stop_flash_rotate : 1; // bit 12 (v5.2.0) - SetOption12 - Switch between dynamic or fixed slot flash save location + uint32_t button_single : 1; // bit 13 (v5.4.0) - SetOption13 - Support only single press to speed up button press recognition + uint32_t interlock : 1; // bit 14 (v5.6.0) - CMND_INTERLOCK + uint32_t pwm_control : 1; // bit 15 (v5.8.1) - SetOption15 - Switch between commands PWM or COLOR/DIMMER/CT/CHANNEL + uint32_t ws_clock_reverse : 1; // bit 16 (v5.8.1) - SetOption16 - Switch between clockwise or counter-clockwise + uint32_t decimal_text : 1; // bit 17 (v5.8.1) - SetOption17 - Switch between decimal or hexadecimal output + uint32_t light_signal : 1; // bit 18 (v5.10.0c) - SetOption18 - Pair light signal with CO2 sensor + uint32_t hass_discovery : 1; // bit 19 (v5.11.1a) - SetOption19 - Control Home Assistantautomatic discovery (See SetOption59) + uint32_t not_power_linked : 1; // bit 20 (v5.11.1f) - SetOption20 - Control power in relation to Dimmer/Color/Ct changes + uint32_t no_power_on_check : 1; // bit 21 (v5.11.1i) - SetOption21 - Show voltage even if powered off + uint32_t mqtt_serial : 1; // bit 22 (v5.12.0f) - CMND_SERIALSEND and CMND_SERIALLOG + uint32_t mqtt_serial_raw : 1; // bit 23 (v6.1.1c) - CMND_SERIALSEND3 + uint32_t pressure_conversion : 1; // bit 24 (v6.3.0.2) - SetOption24 - Switch between hPa or mmHg pressure unit + uint32_t knx_enabled : 1; // bit 25 (v5.12.0l) - CMND_KNX_ENABLED + uint32_t device_index_enable : 1; // bit 26 (v5.13.1a) - SetOption26 - Switch between POWER or POWER1 + uint32_t knx_enable_enhancement : 1; // bit 27 (v5.14.0a) - CMND_KNX_ENHANCED + uint32_t rf_receive_decimal : 1; // bit 28 (v6.0.0a) - SetOption28 - RF receive data format + uint32_t ir_receive_decimal : 1; // bit 29 (v6.0.0a) - SetOption29 - IR receive data format + uint32_t hass_light : 1; // bit 30 (v6.0.0b) - SetOption30 - Enforce HAss autodiscovery as light + uint32_t global_state : 1; // bit 31 (v6.1.0) - SetOption31 - Control link led blinking }; } SysBitfield; typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... uint32_t data; // Allow bit manipulation using SetOption struct { // SetOption50 .. SetOption81 - uint32_t timers_enable : 1; // bit 0 (v6.1.1b) - uint32_t user_esp8285_enable : 1; // bit 1 (v6.1.1.14) - uint32_t time_append_timezone : 1; // bit 2 (v6.2.1.2) - uint32_t gui_hostname_ip : 1; // bit 3 (v6.2.1.20) - uint32_t tuya_apply_o20 : 1; // bit 4 (v6.3.0.4) - uint32_t mdns_enabled : 1; // bit 5 (v6.4.1.4) - SetOption55 - uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10) - uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10) - uint32_t receive_raw : 1; // bit 8 (v6.3.0.11) - uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13) + uint32_t timers_enable : 1; // bit 0 (v6.1.1b) - CMND_TIMERS + uint32_t user_esp8285_enable : 1; // bit 1 (v6.1.1.14) - SetOption51 - Enable ESP8285 user GPIO's + uint32_t time_append_timezone : 1; // bit 2 (v6.2.1.2) - SetOption52 - Append timezone to JSON time + uint32_t gui_hostname_ip : 1; // bit 3 (v6.2.1.20) - SetOption53 - Show hostanme and IP address in GUI main menu + uint32_t tuya_apply_o20 : 1; // bit 4 (v6.3.0.4) - SetOption54 - Apply SetOption20 settings to Tuya device + uint32_t mdns_enabled : 1; // bit 5 (v6.4.1.4) - SetOption55 - Control mDNS service + uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10) - SetOption56 - Scan wifi network at restart for configured AP's + uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10) - SetOption57 - Scan wifi network every 44 minutes for configured AP's + uint32_t receive_raw : 1; // bit 8 (v6.3.0.11) - SetOption58 - Add IR Raw data to JSON message + uint32_t hass_tele_on_power : 1; // bit 9 (v6.3.0.13) - SetOption59 - Send tele/%topic%/STATE in addition to stat/%topic%/RESULT uint32_t sleep_normal : 1; // bit 10 (v6.3.0.15) - SetOption60 - Enable normal sleep instead of dynamic sleep uint32_t button_switch_force_local : 1;// bit 11 (v6.3.0.16) - SetOption61 - Force local operation when button/switch topic is set uint32_t no_hold_retain : 1; // bit 12 (v6.4.1.19) - SetOption62 - Don't use retain flag on HOLD messages diff --git a/sonoff/support_rtc.ino b/sonoff/support_rtc.ino index 35f9b61e9..e66eda691 100644 --- a/sonoff/support_rtc.ino +++ b/sonoff/support_rtc.ino @@ -43,7 +43,7 @@ uint32_t local_time = 0; uint32_t daylight_saving_time = 0; uint32_t standard_time = 0; uint32_t ntp_time = 0; -uint32_t midnight = 1451602800; +uint32_t midnight = 0; uint32_t restart_time = 0; int32_t time_timezone = 0; uint8_t midnight_now = 0; @@ -406,10 +406,17 @@ void RtcSecond(void) if (!Settings.energy_kWhtotal_time) { Settings.energy_kWhtotal_time = local_time; } } BreakTime(local_time, RtcTime); - if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second && RtcTime.valid) { - midnight = local_time; - midnight_now = 1; + + if (RtcTime.valid) { + if (!midnight) { + midnight = local_time - (RtcTime.hour * 3600) - (RtcTime.minute * 60) - RtcTime.second; + } + if (!RtcTime.hour && !RtcTime.minute && !RtcTime.second) { + midnight = local_time; + midnight_now = 1; + } } + RtcTime.year += 1970; } diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index a9fe9161c..6070d8ac8 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -76,7 +76,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "a=p;" "clearTimeout(lt);" "}" - "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "if(x!=null){x.abort();}" // Abort if no response within Settings.web_refresh milliseconds (happens on restart 1) "x=new XMLHttpRequest();" "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" @@ -84,15 +84,15 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "eb('l1').innerHTML=s;" "}" "};" - "x.open('GET','ay'+a,true);" + "x.open('GET','?m=1'+a,true);" // ?m related to WebServer->hasArg("m") "x.send();" "lt=setTimeout(la,{a});" // Settings.web_refresh "}" "function lb(p){" - "la('?d='+p);" // ?d related to WebGetArg("d", tmp, sizeof(tmp)); + "la('&d='+p);" // &d related to WebGetArg("d", tmp, sizeof(tmp)); "}" "function lc(p){" - "la('?t='+p);" // ?t related to WebGetArg("t", tmp, sizeof(tmp)); + "la('&t='+p);" // &t related to WebGetArg("t", tmp, sizeof(tmp)); "}" "window.onload=la();"; @@ -140,14 +140,13 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "sn=t.scrollTop;" "}" "};" - "x.open('GET','ax?c2='+id+o,true);" + "x.open('GET','cs?c2='+id+o,true);" // Related to WebServer->hasArg("c2") and WebGetArg("c2", stmp, sizeof(stmp)) "x.send();" "}" "lt=setTimeout(l,{a});" "return false;" "}" - "window.onload=l;" - ""; + "window.onload=l;"; const char HTTP_MODULE_TEMPLATE_REPLACE[] PROGMEM = "\2%d'>%s (%d\3"; // \2 and \3 are used in below os.replace @@ -432,7 +431,7 @@ const char HTTP_END[] PROGMEM = "" ""; -const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; // ?o is related to WebGetArg("o", tmp, sizeof(tmp)); +const char HTTP_DEVICE_CONTROL[] PROGMEM = ""; // ?o is related to WebGetArg("o", tmp, sizeof(tmp)); const char HTTP_DEVICE_STATE[] PROGMEM = "%s%s"; // {c} = %'>
"); - if (devices_present) { - if (light_type) { - if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER1, LightGetColorTemp()); - page += mqtt_data; - } - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER2, Settings.light_dimmer); + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_MAIN_MENU); + + char stemp[5]; + + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_MAIN_MENU)); + page += FPSTR(HTTP_SCRIPT_ROOT); + page += FPSTR(HTTP_HEAD_STYLE); + + page += F("
"); + if (devices_present) { + if (light_type) { + if ((LST_COLDWARM == (light_type &7)) || (LST_RGBWC == (light_type &7))) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER1, LightGetColorTemp()); page += mqtt_data; } - page += FPSTR(HTTP_TABLE100); - page += F(""); - if (SONOFF_IFAN02 == my_module_type) { - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_MSG_SLIDER2, Settings.light_dimmer); + page += mqtt_data; + } + page += FPSTR(HTTP_TABLE100); + page += F(""); + if (SONOFF_IFAN02 == my_module_type) { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 36, 1, D_BUTTON_TOGGLE, ""); + page += mqtt_data; + for (uint8_t i = 0; i < MAX_FAN_SPEED; i++) { + snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); page += mqtt_data; - for (uint8_t i = 0; i < MAX_FAN_SPEED; i++) { - snprintf_P(stemp, sizeof(stemp), PSTR("%d"), i); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, 16, i +2, stemp, ""); - page += mqtt_data; - } - } else { - for (uint8_t idx = 1; idx <= devices_present; idx++) { - snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); - snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, - 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); - page += mqtt_data; - } } - page += F(""); - } - if (SONOFF_BRIDGE == my_module_type) { - page += FPSTR(HTTP_TABLE100); - page += F(""); - uint8_t idx = 0; - for (uint8_t i = 0; i < 4; i++) { - if (idx > 0) { page += F(""); } - for (uint8_t j = 0; j < 4; j++) { - idx++; - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), idx, idx); // ?k is related to WebGetArg("k", tmp, sizeof(tmp)); - page += mqtt_data; - } + } else { + for (uint8_t idx = 1; idx <= devices_present; idx++) { + snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_DEVICE_CONTROL, + 100 / devices_present, idx, (devices_present < 5) ? D_BUTTON_TOGGLE : "", (devices_present > 1) ? stemp : ""); + page += mqtt_data; } - page += F(""); } + page += F(""); + } + if (SONOFF_BRIDGE == my_module_type) { + page += FPSTR(HTTP_TABLE100); + page += F(""); + uint8_t idx = 0; + for (uint8_t i = 0; i < 4; i++) { + if (idx > 0) { page += F(""); } + for (uint8_t j = 0; j < 4; j++) { + idx++; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), idx, idx); // ?k is related to WebGetArg("k", tmp, sizeof(tmp)); + page += mqtt_data; + } + } + page += F(""); + } #ifndef FIRMWARE_MINIMAL - mqtt_data[0] = '\0'; - XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); - XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); - page += String(mqtt_data); + mqtt_data[0] = '\0'; + XdrvCall(FUNC_WEB_ADD_MAIN_BUTTON); + XsnsCall(FUNC_WEB_ADD_MAIN_BUTTON); + page += String(mqtt_data); #endif // Not FIRMWARE_MINIMAL - if (HTTP_ADMIN == webserver_state) { - page += FPSTR(HTTP_BTN_MENU1); - page += FPSTR(HTTP_BTN_RSTRT); - } - ShowPage(page); + if (HTTP_ADMIN == webserver_state) { + page += FPSTR(HTTP_BTN_MENU1); + page += FPSTR(HTTP_BTN_RSTRT); } + ShowPage(page); } -void HandleAjaxStatusRefresh(void) +bool HandleRootStatusRefresh(void) { - if (!WebAuthenticate()) { return WebServer->requestAuthentication(); } + if (!WebAuthenticate()) { + WebServer->requestAuthentication(); + return true; + } + + if (!WebServer->hasArg("m")) { // Status refresh requested + return false; + } char tmp[8]; // WebGetArg numbers only char svalue[32]; // Command and number parameter @@ -865,6 +873,7 @@ void HandleAjaxStatusRefresh(void) snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s"), mqtt_data); } WSSend(200, CT_HTML, mqtt_data); + return true; } bool HttpCheckPriviledgedAccess(bool autorequestauth = true) @@ -2017,21 +2026,24 @@ void HandleConsole(void) { if (!HttpCheckPriviledgedAccess()) { return; } + if (WebServer->hasArg("c2")) { // Console refresh requested + HandleConsoleRefresh(); + return; + } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONSOLE); String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_CONSOLE)); + page += FPSTR(HTTP_SCRIPT_CONSOL); page += FPSTR(HTTP_HEAD_STYLE); - page.replace(F(""), FPSTR(HTTP_SCRIPT_CONSOL)); page += FPSTR(HTTP_FORM_CMND); page += FPSTR(HTTP_BTN_MAIN); ShowPage(page); } -void HandleAjaxConsoleRefresh(void) +void HandleConsoleRefresh(void) { - if (!HttpCheckPriviledgedAccess()) { return; } - bool cflg = true; uint8_t counter = 0; // Initial start, should never be 0 again diff --git a/sonoff/xdrv_03_energy.ino b/sonoff/xdrv_03_energy.ino index 62e445c91..850a5f2d0 100644 --- a/sonoff/xdrv_03_energy.ino +++ b/sonoff/xdrv_03_energy.ino @@ -395,6 +395,7 @@ bool EnergyCommand(void) Settings.energy_kWhtoday = energy_kWhtoday; RtcSettings.energy_kWhtoday = energy_kWhtoday; energy_daily = (float)energy_kWhtoday / 100000; + if (!RtcSettings.energy_kWhtotal && !energy_kWhtoday) { Settings.energy_kWhtotal_time = LocalTime(); } break; case 2: Settings.energy_kWhyesterday = lnum *100; @@ -403,7 +404,7 @@ bool EnergyCommand(void) RtcSettings.energy_kWhtotal = lnum *100; Settings.energy_kWhtotal = RtcSettings.energy_kWhtotal; energy_total = (float)(RtcSettings.energy_kWhtotal + energy_kWhtoday) / 100000; - if (!energy_total) { Settings.energy_kWhtotal_time = LocalTime(); } + Settings.energy_kWhtotal_time = (!energy_kWhtoday) ? LocalTime() : Midnight(); break; } }