diff --git a/README.md b/README.md index d668ce575..cabcc4a62 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.14** - See ```sonoff/_releasenotes.ino``` for change information. +Current version is **3.9.15** - 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 5e2ad3ee1..a44873b6e 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 a7cc6f25c..0c4a996dc 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,10 +1,16 @@ -/* 3.9.14 20170211 +/* 3.9.15 20170213 + * Change JSON float values from string to number according to http://json.org (#56) + * Add support for exs latched relay module https://ex-store.de/ESP8266-WiFi-Relay-V31 (#58) + * Add support for inverted relays + * Changed MAX_LOG_LINES from 70 to 60 to preserve memory + * + * 3.9.14 20170211 * Add False and True as alternatives for 0/Off and 1/On (#49) * Fix Status10 JSON format (#52) * Fix DS18x20 using OneWire library (#53) * * 3.9.13 20170210 - * Add FlashChipSize to Status 4 + * Add FlashChipMode to Status 4 * Removed redundant DHT2 option and code * Add Sonoff SV GPIO pin 05 configuration (#40) * Add configuration file backup and restore via web page diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 4e0bcc01d..697c41bdd 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -10,7 +10,10 @@ * ==================================================== */ -#define VERSION 0x03090E00 // 3.9.14 +#define VERSION 0x03090F00 // 3.9.15 + +//#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 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}; @@ -38,6 +41,41 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #define MODULE SONOFF_BASIC // [Module] Select default model +#define USE_DHT // Default DHT11 sensor needs no external library +#ifndef USE_DS18x20 +#define USE_DS18B20 // Default DS18B20 sensor needs no external library +#endif + +#ifdef BE_MINIMAL +//#ifdef USE_MQTT_TLS +//#undef USE_MQTT_TLS // Disable TLS support won't work as the MQTTHost is not set +//#endif +#ifdef USE_DISCOVERY +#undef USE_DISCOVERY // Disable Discovery services for both MQTT and web server +#endif +#ifdef USE_DOMOTICZ +#undef USE_DOMOTICZ // Disable Domoticz +#endif +#ifdef USE_EMULATION +#undef USE_EMULATION // Disable Wemo or Hue emulation +#endif +#ifdef USE_DS18x20 +#undef USE_DS18x20 // Disable DS18x20 sensor +#endif +#ifdef USE_I2C +#undef USE_I2C // Disable all I2C sensors +#endif +#ifdef USE_WS2812 +#undef USE_WS2812 // Disable WS2812 Led string +#endif +#ifdef USE_DS18B20 +#undef USE_DS18B20 // Disable internal DS18B20 sensor +#endif +#ifdef USE_DHT +#undef USE_DHT // Disable internal DHT sensor +#endif +#endif // BE_MINIMAL + #ifndef SWITCH_MODE #define SWITCH_MODE TOGGLE // TOGGLE, FOLLOW or FOLLOW_INV (the wall switch state) #endif @@ -46,16 +84,11 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #define MQTT_FINGERPRINT "A5 02 FF 13 99 9F 8B 39 8E F1 83 4F 11 23 65 0B 32 36 FC 07" #endif -#ifndef USE_DS18x20 -#define USE_DS18B20 // Default DS18B20 sensor needs no external library -#endif - #ifndef WS2812_LEDS #define WS2812_LEDS 30 // [Pixels] Number of LEDs #endif #define WIFI_HOSTNAME "%s-%04d" // Expands to - -#define USE_DHT // Default DHT11 sensor needs no external library #define CONFIG_FILE_SIGN 0xA5 // Configuration file signature #define CONFIG_FILE_XOR 0x5A // Configuration file xor (0 = No Xor) @@ -88,7 +121,7 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX}; #ifdef USE_MQTT_TLS #define MAX_LOG_LINES 10 // Max number of lines in weblog #else - #define MAX_LOG_LINES 70 // Max number of lines in weblog + #define MAX_LOG_LINES 60 // Max number of lines in weblog #endif #define APP_BAUDRATE 115200 // Default serial baudrate @@ -371,6 +404,8 @@ uint8_t blink_power; // Blink power state uint8_t blink_mask = 0; // Blink relay active mask uint8_t blink_powersave; // Blink start power save state uint16_t mqtt_cmnd_publish = 0; // ignore flag for publish command +uint8_t latching_power = 0; // Power state at latching start +uint8_t latching_relay_pulse = 0; // Latching relay pulse timer #ifdef USE_MQTT_TLS WiFiClientSecure espClient; // Wifi Secure Client @@ -751,8 +786,26 @@ void getClient(char* output, const char* input, byte size) if (!digits) strlcpy(output, input, size); } +void setLatchingRelay(uint8_t power, uint8_t state) +{ + power &= 1; + if (state == 2) { // Init relay + state = 0; + } + else if (state == 1) { // Set port power to On + latching_power = power; + latching_relay_pulse = 2; // max 200mS (initiated by stateloop()) + } + else { // Set saved port to Off + power = latching_power; + } + if (pin[GPIO_REL1 +power] < 99) digitalWrite(pin[GPIO_REL1 +power], rel_inverted[power] ? !state : state); +} + void setRelay(uint8_t power) { + uint8_t state; + if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { Serial.write(0xA0); Serial.write(0x04); @@ -760,14 +813,18 @@ void setRelay(uint8_t power) Serial.write(0xA1); Serial.write('\n'); Serial.flush(); - } else { - if (sysCfg.module == SONOFF_LED) { - sl_setColor(power &1); - } else { - for (byte i = 0; i < Maxdevice; i++) { - if (pin[GPIO_REL1 +i] < 99) digitalWrite(pin[GPIO_REL1 +i], power & 0x1); - power >>= 1; - } + } + else if (sysCfg.module == SONOFF_LED) { + sl_setColor(power &1); + } + else if (sysCfg.module == EXS_RELAY) { + setLatchingRelay(power, 1); + } + else { + for (byte i = 0; i < Maxdevice; i++) { + state = power &1; + if (pin[GPIO_REL1 +i] < 99) digitalWrite(pin[GPIO_REL1 +i], rel_inverted[i] ? !state : state); + power >>= 1; } } hlw_setPowerSteadyCounter(2); @@ -1513,7 +1570,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len) if ((data_len > 0) && (((payload >= -12) && (payload <= 12)) || (payload == 99))) { sysCfg.timezone = payload; } - snprintf_P(svalue, sizeof(svalue), PSTR("{\"Timezone\":\"%d%s\"}"), sysCfg.timezone, (sysCfg.value_units) ? " Hr" : ""); + snprintf_P(svalue, sizeof(svalue), PSTR("{\"Timezone\":%d}"), sysCfg.timezone); } else if (!strcmp(type,"LEDPOWER")) { if ((data_len > 0) && (payload >= 0) && (payload <= 2)) { @@ -2090,6 +2147,11 @@ void stateloop() if (mqtt_cmnd_publish) mqtt_cmnd_publish--; // Clean up + if (latching_relay_pulse) { + latching_relay_pulse--; + if (!latching_relay_pulse) setLatchingRelay(0, 0); + } + if ((pulse_timer > 0) && (pulse_timer < 112)) { pulse_timer--; if (!pulse_timer) do_cmnd_power(1, 0); @@ -2431,16 +2493,16 @@ void GPIO_init() if ((sysCfg.module == SONOFF_DUAL) || (sysCfg.module == CH4)) { Baudrate = 19200; - } else { - if (sysCfg.module == SONOFF_LED) { - for (byte i = 0; i < 5; i++) { - if (pin[GPIO_PWM0 +i] < 99) pinMode(pin[GPIO_PWM0 +i], OUTPUT); - } - } else { - for (byte i = 0; i < 4; i++) { - 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); - } + } + else if (sysCfg.module == SONOFF_LED) { + for (byte i = 0; i < 5; i++) { + if (pin[GPIO_PWM0 +i] < 99) pinMode(pin[GPIO_PWM0 +i], OUTPUT); + } + } + else { + for (byte i = 0; i < 4; i++) { + 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++) { @@ -2453,6 +2515,10 @@ void GPIO_init() lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // set global now so doesn't change the saved power state on first switch check } } + if (sysCfg.module == EXS_RELAY) { + setLatchingRelay(0,2); + setLatchingRelay(1,2); + } setLed(sysCfg.ledstate &8); hlw_flg = ((pin[GPIO_HLW_SEL] < 99) && (pin[GPIO_HLW_CF1] < 99) && (pin[GPIO_HLW_CF] < 99)); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 8df095811..532345a81 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -84,6 +84,7 @@ enum module_t { CH4, MOTOR, ELECTRODRAGON, + EXS_RELAY, USER_TEST, MAXMODULE }; @@ -253,6 +254,21 @@ const mytmplt modules[MAXMODULE] PROGMEM = { 0, GPIO_LED1 // GPIO16 Green/Blue Led (1 = On, 0 = Off) }, + { "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31 + // Module Pin 1 VCC 3V3, Module Pin 6 GND + GPIO_KEY1, // GPIO00 Module Pin 8 - Button (firmware flash) + GPIO_USER, // GPIO01 Module Pin 2 = UART0_TXD + GPIO_USER, // GPIO02 Module Pin 7 + GPIO_USER, // GPIO03 Module Pin 3 = UART0_RXD + GPIO_USER, // GPIO04 Module Pin 10 + GPIO_USER, // GPIO05 Module Pin 9 + 0, 0, 0, 0, 0, 0, + GPIO_REL1, // GPIO12 Relay1 ( 1 = Off) + GPIO_REL2, // GPIO13 Relay1 ( 1 = On) + GPIO_USER, // GPIO14 Module Pin 5 + 0, + GPIO_USER // GPIO16 Module Pin 4 + }, { "User Test", // Sonoff Basic User Test GPIO_KEY1, // GPIO00 Button 0, diff --git a/sonoff/user_config.h b/sonoff/user_config.h index d428bee39..1e6c6b0da 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -106,7 +106,7 @@ #define APP_POWERON_STATE 3 // [PowerOnState] Power On Relay state (0 = Off, 1 = On, 2 = Toggle Saved state, 3 = Saved state) #define APP_BLINKTIME 10 // [BlinkTime] Time in 0.1 Sec to blink/toggle power for relay 1 #define APP_BLINKCOUNT 10 // [BlinkCount] Number of blinks (0 = 32000) -#define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec) +#define APP_SLEEP 0 // [Sleep] Sleep time to lower energy consumption (0 = Off, 1 - 250 mSec) #define SWITCH_MODE TOGGLE // [SwitchMode] TOGGLE, FOLLOW, FOLLOW_INV, PUSHBUTTON or PUSHBUTTON_INV (the wall switch state) #define WS2812_LEDS 30 // [Pixels] Number of WS2812 LEDs to start with @@ -133,10 +133,6 @@ * No user configurable items below \*********************************************************************************************/ -#if defined(USE_WEMO_EMULATION) && defined(USE_HUE_EMULATION) - #error "Select either USE_WEMO_EMULATION or USE_HUE_EMULATION" -#endif - #if (ARDUINO < 10610) #error "This software is supported with Arduino IDE starting from 1.6.10 and ESP8266 Release 2.3.0" #endif diff --git a/sonoff/xsns_bmp.ino b/sonoff/xsns_bmp.ino index 6475895b6..4ac3d7d17 100644 --- a/sonoff/xsns_bmp.ino +++ b/sonoff/xsns_bmp.ino @@ -437,10 +437,10 @@ void bmp_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) dtostrf(p, 1, PRESSURE_RESOLUTION &3, stemp2); dtostrf(h, 1, HUMIDITY_RESOLUTION &3, stemp3); if (!strcmp(bmpstype,"BME280")) { - snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\", \"Pressure\":\"%s\"}"), + snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s, \"Pressure\":%s}"), svalue, bmpstype, stemp1, stemp3, stemp2); } else { - snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":\"%s\", \"Pressure\":\"%s\"}"), + snprintf_P(svalue, ssvalue, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Pressure\":%s}"), svalue, bmpstype, stemp1, stemp2); } *djson = 1; diff --git a/sonoff/xsns_dht.ino b/sonoff/xsns_dht.ino index 0429446e6..e1b9f9793 100644 --- a/sonoff/xsns_dht.ino +++ b/sonoff/xsns_dht.ino @@ -186,7 +186,7 @@ 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, \"DHT\":{\"Temperature\":\"%s\", \"Humidity\":\"%s\"}"), svalue, stemp1, stemp2); + snprintf_P(svalue, ssvalue, PSTR("%s, \"DHT\":{\"Temperature\":%s, \"Humidity\":%s}"), svalue, stemp1, stemp2); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor2(stemp1, stemp2); diff --git a/sonoff/xsns_ds18b20.ino b/sonoff/xsns_ds18b20.ino index b77d89f69..18375531e 100644 --- a/sonoff/xsns_ds18b20.ino +++ b/sonoff/xsns_ds18b20.ino @@ -179,7 +179,7 @@ void dsb_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) if (dsb_readTemp(TEMP_CONVERSION, t)) { // Check if read failed dtostrf(t, 1, TEMP_RESOLUTION &3, stemp1); - snprintf_P(svalue, ssvalue, PSTR("%s, \"DS18B20\":{\"Temperature\":\"%s\"}"), svalue, stemp1); + snprintf_P(svalue, ssvalue, PSTR("%s, \"DS18B20\":{\"Temperature\":%s}"), svalue, stemp1); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor1(stemp1); diff --git a/sonoff/xsns_ds18x20.ino b/sonoff/xsns_ds18x20.ino index fa38cb686..22fc92654 100644 --- a/sonoff/xsns_ds18x20.ino +++ b/sonoff/xsns_ds18x20.ino @@ -175,7 +175,7 @@ void ds18x20_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) stemp1[0] = '\0'; } dsxflg++; - snprintf_P(svalue, ssvalue, PSTR("%s%s\"DS%d\":{\"Type\":\"%s\", \"Address\":\"%s\", \"Temperature\":\"%s\"}"), + snprintf_P(svalue, ssvalue, PSTR("%s%s\"DS%d\":{\"Type\":\"%s\", \"Address\":\"%s\", \"Temperature\":%s}"), svalue, stemp1, i +1, ds18x20_type(i).c_str(), ds18x20_address(i).c_str(), stemp2); strcpy(stemp1, ", "); #ifdef USE_DOMOTICZ diff --git a/sonoff/xsns_hlw8012.ino b/sonoff/xsns_hlw8012.ino index 097969e7a..3ed5e24c3 100644 --- a/sonoff/xsns_hlw8012.ino +++ b/sonoff/xsns_hlw8012.ino @@ -530,7 +530,7 @@ void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) dtostrf(pc, 1, 2, stemp2); dtostrf(pi, 1, 3, stemp3); snprintf_P(speriod, sizeof(speriod), PSTR(", \"Period\":%d"), pe); - snprintf_P(svalue, ssvalue, PSTR("%s\"Yesterday\":\"%s\", \"Today\":\"%s\"%s, \"Power\":%d, \"Factor\":\"%s\", \"Voltage\":%d, \"Current\":\"%s\"}"), + snprintf_P(svalue, ssvalue, PSTR("%s\"Yesterday\":%s, \"Today\":%s%s, \"Power\":%d, \"Factor\":%s, \"Voltage\":%d, \"Current\":%s}"), svalue, stemp0, stemp1, (option) ? speriod : "", pw, stemp2, pu, stemp3); #ifdef USE_DOMOTICZ dtostrf(ped * 1000, 1, 1, stemp1); @@ -540,7 +540,6 @@ void hlw_mqttStat(byte option, char* svalue, uint16_t ssvalue) void hlw_mqttPresent() { -// char stopic[TOPSZ], svalue[MESSZ], stime[21]; char svalue[MESSZ], stime[21]; snprintf_P(stime, sizeof(stime), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), diff --git a/sonoff/xsns_htu21.ino b/sonoff/xsns_htu21.ino index 36e26f8be..64ea0cde4 100644 --- a/sonoff/xsns_htu21.ino +++ b/sonoff/xsns_htu21.ino @@ -240,7 +240,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, PSTR("%s, \"%s\":{\"Temperature\":%s, \"Humidity\":%s}"), svalue, htustype, stemp1, stemp2); *djson = 1; #ifdef USE_DOMOTICZ domoticz_sensor2(stemp1, stemp2);