diff --git a/README.md b/README.md index ee5810873..707214aae 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **3.9.21** - See ```sonoff/_releasenotes.ino``` for change information. +Current version is **3.9.22** - See ```sonoff/_releasenotes.ino``` for change information. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index d2fb0d14d..fed593281 100644 Binary files a/api/arduino/sonoff.ino.bin and b/api/arduino/sonoff.ino.bin differ diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index 0bcd5e4d5..29f7f4c19 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,14 @@ -/* 3.9.21 20170224 +/* 3.9.22 20170228 + * Update web console + * Fix Status 4 JSON message + * Add Exception info during restart if available + * Add osWatch service to detect loop hangs that might happen during (OTA) upgrades + * Add WiOn support for relay and switch only (#82, #102) + * Allow for user specified relay count up to four in sonoff_template.h (#109) + * Add support for HTU21 compatible I2C sensors SI7013, SI7020 and SI7021 (#118) + * Add NodeMCU or Wemos configuration option (#119) + * + * 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 diff --git a/sonoff/settings.h b/sonoff/settings.h index 55ee022c4..c0aced8e8 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -189,3 +189,10 @@ struct SYSCFG { } sysCfg; +struct RTCMEM { + uint16_t valid; + byte osw_flag; + byte nu1; + unsigned long hlw_kWhtoday; +} rtcMem; + diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 9112638a2..f94567546 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -23,6 +23,85 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*********************************************************************************************\ + * RTC memory +\*********************************************************************************************/ + +#define RTC_MEM_VALID 0xA55A + +uint32_t _rtcHash = 0; + +uint32_t getRtcHash() +{ + uint32_t hash = 0; + uint8_t *bytes = (uint8_t*)&rtcMem; + + for (uint16_t i = 0; i < sizeof(RTCMEM); i++) hash += bytes[i]*(i+1); + return hash; +} + +void RTC_Save() +{ + if (getRtcHash() != _rtcHash) { + rtcMem.valid = RTC_MEM_VALID; + ESP.rtcUserMemoryWrite(100, (uint32_t*)&rtcMem, sizeof(RTCMEM)); + _rtcHash = getRtcHash(); +#ifdef DEBUG_THEO + addLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Save")); + RTC_Dump(); +#endif // DEBUG_THEO + } +} + +void RTC_Load() +{ + ESP.rtcUserMemoryRead(100, (uint32_t*)&rtcMem, sizeof(RTCMEM)); +#ifdef DEBUG_THEO + addLog_P(LOG_LEVEL_DEBUG, PSTR("Dump: Load")); + RTC_Dump(); +#endif // DEBUG_THEO + if (rtcMem.valid != RTC_MEM_VALID) { + memset(&rtcMem, 0x00, sizeof(RTCMEM)); + rtcMem.valid = RTC_MEM_VALID; + RTC_Save(); + } + _rtcHash = getRtcHash(); +} + +boolean RTC_Valid() +{ + return (rtcMem.valid == RTC_MEM_VALID); +} + +#ifdef DEBUG_THEO +void RTC_Dump() +{ + #define CFG_COLS 16 + + char log[LOGSZ]; + uint16_t idx, maxrow, row, col; + + uint8_t *buffer = (uint8_t *) &rtcMem; + maxrow = ((sizeof(RTCMEM)+CFG_COLS)/CFG_COLS); + + for (row = 0; row < maxrow; row++) { + idx = row * CFG_COLS; + snprintf_P(log, sizeof(log), PSTR("%04X:"), idx); + for (col = 0; col < CFG_COLS; col++) { + if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + snprintf_P(log, sizeof(log), PSTR("%s %02X"), log, buffer[idx + col]); + } + snprintf_P(log, sizeof(log), PSTR("%s |"), log); + for (col = 0; col < CFG_COLS; col++) { +// if (!(col%4)) snprintf_P(log, sizeof(log), PSTR("%s "), log); + snprintf_P(log, sizeof(log), PSTR("%s%c"), log, ((buffer[idx + col] > 0x20) && (buffer[idx + col] < 0x7F)) ? (char)buffer[idx + col] : ' '); + } + snprintf_P(log, sizeof(log), PSTR("%s|"), log); + addLog(LOG_LEVEL_INFO, log); + } +} +#endif // DEBUG_THEO + /*********************************************************************************************\ * Config - Flash or Spiffs \*********************************************************************************************/ @@ -131,6 +210,7 @@ void CFG_Save() } _cfgHash = getHash(); } + RTC_Save(); } void CFG_Load() @@ -177,6 +257,8 @@ void CFG_Load() } } _cfgHash = getHash(); + + RTC_Load(); } void CFG_Migrate() diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 1b6fc9c7d..0ac0d0473 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x03091500 // 3.9.21 +#define VERSION 0x03091600 // 3.9.22 //#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 @@ -45,6 +45,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #ifndef USE_DS18x20 #define USE_DS18B20 // Default DS18B20 sensor needs no external library #endif +//#define DEBUG_THEO // Add debug code #ifdef BE_MINIMAL //#ifdef USE_MQTT_TLS @@ -80,6 +81,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #ifdef USE_IR_REMOTE #undef USE_IR_REMOTE // Disable IR driver #endif +#ifdef DEBUG_THEO +#undef DEBUG_THEO // Disable debug code +#endif #endif // BE_MINIMAL #ifndef SWITCH_MODE @@ -497,6 +501,9 @@ void mqtt_connected() mqtt_publish_topic_P(1, PSTR("INFO2"), svalue); } #endif // USE_WEBSERVER + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Started\":\"%s\"}"), + (getResetReason() == "Exception") ? ESP.getResetInfo().c_str() : getResetReason().c_str()); + 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); @@ -1167,7 +1174,13 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) else if ((pin[GPIO_IRSEND] < 99) && ir_send_command(type, index, dataBufUc, data_len, payload, svalue, sizeof(svalue))) { // Serviced } -#endif // USE_IR_REMOTE +#endif // USE_IR_REMOTE +#ifdef DEBUG_THEO + else if (!strcmp(type,"EXCEPTION")) { + if (data_len > 0) exception_tst(payload); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Exception\":\"Triggered\"}")); + } +#endif // DEBUG_THEO else { type = NULL; } @@ -1369,7 +1382,7 @@ void publish_status(uint8_t payload) } if ((payload == 0) || (payload == 4)) { - snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMEM\":{\"ProgramSize\":%d, \"Free\":%d, \"Heap\":%d, \"SpiffsStart\":%d, \"SpiffsSize\":%d, \"FlashSize\":%d, \"ProgramFlashSize\":%d, \"FlashChipMode\",%d}}"), + snprintf_P(svalue, sizeof(svalue), PSTR("{\"StatusMEM\":{\"ProgramSize\":%d, \"Free\":%d, \"Heap\":%d, \"SpiffsStart\":%d, \"SpiffsSize\":%d, \"FlashSize\":%d, \"ProgramFlashSize\":%d, \"FlashChipMode\":%d}}"), ESP.getSketchSize()/1024, ESP.getFreeSketchSpace()/1024, ESP.getFreeHeap()/1024, ((uint32_t)&_SPIFFS_start - 0x40200000)/1024, (((uint32_t)&_SPIFFS_end - 0x40200000) - ((uint32_t)&_SPIFFS_start - 0x40200000))/1024, ESP.getFlashChipRealSize()/1024, ESP.getFlashChipSize()/1024, ESP.getFlashChipMode()); mqtt_publish_topic_P(option, PSTR("STATUS4"), svalue); @@ -1916,20 +1929,12 @@ void GPIO_init() } Maxdevice = 1; - switch (sysCfg.module) { - case SONOFF_DUAL: - case ELECTRODRAGON: - Maxdevice = 2; - break; - case SONOFF_4CH: - case CH4: - Maxdevice = 4; - break; + if (sysCfg.module == SONOFF_DUAL) { + Maxdevice = 2; + Baudrate = 19200; } - - swt_flg = ((pin[GPIO_SWT1] < 99) || (pin[GPIO_SWT2] < 99) || (pin[GPIO_SWT3] < 99) || (pin[GPIO_SWT4] < 99)); - - if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { + else if (sysCfg.module == CH4) { + Maxdevice = 4; Baudrate = 19200; } else if (sysCfg.module == SONOFF_LED) { @@ -1937,9 +1942,13 @@ void GPIO_init() sl_init(); } else { + Maxdevice = 0; for (byte i = 0; i < 4; i++) { + if (pin[GPIO_REL1 +i] < 99) { + pinMode(pin[GPIO_REL1 +i], OUTPUT); + Maxdevice++; + } if (pin[GPIO_KEY1 +i] < 99) pinMode(pin[GPIO_KEY1 +i], INPUT_PULLUP); - if (pin[GPIO_REL1 +i] < 99) pinMode(pin[GPIO_REL1 +i], OUTPUT); } } for (byte i = 0; i < 4; i++) { @@ -1948,6 +1957,7 @@ void GPIO_init() digitalWrite(pin[GPIO_LED1 +i], led_inverted[i]); } if (pin[GPIO_SWT1 +i] < 99) { + swt_flg = 1; pinMode(pin[GPIO_SWT1 +i], INPUT_PULLUP); lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // set global now so doesn't change the saved power state on first switch check } @@ -2007,6 +2017,8 @@ void setup() CFG_Load(); CFG_Delta(); + osw_init(); + sysCfg.bootcount++; snprintf_P(log, sizeof(log), PSTR("APP: Bootcount %d"), sysCfg.bootcount); addLog(LOG_LEVEL_DEBUG, log); @@ -2073,6 +2085,8 @@ void setup() void loop() { + osw_loop(); + #ifdef USE_WEBSERVER pollDnsWeb(); #endif // USE_WEBSERVER diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 598992632..960e00682 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -90,6 +90,8 @@ enum module_t { MOTOR, ELECTRODRAGON, EXS_RELAY, + WION, + NODEMCU, USER_TEST, MAXMODULE }; @@ -283,6 +285,34 @@ const mytmplt modules[MAXMODULE] PROGMEM = { 0, GPIO_USER // GPIO16 Module Pin 4 }, + { "WiOn", // Indoor Tap https://www.amazon.com/gp/product/B00ZYLUBJU/ref=s9_acsd_al_bw_c_x_3_w + GPIO_USER, // GPIO00 Optional sensor (pm clock) + 0, + GPIO_LED1, // GPIO02 Green Led (1 = On, 0 = Off) + 0, 0, 0, 0, 0, 0, 0, 0, 0, + GPIO_USER, // GPIO12 Optional sensor (pm data) + GPIO_KEY1, // GPIO13 Button + 0, + GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On) + 0 + }, + { "NodeMCU", // NodeMCU and Wemos hardware + GPIO_KEY1, // GPIO00 Button + GPIO_USER, // GPIO01 Serial RXD + GPIO_USER, // GPIO02 + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + GPIO_USER, // GPIO04 Optional sensor + GPIO_USER, // GPIO05 + 0, 0, 0, + GPIO_USER, // GPIO09 + GPIO_USER, // GPIO10 + 0, + GPIO_USER, // GPIO12 + GPIO_USER, // GPIO13 + GPIO_USER, // GPIO14 + GPIO_USER, // GPIO15 + 0 + }, { "User Test", // Sonoff Basic User Test GPIO_KEY1, // GPIO00 Button 0, diff --git a/sonoff/support.ino b/sonoff/support.ino index a13c74447..ecbd50b52 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -23,6 +23,127 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/*********************************************************************************************\ + * Watchdog extension (https://github.com/esp8266/Arduino/issues/1532) +\*********************************************************************************************/ + +Ticker tickerOSWatch; + +#define OSWATCH_RESET_TIME 30 + +static unsigned long osw_last_loop; +byte osw_flag = 0; + +void ICACHE_RAM_ATTR osw_osWatch(void) +{ + unsigned long t = millis(); + unsigned long last_run = abs(t - osw_last_loop); + +#ifdef DEBUG_THEO + char log[LOGSZ]; + snprintf_P(log, sizeof(log), PSTR("osWatch: FreeRam %d, rssi %d, last_run %d"), ESP.getFreeHeap(), WIFI_getRSSIasQuality(WiFi.RSSI()), last_run); + addLog(LOG_LEVEL_DEBUG, log); +#endif // DEBUG_THEO + if(last_run >= (OSWATCH_RESET_TIME * 1000)) { + addLog_P(LOG_LEVEL_INFO, PSTR("osWatch: Warning, loop blocked. Restart now")); + rtcMem.osw_flag = 1; + RTC_Save(); +// ESP.restart(); // normal reboot + ESP.reset(); // hard reset + } +} + +void osw_init() +{ + osw_flag = rtcMem.osw_flag; + rtcMem.osw_flag = 0; + osw_last_loop = millis(); + tickerOSWatch.attach_ms(((OSWATCH_RESET_TIME / 3) * 1000), osw_osWatch); +} + +void osw_loop() +{ + osw_last_loop = millis(); +// while(1) delay(1000); // this will trigger the os watch +} + +String getResetReason() +{ + char buff[32]; + if (osw_flag) { + strcpy_P(buff, PSTR("Blocked Loop")); + return String(buff); + } else { + return ESP.getResetReason(); + } +} + +#ifdef DEBUG_THEO +void exception_tst(byte type) +{ +/* +Exception (28): +epc1=0x4000bf64 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000007 depc=0x00000000 + +ctx: cont +sp: 3fff1f30 end: 3fff2840 offset: 01a0 + +>>>stack>>> +3fff20d0: 202c3573 756f7247 2c302070 646e4920 +3fff20e0: 40236a6e 7954202c 45206570 00454358 +3fff20f0: 00000010 00000007 00000000 3fff2180 +3fff2100: 3fff2190 40107bfc 3fff3e4c 3fff22c0 +3fff2110: 40261934 000000f0 3fff22c0 401004d8 +3fff2120: 40238fcf 00000050 3fff2100 4021fc10 +3fff2130: 3fff32bc 4021680c 3ffeade1 4021ff7d +3fff2140: 3fff2190 3fff2180 0000000c 7fffffff +3fff2150: 00000019 00000000 00000000 3fff21c0 +3fff2160: 3fff23f3 3ffe8e08 00000000 4021ffb4 +3fff2170: 3fff2190 3fff2180 0000000c 40201118 +3fff2180: 3fff21c0 0000003c 3ffef840 00000007 +3fff2190: 00000000 00000000 00000000 40201128 +3fff21a0: 3fff23f3 000000f1 3fff23ec 4020fafb +3fff21b0: 3fff23f3 3fff21c0 3fff21d0 3fff23f6 +3fff21c0: 00000000 3fff23fb 4022321b 00000000 + +Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads +Decoding 14 results +0x40236a6e: ets_vsnprintf at ?? line ? +0x40107bfc: vsnprintf at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/libc_replacements.c line 387 +0x40261934: bignum_exptmod at ?? line ? +0x401004d8: malloc at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266\umm_malloc/umm_malloc.c line 1664 +0x40238fcf: wifi_station_get_connect_status at ?? line ? +0x4021fc10: operator new[](unsigned int) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/abi.cpp line 57 +0x4021680c: ESP8266WiFiSTAClass::status() at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\libraries\ESP8266WiFi\src/ESP8266WiFiSTA.cpp line 569 +0x4021ff7d: vsnprintf_P(char*, unsigned int, char const*, __va_list_tag) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146 +0x4021ffb4: snprintf_P(char*, unsigned int, char const*, ...) at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/pgmspace.cpp line 146 +0x40201118: atol at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45 +0x40201128: atoi at C:\Data2\Arduino\arduino-1.8.1-esp-2.3.0\portable\packages\esp8266\hardware\esp8266\2.3.0\cores\esp8266/core_esp8266_noniso.c line 45 +0x4020fafb: mqttDataCb(char*, unsigned char*, unsigned int) at R:\Arduino\Work-ESP8266\Theo\sonoff\sonoff-4\sonoff/sonoff.ino line 679 (discriminator 1) +0x4022321b: pp_attach at ?? line ? + +00:00:08 MQTT: tele/sonoff/INFO3 = {"Started":"Fatal exception:28 flag:2 (EXCEPTION) epc1:0x4000bf64 epc2:0x00000000 epc3:0x00000000 excvaddr:0x00000007 depc:0x00000000"} +*/ + if (type == 1) { + char svalue[10]; + snprintf_P(svalue, sizeof(svalue), PSTR("%s"), 7); // Exception 28 as number in string (7 in excvaddr) + } +/* +14:50:52 osWatch: FreeRam 25896, rssi 68, last_run 0 +14:51:02 osWatch: FreeRam 25896, rssi 58, last_run 0 +14:51:03 CMND: exception 2 +14:51:12 osWatch: FreeRam 25360, rssi 60, last_run 8771 +14:51:22 osWatch: FreeRam 25360, rssi 62, last_run 18771 +14:51:32 osWatch: FreeRam 25360, rssi 62, last_run 28771 +14:51:42 osWatch: FreeRam 25360, rssi 62, last_run 38771 +14:51:42 osWatch: Warning, loop blocked. Restart now +*/ + if (type == 2) { + while(1) delay(1000); // this will trigger the os watch + } +} +#endif // DEBUG_THEO + /*********************************************************************************************\ * Wifi \*********************************************************************************************/ @@ -703,9 +824,6 @@ void addLog(byte loglevel, const char *line) snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d:%02d:%02d"), rtcTime.Hour, rtcTime.Minute, rtcTime.Second); -#ifdef DEBUG_ESP_PORT - DEBUG_ESP_PORT.printf("%s %s\n", mxtime, line); -#endif // DEBUG_ESP_PORT if (loglevel <= seriallog_level) Serial.printf("%s %s\n", mxtime, line); #ifdef USE_WEBSERVER if (sysCfg.webserver && (loglevel <= sysCfg.weblog_level)) { diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 0581ad6ed..032f72613 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -124,7 +124,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_BMP // Add I2C code for BMP/BME280 sensor - #define USE_HTU // Add I2C code for HTU21 sensor + #define USE_HTU // Add I2C code for HTU21/SI7013/SI7020/SI7021 sensor #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0.3k mem) diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index 83233d952..3eba1f96f 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -70,13 +70,22 @@ const char HTTP_HEAD[] PROGMEM = "};" "x.open('GET','ay'+a,true);" "x.send();" - "lt=setTimeout(la,2000);" + "lt=setTimeout(la,2345);" "}" "var sn=0;" // Scroll position "var id=99;" // Get most of weblog initially - "function l(){" - "var e=document.getElementById('t1');" - "if(e.scrollTop>=sn){" // User scrolled back so no updates + "function l(p){" // Console log and command service + "var c,o,t;" + "clearTimeout(lt);" + "o='';" + "t=document.getElementById('t1');" + "if(p==1){" + "c=document.getElementById('c1');" + "o='&c1='+c.value;" + "c.value='';" + "t.scrollTop=sn;" + "}" + "if(t.scrollTop>=sn){" // User scrolled back so no updates "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) "x=new XMLHttpRequest();" "x.onreadystatechange=function(){" @@ -84,25 +93,17 @@ const char HTTP_HEAD[] PROGMEM = "var z,d;" "d=x.responseXML;" "id=d.getElementsByTagName('i')[0].childNodes[0].nodeValue;" - "if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){e.value=\"\";}" + "if(d.getElementsByTagName('j')[0].childNodes[0].nodeValue==0){t.value='';}" "z=d.getElementsByTagName('l')[0].childNodes;" - "if(z.length>0){e.value+=z[0].nodeValue;}" - "e.scrollTop=99999;" - "sn=e.scrollTop;" + "if(z.length>0){t.value+=z[0].nodeValue;}" + "t.scrollTop=99999;" + "sn=t.scrollTop;" "}" "};" - "x.open('GET','ax?c2='+id,true);" + "x.open('GET','ax?c2='+id+o,true);" "x.send();" "}" - "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=\"\";" + "lt=setTimeout(l,2345);" "return false;" "}" "" @@ -122,7 +123,7 @@ const char HTTP_HEAD[] PROGMEM = "" "" "
" - "