diff --git a/README.md b/README.md index 576b8d641..133fdbc36 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 **4.1.1** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **4.1.2** - 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. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. diff --git a/api/arduino/sonoff-minimal.ino.bin b/api/arduino/sonoff-minimal.ino.bin index c6521482c..3ff1cd6f2 100644 Binary files a/api/arduino/sonoff-minimal.ino.bin and b/api/arduino/sonoff-minimal.ino.bin differ diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index dcb2b7dae..25d0697b6 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 dfc95579d..8369fe09b 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,13 @@ -/* 4.1.1 20170329 +/* 4.1.2 20170403 + * Rename Unrecognised command to Unknown command + * Remove all command lists + * Remove command SmartConfig (superseded by WifiConfig) + * Fix boot loop when selecting module Sonoff 4CH or Sonoff Touch on non ESP8285 hardware + * Add optional support for Toshiba and Mitsubishi HVAC IR control (needs updated IRanother (#257) + * Add all configured switches to Domoticz Configuration web page (#305) + * Fix compile error when selecting WS2812 DMA (#313) + * + * 4.1.1 20170329 * Fix default Telemetry for command Prefix3 * Fix webserver Module parameters for disabled select * Fix sensor status for enabled switches diff --git a/sonoff/settings.ino b/sonoff/settings.ino index 036a3b238..080ef0140 100644 --- a/sonoff/settings.ino +++ b/sonoff/settings.ino @@ -125,12 +125,15 @@ int spiffsflag = 0; /* * Based on cores/esp8266/Updater.cpp */ -void setFlashChipMode(byte option, byte mode) +void setFlashMode(byte option, byte mode) { char log[LOGSZ]; uint8_t *_buffer; uint32_t address; +// option 0 - Use absolute address 0 +// option 1 - Use OTA/Upgrade relative address + if (option) { eboot_command ebcmd; eboot_command_read(&ebcmd); @@ -147,13 +150,20 @@ void setFlashChipMode(byte option, byte mode) spi_flash_write(address, (uint32_t*)_buffer, FLASH_SECTOR_SIZE); } interrupts(); - snprintf_P(log, sizeof(log), PSTR("FLSH: Updated Flash Chip Mode to %d"), (option) ? mode : ESP.getFlashChipMode()); + snprintf_P(log, sizeof(log), PSTR("FLSH: Set Flash Mode to %d"), (option) ? mode : ESP.getFlashChipMode()); addLog(LOG_LEVEL_DEBUG, log); } } delete[] _buffer; } +void setModuleFlashMode(byte option) +{ + uint8_t mode = 0; // QIO - ESP8266 + if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) mode = 3; // DOUT - ESP8285 + setFlashMode(option, mode); +} + boolean spiffsPresent() { return (SPIFFS_END - SPIFFS_START); diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index fb9658d84..2261f40f4 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,7 @@ * ==================================================== */ -#define VERSION 0x04010100 // 4.1.1 +#define VERSION 0x04010200 // 4.1.2 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}; @@ -541,7 +541,7 @@ void mqtt_reconnect() #ifdef USE_MQTT_TLS addLog_P(LOG_LEVEL_INFO, PSTR("MQTT: Verify TLS fingerprint...")); if (!espClient.connect(sysCfg.mqtt_host, sysCfg.mqtt_port)) { - snprintf_P(log, sizeof(log), PSTR("MQTT: TLS CONNECT FAILED USING WRONG MQTTHost (%s) or MQTTPort (%d). Retry in %d seconds"), + snprintf_P(log, sizeof(log), PSTR("MQTT: TLS Connect FAILED to %s:%d. Retry in %d seconds"), sysCfg.mqtt_host, sysCfg.mqtt_port, mqttcounter); addLog(LOG_LEVEL_DEBUG, log); return; @@ -549,7 +549,7 @@ void mqtt_reconnect() if (espClient.verify(sysCfg.mqtt_fingerprint, sysCfg.mqtt_host)) { addLog_P(LOG_LEVEL_INFO, PSTR("MQTT: Verified")); } else { - addLog_P(LOG_LEVEL_DEBUG, PSTR("MQTT: WARNING - Insecure connection due to invalid Fingerprint")); + addLog_P(LOG_LEVEL_DEBUG, PSTR("MQTT: Insecure connection due to invalid Fingerprint")); } #endif // USE_MQTT_TLS mqttClient.setCallback(mqttDataCb); @@ -613,7 +613,8 @@ boolean mqtt_command(boolean grpflg, char *type, uint16_t index, char *dataBuf, else if (!strcmp(type,"STATETEXT") && (index > 0) && (index <= 3)) { if ((data_len > 0) && (data_len < sizeof(sysCfg.state_text[0]))) { for(i = 0; i <= data_len; i++) if (dataBuf[i] == ' ') dataBuf[i] = '_'; - strlcpy(sysCfg.state_text[index -1], (payload == 1) ? (index==1)?MQTT_STATUS_OFF:(index==2)?MQTT_STATUS_ON:MQTT_CMND_TOGGLE : dataBuf, sizeof(sysCfg.state_text[0])); +// strlcpy(sysCfg.state_text[index -1], (payload == 1) ? (index==1)?MQTT_STATUS_OFF:(index==2)?MQTT_STATUS_ON:MQTT_CMND_TOGGLE : dataBuf, sizeof(sysCfg.state_text[0])); + strlcpy(sysCfg.state_text[index -1], dataBuf, sizeof(sysCfg.state_text[0])); } snprintf_P(svalue, ssvalue, PSTR("{\"StateText%d\":\"%s\"}"), index, getStateText(index -1)); } @@ -899,7 +900,10 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) payload--; byte new_modflg = (sysCfg.module != payload); sysCfg.module = payload; - if (new_modflg) for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + if (new_modflg) { + for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0; + setModuleFlashMode(0); + } restartflag = 2; } snprintf_P(stemp1, sizeof(stemp1), modules[sysCfg.module].name); @@ -997,11 +1001,11 @@ 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" : ""); } - else if (!strcmp(type,"FLASHCHIPMODE")) { + else if (!strcmp(type,"FLASHMODE")) { // 0 = QIO, 1 = QOUT, 2 = DIO, 3 = DOUT if ((data_len > 0) && (payload >= 0) && (payload <= 3)) { - if (ESP.getFlashChipMode() != payload) setFlashChipMode(0, payload &3); + if (ESP.getFlashChipMode() != payload) setFlashMode(0, payload &3); } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashChipMode\":%d}"), ESP.getFlashChipMode()); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"FlashMode\":%d}"), ESP.getFlashChipMode()); } else if (!strcmp(type,"UPGRADE") || !strcmp(type,"UPLOAD")) { if ((data_len > 0) && (payload == 1)) { @@ -1098,7 +1102,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } snprintf_P(svalue, sizeof(svalue), PSTR("{\"Hostname\":\"%s\"}"), sysCfg.hostname); } - else if (!strcmp(type,"WIFICONFIG") || !strcmp(type,"SMARTCONFIG")) { + else if (!strcmp(type,"WIFICONFIG")) { if ((data_len > 0) && (payload >= WIFI_RESTART) && (payload < MAX_WIFI_OPTION)) { sysCfg.sta_config = payload; wificheckflag = sysCfg.sta_config; @@ -1267,47 +1271,11 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) } if (type == NULL) { blinks = 201; -/* - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands1\":\"Status, SaveData, SaveSate, Sleep, Upgrade, Otaurl, Restart, Reset, WifiConfig, Seriallog, Syslog, LogHost, LogPort, SSId, Password, AP, IPAddres, NTPServer, Hostname, Module, Modules, GPIO, GPIOs\"}")); - mqtt_publish_topic_P(0, PSTR("COMMANDS1"), svalue); - - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands2\":\"Mqtt, MqttResponse, MqttHost, MqttPort, MqttUser, MqttPassword, MqttClient, Topic, GroupTopic, ButtonTopic, ButtonRetain, SwitchTopic, SwitchRetain, PowerRetain, Units, Timezone, LedState, LedPower, TelePeriod\"}")); - mqtt_publish_topic_P(0, PSTR("COMMANDS2"), svalue); - - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Commands3\":\"Power%s, PulseTime, BlinkTime, BlinkCount, ButtonRestrict"), (sysCfg.module != MOTOR) ? ", PowerOnState" : ""); -#ifdef USE_WEBSERVER - snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, WebPassword, Emulation"), svalue); -#endif - if (swt_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, SwitchMode"), svalue); - if (pwm_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, PWM"), svalue); -#ifdef USE_I2C - if (i2c_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, I2CScan"), svalue); -#endif // USE_I2C - if (sysCfg.module == SONOFF_LED) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Color, Dimmer, Fade, Speed, Wakeup, WakeupDuration, LedTable"), svalue); -#ifdef USE_WS2812 - if (pin[GPIO_WS2812] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, Color, Dimmer, Fade, Speed, Wakeup, LedTable, Pixels, Led, Width, Scheme"), svalue); -#endif -#ifdef USE_IR_REMOTE - if (pin[GPIO_IRSEND] < 99) snprintf_P(svalue, sizeof(svalue), PSTR("%s, IRSend"), svalue); -#endif - snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); - mqtt_publish_topic_P(0, PSTR("COMMANDS3"), svalue); - -#ifdef USE_DOMOTICZ - domoticz_commands(svalue, sizeof(svalue)); - mqtt_publish_topic_P(0, PSTR("COMMANDS4"), svalue); -#endif // USE_DOMOTICZ - - if (hlw_flg) { - hlw_commands(svalue, sizeof(svalue)); - mqtt_publish_topic_P(0, PSTR("COMMANDS5"), svalue); - } -*/ - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Invalid command\"}")); - mqtt_publish_topic_P(0, PSTR("COMMAND"), svalue); - } else { - mqtt_publish_topic_P(4, type, svalue); + snprintf_P(topicBuf, sizeof(topicBuf), PSTR("COMMAND")); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Command\":\"Unknown\"}")); + type = (char*)topicBuf; } + mqtt_publish_topic_P(4, type, svalue); } /********************************************************************************************/ @@ -1465,7 +1433,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, \"FlashMode\":%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); @@ -1879,7 +1847,7 @@ void stateloop() if (otaflag == 90) { // Allow MQTT to reconnect otaflag = 0; if (otaok) { - if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) setFlashChipMode(1, 3); // DOUT - ESP8285 + setModuleFlashMode(1); // QIO - ESP8266, DOUT - ESP8285 (Sonoff 4CH and Touch) snprintf_P(svalue, sizeof(svalue), PSTR("Successful. Restarting")); } else { snprintf_P(svalue, sizeof(svalue), PSTR("Failed %s"), ESPhttpUpdate.getLastErrorString().c_str()); @@ -2160,7 +2128,7 @@ void setup() if (Serial.baudRate() != Baudrate) { if (seriallog_level) { - snprintf_P(log, sizeof(log), PSTR("APP: Change baudrate to %d and Serial logging will be disabled in %d seconds"), Baudrate, seriallog_timer); + snprintf_P(log, sizeof(log), PSTR("APP: Change your baudrate to %d"), Baudrate); addLog(LOG_LEVEL_INFO, log); } delay(100); diff --git a/sonoff/support.ino b/sonoff/support.ino index 89fa5835f..5730146d9 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -23,6 +23,9 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +const char JSON_SNS_TEMPHUM[] PROGMEM = + "%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s}"; + /*********************************************************************************************\ * Watchdog extension (https://github.com/esp8266/Arduino/issues/1532) \*********************************************************************************************/ @@ -34,7 +37,11 @@ Ticker tickerOSWatch; static unsigned long osw_last_loop; byte osw_flag = 0; -void ICACHE_RAM_ATTR osw_osWatch(void) +#ifndef USE_WS2812_DMA // Collides with Neopixelbus but solves exception +void osw_osWatch() ICACHE_RAM_ATTR; +#endif // USE_WS2812_DMA + +void osw_osWatch() { unsigned long t = millis(); unsigned long last_run = abs(t - osw_last_loop); @@ -599,7 +606,7 @@ void i2c_scan(char *devs, unsigned int devs_len) strncat(devs, tstr, devs_len); any = 1; } - else if (error == 4) snprintf_P(devs, devs_len, PSTR("{\"I2Cscan\":\"Unknow error at 0x%2x\"}"), address); + else if (error == 4) snprintf_P(devs, devs_len, PSTR("{\"I2Cscan\":\"Unknown error at 0x%2x\"}"), address); } if (any) { strncat(devs, "\"}", devs_len); diff --git a/sonoff/user_config.h b/sonoff/user_config.h index e3796e06f..e73361d53 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -90,7 +90,7 @@ #define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa #define USE_EMULATION // Enable Belkin WeMo and Hue Bridge emulation for Alexa (+11k code, +2k mem) - #define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo or Hue Bridge emulation (EMUL_NONE, EMUL_WEMO or EMUL_HUE) + #define EMULATION EMUL_NONE // [Emulation] Select Belkin WeMo (single relay/light) or Hue Bridge emulation (multi relay/light) (EMUL_NONE, EMUL_WEMO or EMUL_HUE) // -- mDNS ---------------------------------------- #define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) - Disable by // @@ -138,6 +138,7 @@ #define USE_SHT // Add I2C emulating code for SHT1X sensor #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+3k code, 0.3k mem) +// #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+8k code, +1k mem) - Disable by // #define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB) diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index fa230f5c6..f131bd934 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -103,7 +103,6 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM = "t=document.getElementById('t1');" "if(p==1){" "c=document.getElementById('c1');" -// "o='&c1='+c.value;" "o='&c1='+encodeURI(c.value);" "c.value='';" "t.scrollTop=sn;" @@ -223,8 +222,8 @@ const char HTTP_FORM_OTHER2[] PROGMEM = const char HTTP_FORM_OTHER3[] PROGMEM = "
 Emulation " "
None" - "
Belkin WeMo" - "
Hue Bridge
"; + "
Belkin WeMo single device" + "
Hue Bridge multi devices
"; #endif // USE_EMULATION const char HTTP_FORM_END[] PROGMEM = "
"; @@ -258,6 +257,8 @@ const char HTTP_FORM_CMND[] PROGMEM = "
" // "
" ""; +const char HTTP_TABLE100[] PROGMEM = + ""; const char HTTP_COUNTER[] PROGMEM = "
"; const char HTTP_SNS_TEMP[] PROGMEM = @@ -420,7 +421,8 @@ void handleRoot() sysCfg.led_dimmer[0]); page += line; } - page += F("
"); + page += FPSTR(HTTP_TABLE100); + page += F(""); for (byte idx = 1; idx <= Maxdevice; idx++) { snprintf_P(stemp, sizeof(stemp), PSTR(" %d"), idx); snprintf_P(line, sizeof(line), PSTR(""), @@ -477,16 +479,18 @@ void handleAjax2() #endif // USE_I2C String page = ""; if (tpage.length() > 0) { - page += F("
"); + page += FPSTR(HTTP_TABLE100); page += tpage; page += F("
"); } char line[120]; if (Maxdevice) { - page += F(""); + page += FPSTR(HTTP_TABLE100); + page += F(""); for (byte idx = 1; idx <= Maxdevice; idx++) { snprintf_P(line, sizeof(line), PSTR(""), - 100 / Maxdevice, 70 - (Maxdevice * 8), (power & (0x01 << (idx -1))) ? "ON" : "OFF"); +// 100 / Maxdevice, 70 - (Maxdevice * 8), (power & (0x01 << (idx -1))) ? "ON" : "OFF"); + 100 / Maxdevice, 70 - (Maxdevice * 8), getStateText(bitRead(power, idx -1))); page += line; } page += F("
%s
"); @@ -528,6 +532,8 @@ void handleConfig() boolean inModule(byte val, uint8_t *arr) { + int offset = 0; + if (!val) return false; // None #ifndef USE_I2C if (val == GPIO_I2C_SCL) return true; @@ -539,8 +545,11 @@ boolean inModule(byte val, uint8_t *arr) #ifndef USE_IR_REMOTE if (val == GPIO_IRSEND) return true; #endif + if (((val >= GPIO_REL1) && (val <= GPIO_REL4)) || ((val >= GPIO_LED1) && (val <= GPIO_LED4))) offset = 4; + if (((val >= GPIO_REL1_INV) && (val <= GPIO_REL4_INV)) || ((val >= GPIO_LED1_INV) && (val <= GPIO_LED4_INV))) offset = -4; for (byte i = 0; i < MAX_GPIO_PIN; i++) { if (arr[i] == val) return true; + if (arr[i] == val + offset) return true; } return false; } @@ -905,12 +914,14 @@ void handleSave() memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule)); String gpios = ""; for (byte i = 0; i < MAX_GPIO_PIN; i++) { + if (new_modflg) sysCfg.my_module.gp.io[i] = 0; if (cmodule.gp.io[i] == GPIO_USER) { snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); - sysCfg.my_module.gp.io[i] = (new_modflg) ? 0 : (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str()); + sysCfg.my_module.gp.io[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str()); gpios += F(", GPIO"); gpios += String(i); gpios += F(" "); gpios += String(sysCfg.my_module.gp.io[i]); } } + setModuleFlashMode(0); snprintf_P(stemp, sizeof(stemp), modules[sysCfg.module].name); snprintf_P(log, sizeof(log), PSTR("HTTP: %s Module%s"), stemp, gpios.c_str()); addLog(LOG_LEVEL_INFO, log); @@ -1118,7 +1129,7 @@ void handleUploadLoop() } if ((sysCfg.module == SONOFF_TOUCH) || (sysCfg.module == SONOFF_4CH)) { upload.buf[2] = 3; // DOUT - ESP8285 - addLog_P(LOG_LEVEL_DEBUG, PSTR("FLSH: Updated Flash Chip Mode to 3")); + addLog_P(LOG_LEVEL_DEBUG, PSTR("FLSH: Set Flash Mode to 3")); } } } diff --git a/sonoff/xdrv_domoticz.ino b/sonoff/xdrv_domoticz.ino index 5c45a2169..ba155ff08 100644 --- a/sonoff/xdrv_domoticz.ino +++ b/sonoff/xdrv_domoticz.ino @@ -33,6 +33,15 @@ const char HTTP_FORM_DOMOTICZ[] PROGMEM = "
" "" ""; +const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = + "" + ""; +const char HTTP_FORM_DOMOTICZ_SWITCH[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = + ""; +const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = + ""; const char domoticz_sensors[DOMOTICZ_MAX_SENSORS][14] PROGMEM = { "Temp", "Temp,Hum", "Temp,Hum,Baro", "Power,Energy", "Illuminance" }; @@ -173,66 +182,62 @@ boolean domoticz_mqttData(char *topicBuf, uint16_t stopicBuf, char *dataBuf, uin * Commands \*********************************************************************************************/ -boolean domoticz_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) +boolean domoticz_command(const char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload, char *svalue, uint16_t ssvalue) { boolean serviced = true; - if (!strcmp(type,"DOMOTICZINTOPIC")) { - if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_in_topic))) { - strlcpy(sysCfg.domoticz_in_topic, (payload == 1) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic)); - restartflag = 2; + if (!strncmp(type,"DOMOTICZ",8)) { + if (!strcmp(type +8,"INTOPIC")) { + if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_in_topic))) { + strlcpy(sysCfg.domoticz_in_topic, (payload == 1) ? DOMOTICZ_IN_TOPIC : dataBuf, sizeof(sysCfg.domoticz_in_topic)); + restartflag = 2; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzInTopic\":\"%s\"}"), sysCfg.domoticz_in_topic); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzInTopic\":\"%s\"}"), sysCfg.domoticz_in_topic); - } - else if (!strcmp(type,"DOMOTICZOUTTOPIC")) { - if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_out_topic))) { - strlcpy(sysCfg.domoticz_out_topic, (payload == 1) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic)); - restartflag = 2; + else if (!strcmp(type +8,"OUTTOPIC")) { + if ((data_len > 0) && (data_len < sizeof(sysCfg.domoticz_out_topic))) { + strlcpy(sysCfg.domoticz_out_topic, (payload == 1) ? DOMOTICZ_OUT_TOPIC : dataBuf, sizeof(sysCfg.domoticz_out_topic)); + restartflag = 2; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzOutTopic\":\"%s\"}"), sysCfg.domoticz_out_topic); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzOutTopic\":\"%s\"}"), sysCfg.domoticz_out_topic); - } - else if (!strcmp(type,"DOMOTICZIDX") && (index > 0) && (index <= Maxdevice)) { - if ((data_len > 0) && (payload >= 0)) { - sysCfg.domoticz_relay_idx[index -1] = payload; - restartflag = 2; + else if (!strcmp(type +8,"IDX") && (index > 0) && (index <= Maxdevice)) { + if ((data_len > 0) && (payload >= 0)) { + sysCfg.domoticz_relay_idx[index -1] = payload; + restartflag = 2; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzIdx%d\":%d}"), index, sysCfg.domoticz_relay_idx[index -1]); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzIdx%d\":%d}"), index, sysCfg.domoticz_relay_idx[index -1]); - } - else if (!strcmp(type,"DOMOTICZKEYIDX") && (index > 0) && (index <= Maxdevice)) { - if ((data_len > 0) && (payload >= 0)) { - sysCfg.domoticz_key_idx[index -1] = payload; + else if (!strcmp(type +8,"KEYIDX") && (index > 0) && (index <= Maxdevice)) { + if ((data_len > 0) && (payload >= 0)) { + sysCfg.domoticz_key_idx[index -1] = payload; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzKeyIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzKeyIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]); - } - else if (!strcmp(type,"DOMOTICZSWITCHIDX") && (index > 0) && (index <= Maxdevice)) { - if ((data_len > 0) && (payload >= 0)) { - sysCfg.domoticz_switch_idx[index -1] = payload; + else if (!strcmp(type +8,"SWITCHIDX") && (index > 0) && (index <= Maxdevice)) { + if ((data_len > 0) && (payload >= 0)) { + sysCfg.domoticz_switch_idx[index -1] = payload; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSwitchIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSwitchIdx%d\":%d}"), index, sysCfg.domoticz_key_idx[index -1]); - } - else if (!strcmp(type,"DOMOTICZSENSORIDX") && (index > 0) && (index <= DOMOTICZ_MAX_SENSORS)) { - if ((data_len > 0) && (payload >= 0)) { - sysCfg.domoticz_sensor_idx[index -1] = payload; + else if (!strcmp(type +8,"SENSORIDX") && (index > 0) && (index <= DOMOTICZ_MAX_SENSORS)) { + if ((data_len > 0) && (payload >= 0)) { + sysCfg.domoticz_sensor_idx[index -1] = payload; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSensorIdx%d\":%d}"), index, sysCfg.domoticz_sensor_idx[index -1]); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzSensorIdx%d\":%d}"), index, sysCfg.domoticz_sensor_idx[index -1]); - } - else if (!strcmp(type,"DOMOTICZUPDATETIMER")) { - if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { - sysCfg.domoticz_update_timer = payload; + else if (!strcmp(type +8,"UPDATETIMER")) { + if ((data_len > 0) && (payload >= 0) && (payload < 3601)) { + sysCfg.domoticz_update_timer = payload; + } + snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzUpdateTimer\":%d}"), sysCfg.domoticz_update_timer); } - snprintf_P(svalue, ssvalue, PSTR("{\"DomoticzUpdateTimer\":%d}"), sysCfg.domoticz_update_timer); - } - else { - serviced = false; + else serviced = false; } + else serviced = false; return serviced; } -void domoticz_commands(char *svalue, uint16_t ssvalue) -{ - snprintf_P(svalue, ssvalue, PSTR("{\"Commands4\":\"DomoticzInTopic, DomoticzOutTopic, DomoticzIdx, DomoticzKeyIdx, DomoticzSwitchIdx, DomoticzSensorIdx, DomoticzUpdateTimer\"}")); -} - boolean domoticz_button(byte key, byte device, byte state, byte svalflg) { if ((sysCfg.domoticz_key_idx[device -1] || sysCfg.domoticz_switch_idx[device -1]) && (svalflg)) { @@ -321,24 +326,27 @@ void handleDomoticz() page += FPSTR(HTTP_FORM_DOMOTICZ); page.replace("{d1}", String(sysCfg.domoticz_in_topic)); page.replace("{d2}", String(sysCfg.domoticz_out_topic)); - for (int i = 0; i < Maxdevice; i++) { - page += F(""); - page += F(""); - page += F(""); + for (int i = 0; i < 4; i++) { + if (i < Maxdevice) { + page += FPSTR(HTTP_FORM_DOMOTICZ_RELAY); + page.replace("{2", String((int)sysCfg.domoticz_relay_idx[i])); + page.replace("{3", String((int)sysCfg.domoticz_key_idx[i])); + } + if (pin[GPIO_SWT1 +i] < 99) { + page += FPSTR(HTTP_FORM_DOMOTICZ_SWITCH); + page.replace("{4", String((int)sysCfg.domoticz_switch_idx[i])); + } page.replace("{1", String(i +1)); - page.replace("{2", String((int)sysCfg.domoticz_relay_idx[i])); - page.replace("{3", String((int)sysCfg.domoticz_key_idx[i])); - page.replace("{4", String((int)sysCfg.domoticz_switch_idx[i])); } for (int i = 0; i < DOMOTICZ_MAX_SENSORS; i++) { - page += F(""); + page += FPSTR(HTTP_FORM_DOMOTICZ_SENSOR); page.replace("{1", String(i +1)); snprintf_P(stemp, sizeof(stemp), domoticz_sensors[i]); page.replace("{2", stemp); - page.replace("{4", String((int)sysCfg.domoticz_sensor_idx[i])); + page.replace("{5", String((int)sysCfg.domoticz_sensor_idx[i])); } - page += F(""); - page.replace("{d7}", String((int)sysCfg.domoticz_update_timer)); + page += FPSTR(HTTP_FORM_DOMOTICZ_TIMER); + page.replace("{6", String((int)sysCfg.domoticz_update_timer)); page += F("
In topic (" DOMOTICZ_IN_TOPIC ")
Out topic (" DOMOTICZ_OUT_TOPIC ")
Idx {1
Key idx {1
Switch idx {1
Sensor idx {1 - {2
Update timer (" STR(DOMOTICZ_UPDATE_TIMER) ")
Idx {1
Key idx {1
Switch idx {1
Sensor idx {1 - {2
Update timer (" STR(DOMOTICZ_UPDATE_TIMER) ")
"); page += FPSTR(HTTP_FORM_END); page += FPSTR(HTTP_BTN_CONF); diff --git a/sonoff/xdrv_ir_send.ino b/sonoff/xdrv_ir_send.ino index b14cd9615..3a31cfa8d 100644 --- a/sonoff/xdrv_ir_send.ino +++ b/sonoff/xdrv_ir_send.ino @@ -28,13 +28,11 @@ POSSIBILITY OF SUCH DAMAGE. * IR Remote send using IRremoteESP8266 library \*********************************************************************************************/ -// * Add support for Toshiba and Mitsubishi HVAC IR control (#257) -// #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) - #ifndef USE_IR_HVAC #include #else - #include // Currently firmware.elf section `.text' will not fit in region `iram1_0_seg' + #include + // HVAC TOSHIBA_ #define HVAC_TOSHIBA_HDR_MARK 4400 #define HVAC_TOSHIBA_HDR_SPACE 4300 @@ -44,7 +42,11 @@ POSSIBILITY OF SUCH DAMAGE. #define HVAC_TOSHIBA_RPT_MARK 440 #define HVAC_TOSHIBA_RPT_SPACE 7048 // Above original iremote limit #define HVAC_TOSHIBA_DATALEN 9 + IRMitsubishiAC *mitsubir = NULL; + + const char FANSPEED[] = "A12345S"; + const char HVACMODE[] = "HDCA"; #endif IRsend *irsend = NULL; @@ -143,7 +145,7 @@ boolean ir_send_command(char *type, uint16_t index, char *dataBufUc, uint16_t da else error = true; } } else error = true; - if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Wrong parameters value for Vendor, Mode and/or FanSpeed\"}")); + if (error) snprintf_P(svalue, ssvalue, PSTR("{\"IRHVAC\":\"Wrong Vendor, Mode and/or FanSpeed\"}")); } #endif // USE_IR_HVAC else { @@ -157,46 +159,30 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean { unsigned int rawdata[2 + 2*8*HVAC_TOSHIBA_DATALEN + 2]; byte data[HVAC_TOSHIBA_DATALEN] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 }; - boolean error = false; - if (HVAC_Mode == NULL || !strcmp(HVAC_Mode,"HOT")) { //default HVAC_HOT - data[6] = (byte) B00000011; + char *p, *token; + uint8_t mode; + + if (HVAC_Mode == NULL) { + p = (char*)HVACMODE; // default HVAC_HOT + } else { + p = strchr(HVACMODE, HVAC_Mode[0]); } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"COLD")) { - data[6] = (byte) B00000001; - } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"DRY")) { - data[6] = (byte) B00000010; - } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"AUTO")) { - data[6] = (byte) B00000000; - } - else error = true; + if (!p) return true; + data[6] = (p - HVACMODE) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00 if (!HVAC_Power) data[6] = (byte) 0x07; // Turn OFF HVAC - if (HVAC_FanMode && !strcmp(HVAC_FanMode,"1")) { - data[6] = data[6] | (byte) B01000000; + if (HVAC_FanMode == NULL) { + p = (char*)FANSPEED; // default FAN_SPEED_AUTO + } else { + p = strchr(FANSPEED, HVAC_FanMode[0]); } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"2")) { - data[6] = data[6] | (byte) B01100000; - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"3")) { - data[6] = data[6] | (byte) B10000000; - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"4")) { - data[6] = data[6] | (byte) B10100000; - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"5")) { - data[6] = data[6] | (byte) B11000000; - } - else if (HVAC_FanMode == NULL || !strcmp(HVAC_FanMode,"AUTO")) { // default FAN_SPEED_AUTO - data[6] = data[6] | (byte) B00000000; - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"SILENT")) { - data[6] = data[6] | (byte) B00000000; - } - else error = true; + if (!p) return true; + mode = p - FANSPEED +1; + if ((mode == 1) || (mode == 7)) mode = 0; + mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00 + data[6] = data[6] | mode; byte Temp; if (HVAC_Temp > 30) { @@ -243,63 +229,46 @@ boolean ir_hvac_toshiba(const char *HVAC_Mode, const char *HVAC_FanMode, boolean irsend->sendRaw(rawdata,i,38); interrupts(); - return error; + return false; } boolean ir_hvac_mitsubishi(const char *HVAC_Mode,const char *HVAC_FanMode, boolean HVAC_Power, int HVAC_Temp) { - boolean error = false; + char *p, *token; + uint8_t mode; char log[LOGSZ]; mitsubir->stateReset(); - - if (HVAC_Mode == NULL || !strcmp(HVAC_Mode,"HOT")) { // default HVAC_HOT - mitsubir->setMode(MITSUBISHI_AC_HEAT); + + if (HVAC_Mode == NULL) { + p = (char*)HVACMODE; // default HVAC_HOT + } else { + p = strchr(HVACMODE, HVAC_Mode[0]); } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"COLD")) { - mitsubir->setMode(MITSUBISHI_AC_COOL); - } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"DRY")) { - mitsubir->setMode(MITSUBISHI_AC_DRY); - } - else if (HVAC_Mode && !strcmp(HVAC_Mode,"AUTO")) { - mitsubir->setMode(MITSUBISHI_AC_AUTO); - } else error = true; + if (!p) return true; + mode = (p - HVACMODE +1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20 + mitsubir->setMode(mode); mitsubir->setPower(~HVAC_Power); - if (HVAC_FanMode && !strcmp(HVAC_FanMode,"1")) { - mitsubir->setFan(1); + if (HVAC_FanMode == NULL) { + p = (char*)FANSPEED; // default FAN_SPEED_AUTO + } else { + p = strchr(FANSPEED, HVAC_FanMode[0]); } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"2")) { - mitsubir->setFan(2); - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"3")) { - mitsubir->setFan(3); - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"4")) { - mitsubir->setFan(4); - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"5")) { - mitsubir->setFan(5); - } - else if (HVAC_FanMode == NULL || !strcmp(HVAC_FanMode,"AUTO")) { // default FAN_SPEED_AUTO - mitsubir->setFan(MITSUBISHI_AC_FAN_AUTO); - } - else if (HVAC_FanMode && !strcmp(HVAC_FanMode,"SILENT")) { - mitsubir->setFan(MITSUBISHI_AC_FAN_SILENT); - } - else error = true; + if (!p) return true; + mode = p - FANSPEED; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6 + mitsubir->setFan(mode); mitsubir->setTemp(HVAC_Temp); mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO); - mitsubir->send(); - snprintf_P(log, sizeof(log), PSTR("IRHVAC: Sent to Mitsubishi. Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"), - mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane()); - addLog(LOG_LEVEL_DEBUG, log); - return error; +// snprintf_P(log, sizeof(log), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"), +// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane()); +// addLog(LOG_LEVEL_DEBUG, log); + + return false; } #endif // USE_IR_HVAC #endif // USE_IR_REMOTE diff --git a/sonoff/xsns_dht.ino b/sonoff/xsns_dht.ino index 4323d790a..ddab80c70 100644 --- a/sonoff/xsns_dht.ino +++ b/sonoff/xsns_dht.ino @@ -198,8 +198,9 @@ void dht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) if (dht_readTempHum(TEMP_CONVERSION, t, h)) { // Read temperature dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1); dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2); - snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s}"), - svalue, dhtstype, stemp1, stemp2); +// snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s}"), +// svalue, dhtstype, stemp1, stemp2); + snprintf_P(svalue, ssvalue, JSON_SNS_TEMPHUM, svalue, dhtstype, stemp1, stemp2); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor2(stemp1, stemp2); diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index af387ae7a..bc5db1f4c 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -511,12 +511,6 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len return serviced; } -void hlw_commands(char *svalue, uint16_t ssvalue) -{ - snprintf_P(svalue, ssvalue, PSTR("{\"Commands5\":\"PowerLow, PowerHigh, VoltageLow, VoltageHigh, CurrentLow, CurrentHigh, HlwPcal, HlwUcal, HlwIcal%s\"}"), - (FEATURE_POWER_LIMIT)?", SafePower, SafePowerHold, SafePowerWindow, MaxPower, MaxPowerHold, MaxPowerWindow, MaxEnergy, MaxEnergyStart":""); -} - /*********************************************************************************************\ * Presentation \*********************************************************************************************/ diff --git a/sonoff/xsns_htu21.ino b/sonoff/xsns_htu21.ino index aff7615a7..ba6a44179 100644 --- a/sonoff/xsns_htu21.ino +++ b/sonoff/xsns_htu21.ino @@ -262,8 +262,7 @@ void htu_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) h = htu21_compensatedHumidity(h, t); dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1); dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp2); - snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s}"), - svalue, htustype, stemp1, stemp2); + snprintf_P(svalue, ssvalue, JSON_SNS_TEMPHUM, svalue, htustype, stemp1, stemp2); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor2(stemp1, stemp2); diff --git a/sonoff/xsns_sht1x.ino b/sonoff/xsns_sht1x.ino index d3028c901..1d129566d 100644 --- a/sonoff/xsns_sht1x.ino +++ b/sonoff/xsns_sht1x.ino @@ -183,8 +183,7 @@ void sht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) char stemp[10], shum[10]; if (sht_readCharTempHum(stemp, shum)) { - snprintf_P(svalue, ssvalue, PSTR("%s, \"SHT1X\":{\"Temperature\":%s, \"Humidity\":%s}"), - svalue, stemp, shum); + snprintf_P(svalue, ssvalue, JSON_SNS_TEMPHUM, svalue, "SHT1X", stemp, shum); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor2(stemp, shum);