4.0.0 20170303
* Add define to remove config migration code for versions below 3.0 (See
Wiki-Upgrade-Migration path)
* Free memory by switching from String to char[]
* Raised Sonoff Led PWM frequency from 200Hz to 432Hz in search of
stability (hardware watchdog timeouts) (#122)
* Increase message size and suggested minimum MQTT_MAX_PACKET_SIZE to
512 (#114, #124)
* Remove runtime warning message regarding MQTT_MAX_PACKET_SIZE too
small as it is now moved to compile time (#124)
* Fix possible panics with web console and http commands while UDP
syslog is active (#127)
* Add optional static IP address (#129)
* Add define ENERGY_RESOLUTION in user_config.h to allow user control
over precision (#136)
This commit is contained in:
arendst 2017-03-03 12:35:23 +01:00
parent 4a989fb8c6
commit acb5252b54
11 changed files with 126 additions and 83 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota ## 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. 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.22** - See ```sonoff/_releasenotes.ino``` for change information. Current version is **4.0.0** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - 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```. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.

Binary file not shown.

View File

@ -1,4 +1,14 @@
/* 3.9.22 20170228 /* 4.0.0 20170303
* Add define to remove config migration code for versions below 3.0 (See Wiki-Upgrade-Migration path)
* Free memory by switching from String to char[]
* Raised Sonoff Led PWM frequency from 200Hz to 432Hz in search of stability (hardware watchdog timeouts) (#122)
* Increase message size and suggested minimum MQTT_MAX_PACKET_SIZE to 512 (#114, #124)
* Remove runtime warning message regarding MQTT_MAX_PACKET_SIZE too small as it is now moved to compile time (#124)
* Fix possible panics with web console and http commands while UDP syslog is active (#127)
* Add optional static IP address (#129)
* Add define ENERGY_RESOLUTION in user_config.h to allow user control over precision (#136)
*
* 3.9.22 20170228
* Update web console * Update web console
* Fix Status 4 JSON message * Fix Status 4 JSON message
* Add Exception info during restart if available * Add Exception info during restart if available

View File

@ -2,6 +2,7 @@
* Config settings * Config settings
\*********************************************************************************************/ \*********************************************************************************************/
#ifdef ALLOW_MIGRATE_TO_V3
struct SYSCFG2 { // Version 2.x (old) struct SYSCFG2 { // Version 2.x (old)
unsigned long cfg_holder; unsigned long cfg_holder;
unsigned long saveFlag; unsigned long saveFlag;
@ -69,16 +70,17 @@ struct SYSCFG2 { // Version 2.x (old)
char sta_pwd2[65]; char sta_pwd2[65];
} sysCfg2; } sysCfg2;
#endif // ALLOW_MIGRATE_TO_V3
struct SYSCFG { struct SYSCFG {
unsigned long cfg_holder; unsigned long cfg_holder;
unsigned long saveFlag; unsigned long saveFlag;
unsigned long version; unsigned long version;
unsigned long bootcount; unsigned long bootcount;
byte migflg; byte migflg; // Not used since 3.9.1
int16_t savedata; int16_t savedata;
byte savestate; byte savestate;
byte model; byte model; // Not used since 3.9.1
int8_t timezone; int8_t timezone;
char otaUrl[101]; char otaUrl[101];
char ex_friendlyname[33]; // Not used since 3.2.5 - see below char ex_friendlyname[33]; // Not used since 3.2.5 - see below
@ -158,7 +160,7 @@ struct SYSCFG {
uint8_t ws_speed; uint8_t ws_speed;
uint8_t ws_scheme; uint8_t ws_scheme;
uint8_t ws_width; uint8_t ws_width;
uint16_t ws_wakeup; uint16_t ws_wakeup;
char friendlyname[4][33]; char friendlyname[4][33];
char switch_topic[33]; char switch_topic[33];

View File

@ -114,9 +114,11 @@ extern "C" {
#define SPIFFS_START ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE #define SPIFFS_START ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE
#define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE #define SPIFFS_END ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE
// Version 2.x config #ifdef ALLOW_MIGRATE_TO_V3
#define SPIFFS_CONFIG2 "/config.ini" // Version 2.x config
#define CFG_LOCATION2 SPIFFS_END - 2 #define SPIFFS_CONFIG2 "/config.ini"
#define CFG_LOCATION2 SPIFFS_END - 2
#endif // ALLOW_MIGRATE_TO_V3
// Version 3.x config // Version 3.x config
#define SPIFFS_CONFIG "/cfg.ini" #define SPIFFS_CONFIG "/cfg.ini"
@ -247,6 +249,7 @@ void CFG_Load()
addLog(LOG_LEVEL_DEBUG, log); addLog(LOG_LEVEL_DEBUG, log);
} }
} }
#ifdef ALLOW_MIGRATE_TO_V3
// snprintf_P(log, sizeof(log), PSTR("Config: Check 1 for migration (%08X)"), sysCfg.version); // snprintf_P(log, sizeof(log), PSTR("Config: Check 1 for migration (%08X)"), sysCfg.version);
// addLog(LOG_LEVEL_NONE, log); // addLog(LOG_LEVEL_NONE, log);
if (sysCfg.cfg_holder != CFG_HOLDER) { if (sysCfg.cfg_holder != CFG_HOLDER) {
@ -256,11 +259,15 @@ void CFG_Load()
CFG_Default(); CFG_Default();
} }
} }
#else
if (sysCfg.cfg_holder != CFG_HOLDER) CFG_Default();
#endif // ALLOW_MIGRATE_TO_V3
_cfgHash = getHash(); _cfgHash = getHash();
RTC_Load(); RTC_Load();
} }
#ifdef ALLOW_MIGRATE_TO_V3
void CFG_Migrate() void CFG_Migrate()
{ {
char log[LOGSZ]; char log[LOGSZ];
@ -304,6 +311,7 @@ void CFG_Migrate()
} }
_cfgHash = getHash(); _cfgHash = getHash();
} }
#endif // ALLOW_MIGRATE_TO_V3
void CFG_Erase() void CFG_Erase()
{ {
@ -532,6 +540,7 @@ void CFG_Default()
CFG_Save(); CFG_Save();
} }
#ifdef ALLOW_MIGRATE_TO_V3
void CFG_Migrate_Part2() void CFG_Migrate_Part2()
{ {
addLog_P(LOG_LEVEL_NONE, PSTR("Config: Migrating configuration")); addLog_P(LOG_LEVEL_NONE, PSTR("Config: Migrating configuration"));
@ -640,6 +649,7 @@ void CFG_Migrate_Part2()
} }
CFG_Save(); CFG_Save();
} }
#endif // ALLOW_MIGRATE_TO_V3
/********************************************************************************************/ /********************************************************************************************/

