mirror of https://github.com/arendst/Tasmota.git
v3.9.21
3.9.21 20170224 * Add ajax to web root page and web console (#79) * Add commands SwitchMode1..4 and enable user switches 2, 3 and 4 (#84, #88) * Fix MQTT upgrade when webserver is active
This commit is contained in:
parent
3f73e48bfa
commit
3fefb9b931
|
@ -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.20** - See ```sonoff/_releasenotes.ino``` for change information.
|
Current version is **3.9.21** - See ```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.
|
@ -1,4 +1,9 @@
|
||||||
/* 3.9.20 20170221
|
/* 3.9.21 20170224
|
||||||
|
* Add ajax to web root page and web console (#79)
|
||||||
|
* Add commands SwitchMode1..4 and enable user switches 2, 3 and 4 (#84, #88)
|
||||||
|
* Fix MQTT upgrade when webserver is active
|
||||||
|
*
|
||||||
|
* 3.9.20 20170221
|
||||||
* Add minimal basic authentication to Web Admin mode (#87)
|
* Add minimal basic authentication to Web Admin mode (#87)
|
||||||
* Fix Hue and add HSB support (#89)
|
* Fix Hue and add HSB support (#89)
|
||||||
*
|
*
|
||||||
|
|
|
@ -114,7 +114,7 @@ struct SYSCFG {
|
||||||
|
|
||||||
uint8_t power;
|
uint8_t power;
|
||||||
uint8_t ledstate;
|
uint8_t ledstate;
|
||||||
uint8_t switchmode;
|
uint8_t ex_switchmode; // Not used since 3.9.21
|
||||||
|
|
||||||
char domoticz_in_topic[33];
|
char domoticz_in_topic[33];
|
||||||
char domoticz_out_topic[33];
|
char domoticz_out_topic[33];
|
||||||
|
@ -185,5 +185,7 @@ struct SYSCFG {
|
||||||
uint8_t emulation;
|
uint8_t emulation;
|
||||||
|
|
||||||
char web_password[33];
|
char web_password[33];
|
||||||
|
uint8_t switchmode[4];
|
||||||
|
|
||||||
} sysCfg;
|
} sysCfg;
|
||||||
|
|
||||||
|
|
|
@ -367,7 +367,7 @@ void CFG_DefaultSet2()
|
||||||
sysCfg.poweronstate = APP_POWERON_STATE;
|
sysCfg.poweronstate = APP_POWERON_STATE;
|
||||||
sysCfg.pulsetime = APP_PULSETIME;
|
sysCfg.pulsetime = APP_PULSETIME;
|
||||||
sysCfg.ledstate = APP_LEDSTATE;
|
sysCfg.ledstate = APP_LEDSTATE;
|
||||||
sysCfg.switchmode = SWITCH_MODE;
|
// sysCfg.switchmode = SWITCH_MODE;
|
||||||
sysCfg.blinktime = APP_BLINKTIME;
|
sysCfg.blinktime = APP_BLINKTIME;
|
||||||
sysCfg.blinkcount = APP_BLINKCOUNT;
|
sysCfg.blinkcount = APP_BLINKCOUNT;
|
||||||
sysCfg.sleep = APP_SLEEP;
|
sysCfg.sleep = APP_SLEEP;
|
||||||
|
@ -376,6 +376,7 @@ void CFG_DefaultSet2()
|
||||||
strlcpy(sysCfg.domoticz_out_topic, DOMOTICZ_OUT_TOPIC, sizeof(sysCfg.domoticz_out_topic));
|
strlcpy(sysCfg.domoticz_out_topic, DOMOTICZ_OUT_TOPIC, sizeof(sysCfg.domoticz_out_topic));
|
||||||
sysCfg.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER;
|
sysCfg.domoticz_update_timer = DOMOTICZ_UPDATE_TIMER;
|
||||||
for (byte i = 0; i < 4; i++) {
|
for (byte i = 0; i < 4; i++) {
|
||||||
|
sysCfg.switchmode[i] = SWITCH_MODE;
|
||||||
sysCfg.domoticz_relay_idx[i] = 0;
|
sysCfg.domoticz_relay_idx[i] = 0;
|
||||||
sysCfg.domoticz_key_idx[i] = 0;
|
sysCfg.domoticz_key_idx[i] = 0;
|
||||||
sysCfg.domoticz_switch_idx[i] = 0;
|
sysCfg.domoticz_switch_idx[i] = 0;
|
||||||
|
@ -545,7 +546,7 @@ void CFG_Migrate_Part2()
|
||||||
sysCfg.hlw_kWhdoy = sysCfg2.hlw_kWhdoy;
|
sysCfg.hlw_kWhdoy = sysCfg2.hlw_kWhdoy;
|
||||||
}
|
}
|
||||||
if (sysCfg2.version >= 0x02001200) { // 2.0.18
|
if (sysCfg2.version >= 0x02001200) { // 2.0.18
|
||||||
sysCfg.switchmode = sysCfg2.switchmode;
|
sysCfg.switchmode[0] = sysCfg2.switchmode;
|
||||||
}
|
}
|
||||||
if (sysCfg2.version >= 0x02010000) { // 2.1.0
|
if (sysCfg2.version >= 0x02010000) { // 2.1.0
|
||||||
strlcpy(sysCfg.mqtt_fingerprint, sysCfg2.mqtt_fingerprint, sizeof(sysCfg.mqtt_fingerprint));
|
strlcpy(sysCfg.mqtt_fingerprint, sysCfg2.mqtt_fingerprint, sizeof(sysCfg.mqtt_fingerprint));
|
||||||
|
@ -629,6 +630,9 @@ void CFG_Delta()
|
||||||
if (sysCfg.version < 0x03091301) {
|
if (sysCfg.version < 0x03091301) {
|
||||||
strlcpy(sysCfg.web_password, WEB_PASSWORD, sizeof(sysCfg.web_password));
|
strlcpy(sysCfg.web_password, WEB_PASSWORD, sizeof(sysCfg.web_password));
|
||||||
}
|
}
|
||||||
|
if (sysCfg.version < 0x03091500) {
|
||||||
|
for (byte i = 0; i < 4; i++) sysCfg.switchmode[i] = sysCfg.ex_switchmode;
|
||||||
|
}
|
||||||
|
|
||||||
sysCfg.version = VERSION;
|
sysCfg.version = VERSION;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* ====================================================
|
* ====================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define VERSION 0x03091400 // 3.9.20
|
#define VERSION 0x03091500 // 3.9.21
|
||||||
|
|
||||||
//#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k)
|
//#define BE_MINIMAL // Compile a minimal version if upgrade memory gets tight (still 404k)
|
||||||
// To be used as step 1. Next step is compile and use desired version
|
// To be used as step 1. Next step is compile and use desired version
|
||||||
|
@ -118,7 +118,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
|
||||||
#define STATES 10 // loops per second
|
#define STATES 10 // loops per second
|
||||||
#define SYSLOG_TIMER 600 // Seconds to restore syslog_level
|
#define SYSLOG_TIMER 600 // Seconds to restore syslog_level
|
||||||
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
|
#define SERIALLOG_TIMER 600 // Seconds to disable SerialLog
|
||||||
#define OTA_ATTEMPTS 5 // Number of times to try fetching the new firmware
|
#define OTA_ATTEMPTS 10 // Number of times to try fetching the new firmware
|
||||||
|
|
||||||
#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
|
||||||
|
@ -213,12 +213,14 @@ int state = 0; // State per second flag
|
||||||
int mqttflag = 2; // MQTT connection messages flag
|
int mqttflag = 2; // MQTT connection messages flag
|
||||||
int otaflag = 0; // OTA state flag
|
int otaflag = 0; // OTA state flag
|
||||||
int otaok = 0; // OTA result
|
int otaok = 0; // OTA result
|
||||||
|
byte otaretry = OTA_ATTEMPTS; // OTA retry counter
|
||||||
int restartflag = 0; // Sonoff restart flag
|
int restartflag = 0; // Sonoff restart flag
|
||||||
int wificheckflag = WIFI_RESTART; // Wifi state flag
|
int wificheckflag = WIFI_RESTART; // Wifi state flag
|
||||||
int uptime = 0; // Current uptime in hours
|
int uptime = 0; // Current uptime in hours
|
||||||
int tele_period = 0; // Tele period timer
|
int tele_period = 0; // Tele period timer
|
||||||
String Log[MAX_LOG_LINES]; // Web log buffer
|
String Log[MAX_LOG_LINES]; // Web log buffer
|
||||||
byte logidx = 0; // Index in Web log buffer
|
byte logidx = 0; // Index in Web log buffer
|
||||||
|
byte logajaxflg = 0; // Reset web console log
|
||||||
byte Maxdevice = MAX_DEVICE; // Max number of devices supported
|
byte Maxdevice = MAX_DEVICE; // Max number of devices supported
|
||||||
int status_update_timer = 0; // Refresh initial status
|
int status_update_timer = 0; // Refresh initial status
|
||||||
uint16_t pulse_timer = 0; // Power off timer
|
uint16_t pulse_timer = 0; // Power off timer
|
||||||
|
@ -891,11 +893,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
||||||
}
|
}
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"FriendlyName%d\":\"%s\"}"), index, sysCfg.friendlyname[index -1]);
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"FriendlyName%d\":\"%s\"}"), index, sysCfg.friendlyname[index -1]);
|
||||||
}
|
}
|
||||||
else if (swt_flg && !strcmp(type,"SWITCHMODE")) {
|
else if (swt_flg && !strcmp(type,"SWITCHMODE") && (index > 0) && (index <= 4)) {
|
||||||
if ((data_len > 0) && (payload >= 0) && (payload < MAX_SWITCH_OPTION)) {
|
if ((data_len > 0) && (payload >= 0) && (payload < MAX_SWITCH_OPTION)) {
|
||||||
sysCfg.switchmode = payload;
|
sysCfg.switchmode[index -1] = payload;
|
||||||
}
|
}
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SwitchMode\":%d}"), sysCfg.switchmode);
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"SwitchMode%d\":%d}"), index, sysCfg.switchmode[index-1]);
|
||||||
}
|
}
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
else if (!strcmp(type,"WEBSERVER")) {
|
else if (!strcmp(type,"WEBSERVER")) {
|
||||||
|
@ -1184,7 +1186,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
|
||||||
|
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"%s%s, PulseTime, BlinkTime, BlinkCount"), (Maxdevice == 1) ? "Power, Light" : "Power1, Power2, Light1 Light2", (sysCfg.module != MOTOR) ? ", PowerOnState" : "");
|
snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"%s%s, PulseTime, BlinkTime, BlinkCount"), (Maxdevice == 1) ? "Power, Light" : "Power1, Power2, Light1 Light2", (sysCfg.module != MOTOR) ? ", PowerOnState" : "");
|
||||||
#ifdef USE_WEBSERVER
|
#ifdef USE_WEBSERVER
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, Emulation"), svalue);
|
snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, WebPassword, Emulation"), svalue);
|
||||||
#endif
|
#endif
|
||||||
if (swt_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, SwitchMode"), svalue);
|
if (swt_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, SwitchMode"), svalue);
|
||||||
#ifdef USE_I2C
|
#ifdef USE_I2C
|
||||||
|
@ -1223,10 +1225,10 @@ void send_button_power(byte key, byte device, byte state)
|
||||||
|
|
||||||
char stopic[TOPSZ], svalue[TOPSZ], stemp1[10];
|
char stopic[TOPSZ], svalue[TOPSZ], stemp1[10];
|
||||||
|
|
||||||
if (device > Maxdevice) device = 1;
|
if (!key && (device > Maxdevice)) device = 1;
|
||||||
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), device);
|
snprintf_P(stemp1, sizeof(stemp1), PSTR("%d"), device);
|
||||||
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s%s"),
|
snprintf_P(stopic, sizeof(stopic), PSTR("%s/%s/%s%s"),
|
||||||
SUB_PREFIX, (key) ? sysCfg.switch_topic : sysCfg.button_topic, sysCfg.mqtt_subtopic, (Maxdevice > 1) ? stemp1 : "");
|
SUB_PREFIX, (key) ? sysCfg.switch_topic : sysCfg.button_topic, sysCfg.mqtt_subtopic, (key || (Maxdevice > 1)) ? stemp1 : "");
|
||||||
|
|
||||||
if (state == 3) {
|
if (state == 3) {
|
||||||
svalue[0] = '\0';
|
svalue[0] = '\0';
|
||||||
|
@ -1676,11 +1678,12 @@ void stateloop()
|
||||||
lastbutton[i] = button;
|
lastbutton[i] = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (byte i = 0; i < Maxdevice; i++) if (pin[GPIO_SWT1 +i] < 99) {
|
// for (byte i = 0; i < Maxdevice; i++) if (pin[GPIO_SWT1 +i] < 99) {
|
||||||
|
for (byte i = 0; i < 4; i++) if (pin[GPIO_SWT1 +i] < 99) {
|
||||||
button = digitalRead(pin[GPIO_SWT1 +i]);
|
button = digitalRead(pin[GPIO_SWT1 +i]);
|
||||||
if (button != lastwallswitch[i]) {
|
if (button != lastwallswitch[i]) {
|
||||||
switchflag = 3;
|
switchflag = 3;
|
||||||
switch (sysCfg.switchmode) {
|
switch (sysCfg.switchmode[i]) {
|
||||||
case TOGGLE:
|
case TOGGLE:
|
||||||
switchflag = 2; // Toggle
|
switchflag = 2; // Toggle
|
||||||
break;
|
break;
|
||||||
|
@ -1698,9 +1701,9 @@ void stateloop()
|
||||||
}
|
}
|
||||||
if (switchflag < 3) {
|
if (switchflag < 3) {
|
||||||
if (sysCfg.mqtt_enabled && mqttClient.connected() && strcmp(sysCfg.switch_topic,"0")) {
|
if (sysCfg.mqtt_enabled && mqttClient.connected() && strcmp(sysCfg.switch_topic,"0")) {
|
||||||
send_button_power(1, i +1, switchflag); // Execute commend via MQTT
|
send_button_power(1, i +1, switchflag); // Execute commend via MQTT
|
||||||
} else {
|
} else {
|
||||||
do_cmnd_power(i +1, switchflag); // Execute command internally
|
do_cmnd_power(i +1, switchflag); // Execute command internally (if i < Maxdevice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastwallswitch[i] = button;
|
lastwallswitch[i] = button;
|
||||||
|
@ -1730,30 +1733,34 @@ void stateloop()
|
||||||
case (STATES/10)*2:
|
case (STATES/10)*2:
|
||||||
if (otaflag) {
|
if (otaflag) {
|
||||||
otaflag--;
|
otaflag--;
|
||||||
if (otaflag <= 0) {
|
if (otaflag == 2){
|
||||||
otaflag = 12;
|
otaretry = OTA_ATTEMPTS;
|
||||||
ESPhttpUpdate.rebootOnUpdate(false);
|
ESPhttpUpdate.rebootOnUpdate(false);
|
||||||
sl_blank(1);
|
sl_blank(1);
|
||||||
// Try multiple times to get the update, in case we have a transient issue.
|
}
|
||||||
// e.g. Someone issued "cmnd/sonoffs/update 1" and all the devices
|
if (otaflag <= 0) {
|
||||||
// are hammering the OTAURL.
|
#ifdef USE_WEBSERVER
|
||||||
for (byte i = 0; i < OTA_ATTEMPTS && !otaok; i++) {
|
if (sysCfg.webserver) stopWebserver();
|
||||||
// Delay an increasing pseudo-random time for each interation.
|
#endif // USE_WEBSERVER
|
||||||
// Starting at 0 (no delay) up to a maximum of OTA_ATTEMPTS-1 seconds.
|
otaflag = 92;
|
||||||
delay((ESP.getChipId() % 1000) * i);
|
otaok = 0;
|
||||||
|
otaretry--;
|
||||||
|
if (otaretry) {
|
||||||
|
// snprintf_P(log, sizeof(log), PSTR("OTA: Attempt %d"), OTA_ATTEMPTS - otaretry);
|
||||||
|
// addLog(LOG_LEVEL_INFO, log);
|
||||||
otaok = (ESPhttpUpdate.update(sysCfg.otaUrl) == HTTP_UPDATE_OK);
|
otaok = (ESPhttpUpdate.update(sysCfg.otaUrl) == HTTP_UPDATE_OK);
|
||||||
|
if (!otaok) otaflag = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (otaflag == 10) { // Allow MQTT to reconnect
|
if (otaflag == 90) { // Allow MQTT to reconnect
|
||||||
otaflag = 0;
|
otaflag = 0;
|
||||||
if (otaok) {
|
if (otaok) {
|
||||||
if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) setFlashChipMode(1, 3); // DOUT - ESP8285
|
if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) setFlashChipMode(1, 3); // DOUT - ESP8285
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting"));
|
snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting"));
|
||||||
restartflag = 2;
|
|
||||||
} else {
|
} else {
|
||||||
sl_blank(0);
|
|
||||||
snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str());
|
snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str());
|
||||||
}
|
}
|
||||||
|
restartflag = 2; // Restart anyway to keep memory clean webserver
|
||||||
mqtt_publish_topic_P(0, PSTR("UPGRADE"), svalue);
|
mqtt_publish_topic_P(0, PSTR("UPGRADE"), svalue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@ enum upins_t {
|
||||||
GPIO_WS2812, // WS2812 Led string
|
GPIO_WS2812, // WS2812 Led string
|
||||||
GPIO_IRSEND, // IR remote
|
GPIO_IRSEND, // IR remote
|
||||||
GPIO_SWT1, // User connected external switches
|
GPIO_SWT1, // User connected external switches
|
||||||
|
GPIO_SWT2,
|
||||||
|
GPIO_SWT3,
|
||||||
|
GPIO_SWT4,
|
||||||
GPIO_SENSOR_END };
|
GPIO_SENSOR_END };
|
||||||
|
|
||||||
// Text in webpage Module Parameters and commands GPIOS and GPIO
|
// Text in webpage Module Parameters and commands GPIOS and GPIO
|
||||||
|
@ -27,14 +30,14 @@ const char sensors[GPIO_SENSOR_END][9] PROGMEM = {
|
||||||
"I2C SDA",
|
"I2C SDA",
|
||||||
"WS2812",
|
"WS2812",
|
||||||
"IRremote",
|
"IRremote",
|
||||||
"Switch" };
|
"Switch1",
|
||||||
|
"Switch2",
|
||||||
|
"Switch3",
|
||||||
|
"Switch4" };
|
||||||
|
|
||||||
// Programmer selectable GPIO functionality offset by user selectable GPIOs
|
// Programmer selectable GPIO functionality offset by user selectable GPIOs
|
||||||
enum fpins_t {
|
enum fpins_t {
|
||||||
GPIO_SWT2 = GPIO_SENSOR_END,
|
GPIO_KEY1 = GPIO_SENSOR_END, // Button usually connected to GPIO0
|
||||||
GPIO_SWT3,
|
|
||||||
GPIO_SWT4,
|
|
||||||
GPIO_KEY1, // Button usually connected to GPIO0
|
|
||||||
GPIO_KEY2,
|
GPIO_KEY2,
|
||||||
GPIO_KEY3,
|
GPIO_KEY3,
|
||||||
GPIO_KEY4,
|
GPIO_KEY4,
|
||||||
|
@ -107,14 +110,22 @@ typedef struct MYTMPLT {
|
||||||
const mytmplt modules[MAXMODULE] PROGMEM = {
|
const mytmplt modules[MAXMODULE] PROGMEM = {
|
||||||
{ "Sonoff Basic", // Sonoff Basic
|
{ "Sonoff Basic", // Sonoff Basic
|
||||||
GPIO_KEY1, // GPIO00 Button
|
GPIO_KEY1, // GPIO00 Button
|
||||||
0, 0,
|
0, // GPIO01 Serial RXD
|
||||||
|
0, // GPIO02
|
||||||
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
|
||||||
GPIO_USER, // GPIO04 Optional sensor
|
GPIO_USER, // GPIO04 Optional sensor
|
||||||
0, 0, 0, 0, 0, 0, 0,
|
0, // GPIO05
|
||||||
|
0, // GPIO06 (SD_CLK Flash)
|
||||||
|
0, // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT)
|
||||||
|
0, // GPIO08 (SD_DATA1 Flash QIO/DIO)
|
||||||
|
0, // GPIO09 (SD_DATA2 Flash QIO)
|
||||||
|
0, // GPIO10 (SD_DATA3 Flash QIO)
|
||||||
|
0, // GPIO11 (SD_CMD Flash)
|
||||||
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
|
||||||
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
GPIO_LED1_INV, // GPIO13 Green Led (0 = On, 1 = Off)
|
||||||
GPIO_USER, // GPIO14 Optional sensor
|
GPIO_USER, // GPIO14 Optional sensor
|
||||||
0, 0
|
0, // GPIO15
|
||||||
|
0 // GPIO16
|
||||||
},
|
},
|
||||||
{ "Sonoff RF", // Sonoff RF
|
{ "Sonoff RF", // Sonoff RF
|
||||||
GPIO_KEY1, // GPIO00 Button
|
GPIO_KEY1, // GPIO00 Button
|
||||||
|
|
|
@ -53,34 +53,58 @@ const char HTTP_HEAD[] PROGMEM =
|
||||||
"document.getElementById('s1').value=l.innerText||l.textContent;"
|
"document.getElementById('s1').value=l.innerText||l.textContent;"
|
||||||
"document.getElementById('p1').focus();"
|
"document.getElementById('p1').focus();"
|
||||||
"}"
|
"}"
|
||||||
"var sn=0;"
|
"var x=null;" // Allow for abortion
|
||||||
|
"var lt;" // Enable clearTimeout
|
||||||
|
"function la(p){"
|
||||||
|
"var a='';"
|
||||||
|
"if(la.arguments.length==1){"
|
||||||
|
"a='?o='+p;"
|
||||||
|
"clearTimeout(lt);"
|
||||||
|
"}"
|
||||||
|
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||||
|
"x=new XMLHttpRequest();"
|
||||||
|
"x.onreadystatechange=function(){"
|
||||||
|
"if(x.readyState==4&&x.status==200){"
|
||||||
|
"document.getElementById('l1').innerHTML=x.responseText;"
|
||||||
|
"}"
|
||||||
|
"};"
|
||||||
|
"x.open('GET','ay'+a,true);"
|
||||||
|
"x.send();"
|
||||||
|
"lt=setTimeout(la,2000);"
|
||||||
|
"}"
|
||||||
|
"var sn=0;" // Scroll position
|
||||||
|
"var id=99;" // Get most of weblog initially
|
||||||
"function l(){"
|
"function l(){"
|
||||||
"var e=document.getElementById('t1');"
|
"var e=document.getElementById('t1');"
|
||||||
"if(e.scrollTop>=sn){"
|
"if(e.scrollTop>=sn){" // User scrolled back so no updates
|
||||||
"var x=new XMLHttpRequest();"
|
"if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||||
|
"x=new XMLHttpRequest();"
|
||||||
"x.onreadystatechange=function(){"
|
"x.onreadystatechange=function(){"
|
||||||
"if(x.readyState==4&&x.status==200){"
|
"if(x.readyState==4&&x.status==200){"
|
||||||
"var s1=x.responseText;"
|
"var z,d;"
|
||||||
"if(e.value.length==0){"
|
"d=x.responseXML;"
|
||||||
"e.value=s1;"
|
"id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue;"
|
||||||
"}else{"
|
"if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){e.value=\"\";}"
|
||||||
"var s2=e.value.slice(e.value.lastIndexOf(\"\\n\")+2);"
|
"z=d.getElementsByTagName('l')[0].childNodes;"
|
||||||
"var p2=s1.search(s2);"
|
"if(z.length>0){e.value+=z[0].nodeValue;}"
|
||||||
"if(p2>-1){"
|
|
||||||
"e.value=e.value.replace(s2,s1.slice(p2));"
|
|
||||||
"}else{"
|
|
||||||
"e.value=e.value+\"\\n\"+s1;"
|
|
||||||
"}"
|
|
||||||
"}"
|
|
||||||
"e.scrollTop=99999;"
|
"e.scrollTop=99999;"
|
||||||
"sn=e.scrollTop;"
|
"sn=e.scrollTop;"
|
||||||
"}"
|
"}"
|
||||||
"};"
|
"};"
|
||||||
"x.open('GET','ax',true);"
|
"x.open('GET','ax?c2='+id,true);"
|
||||||
"x.send();"
|
"x.send();"
|
||||||
"}"
|
"}"
|
||||||
"setTimeout(l,2000);"
|
"setTimeout(l,2000);"
|
||||||
"}"
|
"}"
|
||||||
|
"function lc(){"
|
||||||
|
"var e=document.getElementById('c1');"
|
||||||
|
// "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1)
|
||||||
|
"var x=new XMLHttpRequest();"
|
||||||
|
"x.open('GET','ax?c1='+e.value+'&c2='+id,true);"
|
||||||
|
"x.send();"
|
||||||
|
"e.value=\"\";"
|
||||||
|
"return false;"
|
||||||
|
"}"
|
||||||
"</script>"
|
"</script>"
|
||||||
"<style>"
|
"<style>"
|
||||||
"div,fieldset,input,select{padding:5px;font-size:1em;}"
|
"div,fieldset,input,select{padding:5px;font-size:1em;}"
|
||||||
|
@ -210,7 +234,7 @@ const char HTTP_FORM_UPG[] PROGMEM =
|
||||||
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>Upload started ...</b></div>";
|
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>Upload started ...</b></div>";
|
||||||
const char HTTP_FORM_CMND[] PROGMEM =
|
const char HTTP_FORM_CMND[] PROGMEM =
|
||||||
"<br/><textarea readonly id='t1' name='t1' cols='99' wrap='off'></textarea><br/><br/>"
|
"<br/><textarea readonly id='t1' name='t1' cols='99' wrap='off'></textarea><br/><br/>"
|
||||||
"<form method='post' action='cs'>"
|
"<form method='get' onsubmit='return lc();'>"
|
||||||
"<input style='width:98%' id='c1' name='c1' length='99' placeholder='Enter command' autofocus><br/>"
|
"<input style='width:98%' id='c1' name='c1' length='99' placeholder='Enter command' autofocus><br/>"
|
||||||
// "<br/><button type='submit'>Send command</button>"
|
// "<br/><button type='submit'>Send command</button>"
|
||||||
"</form>";
|
"</form>";
|
||||||
|
@ -261,6 +285,7 @@ void startWebserver(int type, IPAddress ipweb)
|
||||||
webServer->on("/cm", handleCmnd);
|
webServer->on("/cm", handleCmnd);
|
||||||
webServer->on("/cs", handleConsole);
|
webServer->on("/cs", handleConsole);
|
||||||
webServer->on("/ax", handleAjax);
|
webServer->on("/ax", handleAjax);
|
||||||
|
webServer->on("/ay", handleAjax2);
|
||||||
webServer->on("/in", handleInfo);
|
webServer->on("/in", handleInfo);
|
||||||
webServer->on("/rb", handleRestart);
|
webServer->on("/rb", handleRestart);
|
||||||
webServer->on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
|
webServer->on("/fwlink", handleRoot); // Microsoft captive portal. Maybe not needed. Might be handled by notFound handler.
|
||||||
|
@ -276,6 +301,7 @@ void startWebserver(int type, IPAddress ipweb)
|
||||||
#endif // USE_EMULATION
|
#endif // USE_EMULATION
|
||||||
webServer->onNotFound(handleNotFound);
|
webServer->onNotFound(handleNotFound);
|
||||||
}
|
}
|
||||||
|
logajaxflg = 0;
|
||||||
webServer->begin(); // Web server start
|
webServer->begin(); // Web server start
|
||||||
}
|
}
|
||||||
if (_httpflag != type) {
|
if (_httpflag != type) {
|
||||||
|
@ -356,73 +382,81 @@ void handleRoot()
|
||||||
if (_httpflag == HTTP_MANAGER) {
|
if (_httpflag == HTTP_MANAGER) {
|
||||||
handleWifi0();
|
handleWifi0();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
String page = FPSTR(HTTP_HEAD);
|
String page = FPSTR(HTTP_HEAD);
|
||||||
// page.replace("<meta", "<meta http-equiv=\"refresh\" content=\"4; URL=/\"><meta"); // Fails Edge (asks for reload)
|
|
||||||
// page.replace("</script>", "setTimeout(function(){window.location.reload(1);},4000);</script>"); // Repeats POST on All
|
|
||||||
page.replace("</script>", "setTimeout(function(){window.location.replace(\"/\");},4000);</script>"); // OK on All
|
|
||||||
page.replace("{v}", "Main menu");
|
page.replace("{v}", "Main menu");
|
||||||
|
page.replace("<body>", "<body onload='la()'>");
|
||||||
|
|
||||||
|
page += F("<div id='l1' name='l1'></div>");
|
||||||
if (Maxdevice) {
|
if (Maxdevice) {
|
||||||
if (strlen(webServer->arg("o").c_str())) {
|
|
||||||
do_cmnd_power(atoi(webServer->arg("o").c_str()), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
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:");
|
page += F("<td style='width:");
|
||||||
page += String(100 / Maxdevice);
|
page += String(100 / Maxdevice);
|
||||||
page += F("%'><form action='/?o=");
|
page += F("%'><button onclick='la(");
|
||||||
page += String(idx);
|
page += String(idx);
|
||||||
page += F("' method='post'><div style='text-align:center;font-weight:bold;font-size:");
|
page += F(");'>Toggle");
|
||||||
page += String(70 - (Maxdevice * 8));
|
|
||||||
page += F("px'>");
|
|
||||||
page += (power & (0x01 << (idx -1))) ? "ON" : "OFF";
|
|
||||||
page += F("</div><br/><button>Toggle");
|
|
||||||
if (Maxdevice > 1) {
|
if (Maxdevice > 1) {
|
||||||
page += F(" ");
|
page += F(" ");
|
||||||
page += String(idx);
|
page += String(idx);
|
||||||
}
|
}
|
||||||
page += F("</button></form></td>");
|
page += F("</button></td>");
|
||||||
}
|
}
|
||||||
page += F("</tr></table><br/>");
|
page += F("</tr></table>");
|
||||||
}
|
}
|
||||||
|
|
||||||
String tpage = "";
|
|
||||||
if (hlw_flg) tpage += hlw_webPresent();
|
|
||||||
#ifdef USE_DS18B20
|
|
||||||
if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent();
|
|
||||||
#endif // USE_DS18B20
|
|
||||||
#ifdef USE_DS18x20
|
|
||||||
if (pin[GPIO_DSB] < 99) tpage += ds18x20_webPresent();
|
|
||||||
#endif // USE_DS18x20
|
|
||||||
#ifdef USE_DHT
|
|
||||||
if (dht_type) tpage += dht_webPresent();
|
|
||||||
#endif // USE_DHT
|
|
||||||
#ifdef USE_I2C
|
|
||||||
if (i2c_flg) {
|
|
||||||
tpage += htu_webPresent();
|
|
||||||
tpage += bmp_webPresent();
|
|
||||||
tpage += bh1750_webPresent();
|
|
||||||
}
|
|
||||||
#endif // USE_I2C
|
|
||||||
if (tpage.length() > 0) {
|
|
||||||
page += F("<table style='width:100%'>");
|
|
||||||
page += tpage;
|
|
||||||
page += F("</table><br/>");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_httpflag == HTTP_ADMIN) {
|
if (_httpflag == HTTP_ADMIN) {
|
||||||
page += FPSTR(HTTP_BTN_MENU1);
|
page += FPSTR(HTTP_BTN_MENU1);
|
||||||
page += FPSTR(HTTP_BTN_RSTRT);
|
page += FPSTR(HTTP_BTN_RSTRT);
|
||||||
}
|
}
|
||||||
showPage(page);
|
showPage(page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleAjax2()
|
||||||
|
{
|
||||||
|
if (strlen(webServer->arg("o").c_str())) do_cmnd_power(atoi(webServer->arg("o").c_str()), 2);
|
||||||
|
String tpage = "";
|
||||||
|
if (hlw_flg) tpage += hlw_webPresent();
|
||||||
|
#ifdef USE_DS18B20
|
||||||
|
if (pin[GPIO_DSB] < 99) tpage += dsb_webPresent();
|
||||||
|
#endif // USE_DS18B20
|
||||||
#ifdef USE_DS18x20
|
#ifdef USE_DS18x20
|
||||||
|
if (pin[GPIO_DSB] < 99) {
|
||||||
|
tpage += ds18x20_webPresent();
|
||||||
ds18x20_search(); // Check for changes in sensors number
|
ds18x20_search(); // Check for changes in sensors number
|
||||||
ds18x20_convert(); // Start Conversion, takes up to one second
|
ds18x20_convert(); // Start Conversion, takes up to one second
|
||||||
#endif // USE_DS18x20
|
|
||||||
}
|
}
|
||||||
|
#endif // USE_DS18x20
|
||||||
|
#ifdef USE_DHT
|
||||||
|
if (dht_type) tpage += dht_webPresent();
|
||||||
|
#endif // USE_DHT
|
||||||
|
#ifdef USE_I2C
|
||||||
|
if (i2c_flg) {
|
||||||
|
tpage += htu_webPresent();
|
||||||
|
tpage += bmp_webPresent();
|
||||||
|
tpage += bh1750_webPresent();
|
||||||
|
}
|
||||||
|
#endif // USE_I2C
|
||||||
|
String page = "";
|
||||||
|
if (tpage.length() > 0) {
|
||||||
|
page += F("<table style='width:100%'>");
|
||||||
|
page += tpage;
|
||||||
|
page += F("</table>");
|
||||||
|
}
|
||||||
|
if (Maxdevice) {
|
||||||
|
page += F("<table style='width:100%'><tr>");
|
||||||
|
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.replace("{1", String(100 / Maxdevice));
|
||||||
|
page.replace("{2", String(70 - (Maxdevice * 8)));
|
||||||
|
page.replace("{3", (power & (0x01 << (idx -1))) ? "ON" : "OFF");
|
||||||
|
}
|
||||||
|
page += F("</tr></table>");
|
||||||
|
}
|
||||||
|
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
|
webServer->sendHeader("Pragma", "no-cache");
|
||||||
|
webServer->sendHeader("Expires", "-1");
|
||||||
|
webServer->send(200, "text/plain", page);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean httpUser()
|
boolean httpUser()
|
||||||
|
@ -1119,15 +1153,9 @@ void handleCmnd()
|
||||||
void handleConsole()
|
void handleConsole()
|
||||||
{
|
{
|
||||||
if (httpUser()) return;
|
if (httpUser()) return;
|
||||||
char svalue[MESSZ];
|
|
||||||
|
|
||||||
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle console"));
|
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Handle console"));
|
||||||
|
|
||||||
if (strlen(webServer->arg("c1").c_str())) {
|
|
||||||
snprintf_P(svalue, sizeof(svalue), webServer->arg("c1").c_str());
|
|
||||||
do_cmnd(svalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
String page = FPSTR(HTTP_HEAD);
|
String page = FPSTR(HTTP_HEAD);
|
||||||
page.replace("{v}", "Console");
|
page.replace("{v}", "Console");
|
||||||
page.replace("<body>", "<body onload='l()'>");
|
page.replace("<body>", "<body onload='l()'>");
|
||||||
|
@ -1139,29 +1167,44 @@ void handleConsole()
|
||||||
void handleAjax()
|
void handleAjax()
|
||||||
{
|
{
|
||||||
if (httpUser()) return;
|
if (httpUser()) return;
|
||||||
String message = "";
|
char svalue[MESSZ], log[LOGSZ];
|
||||||
uint16_t size = 0;
|
byte counter = 99;
|
||||||
|
|
||||||
int maxSize = ESP.getFreeHeap() - 6000;
|
if (strlen(webServer->arg("c1").c_str())) {
|
||||||
|
snprintf_P(svalue, sizeof(svalue), webServer->arg("c1").c_str());
|
||||||
|
snprintf_P(log, sizeof(log), PSTR("CMND: %s"), svalue);
|
||||||
|
addLog(LOG_LEVEL_INFO, log);
|
||||||
|
do_cmnd(svalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(webServer->arg("c2").c_str())) counter = atoi(webServer->arg("c2").c_str());
|
||||||
|
|
||||||
byte counter = logidx;
|
String message = F("<r><i>");
|
||||||
do {
|
message += String(logidx);
|
||||||
counter--;
|
message += F("</i><j>");
|
||||||
if (counter == 255) counter = MAX_LOG_LINES -1;
|
message += String(logajaxflg);
|
||||||
size += Log[counter].length();
|
if (!logajaxflg) {
|
||||||
} while ((counter != logidx) && (size < maxSize));
|
counter = 99;
|
||||||
do {
|
logajaxflg = 1;
|
||||||
if (Log[counter].length()) {
|
}
|
||||||
if (message.length()) message += F("\n");
|
message += F("</j><l>");
|
||||||
message += Log[counter];
|
if (counter != logidx) {
|
||||||
}
|
if (counter == 99) counter = logidx;
|
||||||
counter++;
|
do {
|
||||||
if (counter > MAX_LOG_LINES -1) counter = 0;
|
if (Log[counter].length()) {
|
||||||
} while (counter != logidx);
|
message += F("\n");
|
||||||
|
message += Log[counter];
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
if (counter > MAX_LOG_LINES -1) counter = 0;
|
||||||
|
} while (counter != logidx);
|
||||||
|
}
|
||||||
|
message += F("</l></r>");
|
||||||
|
|
||||||
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
webServer->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||||
webServer->sendHeader("Pragma", "no-cache");
|
webServer->sendHeader("Pragma", "no-cache");
|
||||||
webServer->sendHeader("Expires", "-1");
|
webServer->sendHeader("Expires", "-1");
|
||||||
webServer->send(200, "text/plain", message);
|
webServer->send(200, "text/xml", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleInfo()
|
void handleInfo()
|
||||||
|
@ -1274,9 +1317,6 @@ void handleRestart()
|
||||||
restartflag = 2;
|
restartflag = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
|
||||||
void handleNotFound()
|
void handleNotFound()
|
||||||
|
|
Loading…
Reference in New Issue