View File

@ -1,19 +1,21 @@
/* /*
* Sonoff and ElectroDragon by Theo Arends * Sonoff-Tasmota by Theo Arends
* *
* ==================================================== * ====================================================
* Prerequisites: * Prerequisites:
* - Change libraries/PubSubClient/src/PubSubClient.h * - Change libraries/PubSubClient/src/PubSubClient.h
* #define MQTT_MAX_PACKET_SIZE 400 * #define MQTT_MAX_PACKET_SIZE 512
* *
* - Select IDE Tools - Flash size: "1M (64K SPIFFS)" * - Select IDE Tools - Flash size: "1M (64K SPIFFS)"
* ==================================================== * ====================================================
*/ */
#define VERSION 0x03091600 // 3.9.22 //#define ALLOW_MIGRATE_TO_V3
#ifdef ALLOW_MIGRATE_TO_V3
//#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k) #define VERSION 0x03091700 // 3.9.23
// To be used as step 1. Next step is compile and use desired version #else
#define VERSION 0x04000000 // 4.0.0
#endif // ALLOW_MIGRATE_TO_V3
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
enum week_t {Last, First, Second, Third, Fourth}; enum week_t {Last, First, Second, Third, Fourth};
@ -34,6 +36,8 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
\*********************************************************************************************/ \*********************************************************************************************/
//#define USE_SPIFFS // Switch persistent configuration from flash to spiffs (+24k code, +0.6k mem) //#define USE_SPIFFS // Switch persistent configuration from flash to spiffs (+24k code, +0.6k mem)
//#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (-45k code, -2k mem)
// To be used as step 1. Next step is compile and use desired version
/*********************************************************************************************\ /*********************************************************************************************\
* No user configurable items below * No user configurable items below
@ -126,7 +130,6 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#define INPUT_BUFFER_SIZE 100 // Max number of characters in serial buffer #define INPUT_BUFFER_SIZE 100 // Max number of characters in serial buffer
#define TOPSZ 60 // Max number of characters in topic string #define TOPSZ 60 // Max number of characters in topic string
#define MESSZ 240 // Max number of characters in JSON message string
#define LOGSZ 128 // Max number of characters in log string #define LOGSZ 128 // Max number of characters in log string
#ifdef USE_MQTT_TLS #ifdef USE_MQTT_TLS
#define MAX_LOG_LINES 10 // Max number of lines in weblog #define MAX_LOG_LINES 10 // Max number of lines in weblog
@ -140,11 +143,18 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
enum butt_t {PRESSED, NOT_PRESSED}; enum butt_t {PRESSED, NOT_PRESSED};
#include "support.h" // Global support #include "support.h" // Global support
#include <PubSubClient.h> // MQTT
#define MESSZ 352 // Max number of characters in JSON message string
#if (MQTT_MAX_PACKET_SIZE -TOPSZ -60 -40) < MESSZ // If the max message size is too small, throw an error at compile time
// 60 bytes for the IPv4 TCP header, 40 bytes to keep the original 400/240 headroom
#error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 512"
#endif
#include <Ticker.h> // RTC #include <Ticker.h> // RTC
#include <ESP8266WiFi.h> // MQTT, Ota, WifiManager #include <ESP8266WiFi.h> // MQTT, Ota, WifiManager
#include <ESP8266HTTPClient.h> // MQTT, Ota #include <ESP8266HTTPClient.h> // MQTT, Ota
#include <ESP8266httpUpdate.h> // Ota #include <ESP8266httpUpdate.h> // Ota
#include <PubSubClient.h> // MQTT
#include <ArduinoJson.h> // WemoHue, IRremote, Domoticz #include <ArduinoJson.h> // WemoHue, IRremote, Domoticz
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
#include <ESP8266WebServer.h> // WifiManager, Webserver #include <ESP8266WebServer.h> // WifiManager, Webserver
@ -201,6 +211,13 @@ struct TimeChangeRule
TimeChangeRule myDST = { TIME_DST }; // Daylight Saving Time TimeChangeRule myDST = { TIME_DST }; // Daylight Saving Time
TimeChangeRule mySTD = { TIME_STD }; // Standard Time TimeChangeRule mySTD = { TIME_STD }; // Standard Time
#ifdef USE_STATIC_IP_ADDRESS
const uint8_t ipadd[4] = { WIFI_IP_ADDRESS }; // Static ip
const uint8_t ipgat[4] = { WIFI_GATEWAY }; // Local router gateway ip
const uint8_t ipdns[4] = { WIFI_DNS }; // DNS ip
const uint8_t ipsub[4] = { WIFI_SUBNETMASK }; // Subnetmask
#endif // USE_STATIC_IP_ADDRESS
int Baudrate = APP_BAUDRATE; // Serial interface baud rate int Baudrate = APP_BAUDRATE; // Serial interface baud rate
byte SerialInByte; // Received byte byte SerialInByte; // Received byte
int SerialInByteCounter = 0; // Index in receive buffer int SerialInByteCounter = 0; // Index in receive buffer
@ -504,13 +521,9 @@ void mqtt_connected()
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Started\":\"%s\"}"), snprintf_P(svalue, sizeof(svalue), PSTR("{\"Started\":\"%s\"}"),
(getResetReason() == "Exception") ? ESP.getResetInfo().c_str() : getResetReason().c_str()); (getResetReason() == "Exception") ? ESP.getResetInfo().c_str() : getResetReason().c_str());
mqtt_publish_topic_P(1, PSTR("INFO3"), svalue); mqtt_publish_topic_P(1, PSTR("INFO3"), svalue);
if (sysCfg.mqtt_enabled && (MQTT_MAX_PACKET_SIZE < (TOPSZ+MESSZ))) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Warning1\":\"Change MQTT_MAX_PACKET_SIZE in libraries/PubSubClient.h to at least %d\"}"), TOPSZ+MESSZ);
mqtt_publish_topic_P(1, PSTR("WARNING1"), svalue);
}
if (!spiffsPresent()) { if (!spiffsPresent()) {
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Warning2\":\"No persistent config. Please reflash with at least 16K SPIFFS\"}")); snprintf_P(svalue, sizeof(svalue), PSTR("{\"Warning1\":\"No persistent config. Please reflash with at least 16K SPIFFS\"}"));
mqtt_publish_topic_P(1, PSTR("WARNING2"), svalue); mqtt_publish_topic_P(1, PSTR("WARNING1"), svalue);
} }
if (sysCfg.tele_period) tele_period = sysCfg.tele_period -9; if (sysCfg.tele_period) tele_period = sysCfg.tele_period -9;
status_update_timer = 2; status_update_timer = 2;
@ -787,7 +800,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Sleep\":\"%d%s (%d%s)\"}"), sleep, (sysCfg.value_units) ? " mS" : "", sysCfg.sleep, (sysCfg.value_units) ? " mS" : ""); snprintf_P(svalue, sizeof(svalue), PSTR("{\"Sleep\":\"%d%s (%d%s)\"}"), sleep, (sysCfg.value_units) ? " mS" : "", sysCfg.sleep, (sysCfg.value_units) ? " mS" : "");
} }
else if (!strcmp(type,"FLASHCHIPMODE")) { else if (!strcmp(type,"FLASHCHIPMODE")) {
if ((data_len > 0) && (payload >= 2) && (payload <= 3)) { if ((data_len > 0) && (payload >= 0) && (payload <= 3)) {
if (ESP.getFlashChipMode() != payload) setFlashChipMode(0, payload &3); if (ESP.getFlashChipMode() != payload) setFlashChipMode(0, payload &3);
} }
snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashChipMode\":%d}"), ESP.getFlashChipMode()); snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashChipMode\":%d}"), ESP.getFlashChipMode());

View File

@ -285,6 +285,9 @@ void WIFI_begin(uint8_t flag)
sysCfg.sta_active ^= 1; sysCfg.sta_active ^= 1;
} // 3: Current AP } // 3: Current AP
if (strlen(sysCfg.sta_ssid[1]) == 0) sysCfg.sta_active = 0; if (strlen(sysCfg.sta_ssid[1]) == 0) sysCfg.sta_active = 0;
#ifdef USE_STATIC_IP_ADDRESS
WiFi.config(ipadd, ipgat, ipsub, ipdns); // Set static IP
#endif // USE_STATIC_IP_ADDRESS
WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]); WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]);
snprintf_P(log, sizeof(log), PSTR("Wifi: Connecting to AP%d %s in mode 11%c as %s..."), snprintf_P(log, sizeof(log), PSTR("Wifi: Connecting to AP%d %s in mode 11%c as %s..."),
sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], PhyMode[WiFi.getPhyMode() & 0x3], Hostname); sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], PhyMode[WiFi.getPhyMode() & 0x3], Hostname);

View File

@ -17,12 +17,18 @@
#define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable) #define SAVE_STATE 1 // [SaveState] Save changed power state to Flash (0 = disable, 1 = enable)
// -- Wifi ---------------------------------------- // -- Wifi ----------------------------------------
//#define USE_STATIC_IP_ADDRESS // Enable optional static IP address (Use DHCP by disabling using //)
#define WIFI_IP_ADDRESS 192,168,2,72 // IP address
#define WIFI_GATEWAY 192,168,2,254 // Gateway IP address
#define WIFI_DNS 192,168,2,27 // DNS IP address (might be the same as WIFI_GATEWAY)
#define WIFI_SUBNETMASK 255,255,255,0 // Network mask
#define STA_SSID1 "indebuurt1" // [Ssid1] Wifi SSID #define STA_SSID1 "indebuurt1" // [Ssid1] Wifi SSID
#define STA_PASS1 "VnsqrtnrsddbrN" // [Password1] Wifi password #define STA_PASS1 "VnsqrtnrsddbrN" // [Password1] Wifi password
#define STA_SSID2 "indebuurt2" // [Ssid2] Optional alternate AP Wifi SSID #define STA_SSID2 "indebuurt2" // [Ssid2] Optional alternate AP Wifi SSID
#define STA_PASS2 "VnsqrtnrsddbrN" // [Password2] Optional alternate AP Wifi password #define STA_PASS2 "VnsqrtnrsddbrN" // [Password2] Optional alternate AP Wifi password
#define WIFI_CONFIG_TOOL WIFI_WPSCONFIG // [WifiConfig] Default tool if wifi fails to connect #define WIFI_CONFIG_TOOL WIFI_WPSCONFIG // [WifiConfig] Default tool if wifi fails to connect
// (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY) // (WIFI_RESTART, WIFI_SMARTCONFIG, WIFI_MANAGER, WIFI_WPSCONFIG, WIFI_RETRY)
// -- Syslog -------------------------------------- // -- Syslog --------------------------------------
#define SYS_LOG_HOST "domus1" // [LogHost] (Linux) syslog host #define SYS_LOG_HOST "domus1" // [LogHost] (Linux) syslog host
#define SYS_LOG_PORT 514 // [LogPort] default syslog UDP port #define SYS_LOG_PORT 514 // [LogPort] default syslog UDP port
@ -117,6 +123,7 @@
#define TEMP_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Temperature #define TEMP_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Temperature
#define HUMIDITY_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Humidity #define HUMIDITY_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Humidity
#define PRESSURE_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Pressure #define PRESSURE_RESOLUTION 1 // Maximum number of decimals (0 - 3) showing sensor Pressure
#define ENERGY_RESOLUTION 3 // Maximum number of decimals (0 - 5) showing energy usage in kWh
// -- Sensor code selection ----------------------- // -- Sensor code selection -----------------------
//#define USE_DS18x20 // Optional using OneWire library for multiple DS18B20 and/or DS18S20 //#define USE_DS18x20 // Optional using OneWire library for multiple DS18B20 and/or DS18S20

View File

@ -182,7 +182,7 @@ const char HTTP_FORM_LOG1[] PROGMEM =
"<fieldset><legend><b>&nbsp;Logging parameters&nbsp;</b></legend><form method='post' action='sv'>" "<fieldset><legend><b>&nbsp;Logging parameters&nbsp;</b></legend><form method='post' action='sv'>"
"<input id='w' name='w' value='3' hidden><input id='r' name='r' value='0' hidden>"; "<input id='w' name='w' value='3' hidden><input id='r' name='r' value='0' hidden>";
const char HTTP_FORM_LOG2[] PROGMEM = const char HTTP_FORM_LOG2[] PROGMEM =
"<br/><b>{b0} level</b> ({b1})<br/><select id='{b2}' name='{b2}'>" "<br/><b>{b0}log level</b> ({b1})<br/><select id='{b2}' name='{b2}'>"
"<option{a0value='0'>0 None</option>" "<option{a0value='0'>0 None</option>"
"<option{a1value='1'>1 Error</option>" "<option{a1value='1'>1 Error</option>"
"<option{a2value='2'>2 Info</option>" "<option{a2value='2'>2 Info</option>"
@ -389,6 +389,7 @@ void handleRoot()
if (_httpflag == HTTP_MANAGER) { if (_httpflag == HTTP_MANAGER) {
handleWifi0(); handleWifi0();
} else { } else {
char stemp[10], line[100];
String page = FPSTR(HTTP_HEAD); String page = FPSTR(HTTP_HEAD);
page.replace("{v}", "Main menu"); page.replace("{v}", "Main menu");
page.replace("<body>", "<body onload='la()'>"); page.replace("<body>", "<body onload='la()'>");
@ -397,16 +398,10 @@ void handleRoot()
if (Maxdevice) { if (Maxdevice) {
page += F("<table style='width:100%'><tr>"); page += F("<table style='width:100%'><tr>");
for (byte idx = 1; idx <= Maxdevice; idx++) { for (byte idx = 1; idx <= Maxdevice; idx++) {
page += F("<td style='width:"); snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx);
page += String(100 / Maxdevice); snprintf_P(line, sizeof(line), PSTR("<td style='width:%d%'><button onclick='la(%d);'>Toggle%s</button></td>"),
page += F("%'><button onclick='la("); 100 / Maxdevice, idx, (Maxdevice > 1) ? stemp : "");
page += String(idx); page += line;
page += F(");'>Toggle");
if (Maxdevice > 1) {
page += F(" ");
page += String(idx);
}
page += F("</button></td>");
} }
page += F("</tr></table>"); page += F("</tr></table>");
} }
@ -450,13 +445,19 @@ void handleAjax2()
page += tpage; page += tpage;
page += F("</table>"); page += F("</table>");
} }
char line[120];
if (Maxdevice) { if (Maxdevice) {
page += F("<table style='width:100%'><tr>"); page += F("<table style='width:100%'><tr>");
for (byte idx = 1; idx <= Maxdevice; idx++) { for (byte idx = 1; idx <= Maxdevice; idx++) {
/*
page += F("<td style='width:{1%'><div style='text-align:center;font-weight:bold;font-size:{2px'>{3</div></td>"); page += F("<td style='width:{1%'><div style='text-align:center;font-weight:bold;font-size:{2px'>{3</div></td>");
page.replace("{1", String(100 / Maxdevice)); page.replace("{1", String(100 / Maxdevice));
page.replace("{2", String(70 - (Maxdevice * 8))); page.replace("{2", String(70 - (Maxdevice * 8)));
page.replace("{3", (power & (0x01 << (idx -1))) ? "ON" : "OFF"); page.replace("{3", (power & (0x01 << (idx -1))) ? "ON" : "OFF");
*/
snprintf_P(line, sizeof(line), PSTR("<td style='width:%d%'><div style='text-align:center;font-weight:bold;font-size:%dpx'>%s</div></td>"),
100 / Maxdevice, 70 - (Maxdevice * 8), (power & (0x01 << (idx -1))) ? "ON" : "OFF");
page += line;
} }
page += F("</tr></table>"); page += F("</tr></table>");
} }
@ -490,7 +491,7 @@ void handleConfig()
void handleModule() void handleModule()
{ {
if (httpUser()) return; if (httpUser()) return;
char stemp[20]; char stemp[20], line[128];
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Module config")); addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle Module config"));
@ -501,11 +502,11 @@ void handleModule()
snprintf_P(stemp, sizeof(stemp), modules[MODULE].name); snprintf_P(stemp, sizeof(stemp), modules[MODULE].name);
page.replace("{mt}", stemp); page.replace("{mt}", stemp);
for (byte i = 0; i < MAXMODULE; i++) { for (byte i = 0; i < MAXMODULE; i++) {
page += F("<option ");
if (i == sysCfg.module) page += F("selected ");
snprintf_P(stemp, sizeof(stemp), modules[i].name); snprintf_P(stemp, sizeof(stemp), modules[i].name);
page += F("value='"); page += String(i); page += F("'>"); page += String(i +1); page += F(" "); page += stemp; page += F("</option>"); snprintf_P(line, sizeof(line), PSTR("<option%s value='%d'>%d %s</option>"),
(i == sysCfg.module) ? " selected" : "", i, i +1, stemp);
page += line;
} }
page += F("</select></br>"); page += F("</select></br>");
@ -513,14 +514,13 @@ void handleModule()
memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule)); memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule));
for (byte i = 0; i < MAX_GPIO_PIN; i++) { for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (cmodule.gp.io[i] == GPIO_USER) { if (cmodule.gp.io[i] == GPIO_USER) {
page += F("<br/><b>GPIO"); page += String(i); page += F("</b> <select id='g"); page += String(i); page += F("' name='g"); page += String(i); page += F("'>"); snprintf_P(line, sizeof(line), PSTR("<br/><b>GPIO%d</b><select id='g%d' name='g%d'>"), i, i, i);
page += line;
for (byte j = 0; j < GPIO_SENSOR_END; j++) { for (byte j = 0; j < GPIO_SENSOR_END; j++) {
page += F("<option ");
if (j == my_module.gp.io[i]) page += F("selected ");
page += F("value='"); page += String(j); page += F("'>");
page += String(j); page += F(" ");
snprintf_P(stemp, sizeof(stemp), sensors[j]); snprintf_P(stemp, sizeof(stemp), sensors[j]);
page += stemp; page += F("</option>"); snprintf_P(line, sizeof(line), PSTR("<option%s value='%d'>%d %s</option>"),
(j == my_module.gp.io[i]) ? " selected" : "", j, j, stemp);
page += line;
} }
page += F("</select></br>"); page += F("</select></br>");
} }
@ -673,7 +673,7 @@ void handleLog()
page += FPSTR(HTTP_FORM_LOG2); page += FPSTR(HTTP_FORM_LOG2);
switch (idx) { switch (idx) {
case 0: case 0:
page.replace("{b0}", "Serial log"); page.replace("{b0}", F("Serial "));
page.replace("{b1}", STR(SERIAL_LOG_LEVEL)); page.replace("{b1}", STR(SERIAL_LOG_LEVEL));
page.replace("{b2}", "ls"); page.replace("{b2}", "ls");
for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) {
@ -681,7 +681,7 @@ void handleLog()
} }
break; break;
case 1: case 1:
page.replace("{b0}", "Web log"); page.replace("{b0}", F("Web "));
page.replace("{b1}", STR(WEB_LOG_LEVEL)); page.replace("{b1}", STR(WEB_LOG_LEVEL));
page.replace("{b2}", "lw"); page.replace("{b2}", "lw");
for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) {
@ -689,7 +689,7 @@ void handleLog()
} }
break; break;
case 2: case 2:
page.replace("{b0}", "Syslog"); page.replace("{b0}", F("Sys"));
page.replace("{b1}", STR(SYS_LOG_LEVEL)); page.replace("{b1}", STR(SYS_LOG_LEVEL));
page.replace("{b2}", "ll"); page.replace("{b2}", "ll");
for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) { for (byte i = LOG_LEVEL_NONE; i < LOG_LEVEL_ALL; i++) {
@ -750,11 +750,10 @@ void handleDownload()
WiFiClient myClient = webServer->client(); WiFiClient myClient = webServer->client();
webServer->setContentLength(4096); webServer->setContentLength(4096);
String attachment = F("attachment; filename=Config_");
attachment += sysCfg.friendlyname[0]; char attachment[100];
attachment += F("_"); snprintf_P(attachment, sizeof(attachment), PSTR("attachment; filename=Config_%s_%s.dmp"),
attachment += Version; sysCfg.friendlyname[0], Version);
attachment += F(".dmp");
webServer->sendHeader("Content-Disposition", attachment); webServer->sendHeader("Content-Disposition", attachment);
webServer->send(200, "application/octet-stream", ""); webServer->send(200, "application/octet-stream", "");
memcpy(buffer, &sysCfg, sizeof(sysCfg)); memcpy(buffer, &sysCfg, sizeof(sysCfg));
@ -950,7 +949,7 @@ void handleUploadDone()
if (httpUser()) return; if (httpUser()) return;
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: File upload done")); addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: File upload done"));
char log[LOGSZ]; char error[80], log[LOGSZ];
WIFI_configCounter(); WIFI_configCounter();
restartflag = 0; restartflag = 0;
mqttcounter = 0; mqttcounter = 0;
@ -960,35 +959,25 @@ void handleUploadDone()
page += F("<div style='text-align:center;'><b>Upload "); page += F("<div style='text-align:center;'><b>Upload ");
if (_uploaderror) { if (_uploaderror) {
page += F("<font color='red'>failed</font></b><br/><br/>"); page += F("<font color='red'>failed</font></b><br/><br/>");
String error = ""; switch (_uploaderror) {
if (_uploaderror == 1) { case 1: strcpy_P(error, PSTR("No file selected")); break;
error = F("No file selected"); case 2: strcpy_P(error, PSTR("File size is larger than available free space")); break;
} else if (_uploaderror == 2) { case 3: strcpy_P(error, PSTR("File magic header does not start with 0xE9")); break;
error = F("File size is larger than available free space"); case 4: strcpy_P(error, PSTR("File flash size is larger than device flash size")); break;
} else if (_uploaderror == 3) { case 5: strcpy_P(error, PSTR("File upload buffer miscompare")); break;
error = F("File magic header does not start with 0xE9"); case 6: strcpy_P(error, PSTR("Upload failed. Enable logging option 3 for more information")); break;
} else if (_uploaderror == 4) { case 7: strcpy_P(error, PSTR("Upload aborted")); break;
error = F("File flash size is larger than device flash size"); case 8: strcpy_P(error, PSTR("Invalid configuration file")); break;
} else if (_uploaderror == 5) { case 9: strcpy_P(error, PSTR("Configuration file too large")); break;
error = F("File upload buffer miscompare"); default:
} else if (_uploaderror == 6) { snprintf_P(error, sizeof(error), PSTR("Upload error code %d"), _uploaderror);
error = F("Upload failed. Enable logging option 3 for more information");
} else if (_uploaderror == 7) {
error = F("Upload aborted");
} else if (_uploaderror == 8) {
error = F("Invalid configuration file");
} else if (_uploaderror == 9) {
error = F("Configuration file too large");
} else {
error = F("Upload error code ");
error += String(_uploaderror);
} }
page += error; page += error;
if (!_uploadfiletype && Update.hasError()) { if (!_uploadfiletype && Update.hasError()) {
page += F("<br/><br/>Update error code (see Updater.cpp) "); page += F("<br/><br/>Update error code (see Updater.cpp) ");
page += String(Update.getError()); page += String(Update.getError());
} }
snprintf_P(log, sizeof(log), PSTR("Upload: Error - %s"), error.c_str()); snprintf_P(log, sizeof(log), PSTR("Upload: Error - %s"), error);
addLog(LOG_LEVEL_DEBUG, log); addLog(LOG_LEVEL_DEBUG, log);
sl_blank(0); sl_blank(0);
} else { } else {
@ -1124,7 +1113,10 @@ void handleCmnd()
byte curridx = logidx; byte curridx = logidx;
if (strlen(webServer->arg("cmnd").c_str())) { if (strlen(webServer->arg("cmnd").c_str())) {
snprintf_P(svalue, sizeof(svalue), webServer->arg("cmnd").c_str()); snprintf_P(svalue, sizeof(svalue), webServer->arg("cmnd").c_str());
byte syslog_now = syslog_level;
syslog_level = 0; // Disable UDP syslog to not trigger hardware WDT
do_cmnd(svalue); do_cmnd(svalue);
syslog_level = syslog_now;
} }
if (logidx != curridx) { if (logidx != curridx) {
@ -1181,7 +1173,10 @@ void handleAjax()
snprintf_P(svalue, sizeof(svalue), webServer->arg("c1").c_str()); snprintf_P(svalue, sizeof(svalue), webServer->arg("c1").c_str());
snprintf_P(log, sizeof(log), PSTR("CMND: %s"), svalue); snprintf_P(log, sizeof(log), PSTR("CMND: %s"), svalue);
addLog(LOG_LEVEL_INFO, log); addLog(LOG_LEVEL_INFO, log);
byte syslog_now = syslog_level;
syslog_level = 0; // Disable UDP syslog to not trigger hardware WDT
do_cmnd(svalue); do_cmnd(svalue);
syslog_level = syslog_now;
} }
if (strlen(webServer->arg("c2").c_str())) counter = atoi(webServer->arg("c2").c_str()); if (strlen(webServer->arg("c2").c_str())) counter = atoi(webServer->arg("c2").c_str());

View File

@ -27,6 +27,9 @@ POSSIBILITY OF SUCH DAMAGE.
* Sonoff Led * Sonoff Led
\*********************************************************************************************/ \*********************************************************************************************/
#define ANALOG_WRITE_RANGE 255 // 127..1023 but as Color is addressed by 8 bits it should be 255 for my code
#define ANALOG_WRITE_FREQ 432 // 100..1000 Hz led refresh
uint8_t ledTable[] = { uint8_t ledTable[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -87,8 +90,8 @@ void sl_setDim(uint8_t myDimmer)
void sl_init(void) void sl_init(void)
{ {
analogWriteRange(255); // Default is 1023 (Arduino.h) analogWriteRange(ANALOG_WRITE_RANGE); // Default is 1023 (Arduino.h)
analogWriteFreq(200); // Default is 1000 (core_esp8266_wiring_pwm.c) - Try to lower flicker analogWriteFreq(ANALOG_WRITE_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c) - Try to lower flicker
sl_blankv = 0; sl_blankv = 0;
sl_power = 0; sl_power = 0;
sl_any = 0; sl_any = 0;

View File

@ -528,8 +528,8 @@ void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue)
uint16_t pe, pw, pu; uint16_t pe, pw, pu;
hlw_readEnergy(option, ped, pe, pw, pu, pi, pc); hlw_readEnergy(option, ped, pe, pw, pu, pi, pc);
dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, 3, stemp0); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, ENERGY_RESOLUTION &7, stemp0);
dtostrf(ped, 1, 3, stemp1); dtostrf(ped, 1, ENERGY_RESOLUTION &7, stemp1);
dtostrf(pc, 1, 2, stemp2); dtostrf(pc, 1, 2, stemp2);
dtostrf(pi, 1, 3, stemp3); dtostrf(pi, 1, 3, stemp3);
snprintf_P(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe); snprintf_P(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe);
@ -582,8 +582,8 @@ String hlw_webPresent()
dtostrf(pi, 1, 3, stemp); dtostrf(pi, 1, 3, stemp);
dtostrf(pc, 1, 2, stemp2); dtostrf(pc, 1, 2, stemp2);
dtostrf(ped, 1, 3, stemp3); dtostrf(ped, 1, ENERGY_RESOLUTION &7, stemp3);
dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, 3, stemp4); dtostrf((float)sysCfg.hlw_kWhyesterday / 100000000, 1, ENERGY_RESOLUTION &7, stemp4);
snprintf_P(sensor, sizeof(sensor), HTTP_ENERGY_SNS, pu, stemp, pw, stemp2, stemp3, stemp4); snprintf_P(sensor, sizeof(sensor), HTTP_ENERGY_SNS, pu, stemp, pw, stemp2, stemp3, stemp4);
page += sensor; page += sensor;
return page; return page;