diff --git a/README.md b/README.md index b1a30802f1e7..4ab1e7d3b0d8 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.0.5** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. +Current version is **4.0.6** - 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```. @@ -24,6 +24,7 @@ The following devices are supported: - [iTead Slampher](http://sonoff.itead.cc/en/products/residential/slampher-rf) - [iTead Sonoff Touch](http://sonoff.itead.cc/en/products/residential/sonoff-touch) - [iTead Sonoff Led](http://sonoff.itead.cc/en/products/appliances/sonoff-led) +- [iTead Sonoff Dev](https://www.itead.cc/sonoff-dev.html) - [iTead 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html) - [iTead Motor Clockwise/Anticlockwise](https://www.itead.cc/smart-home/motor-reversing-wifi-wireless-switch.html) - [Electrodragon IoT Relay Board](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/) diff --git a/api/arduino/sonoff.ino.bin b/api/arduino/sonoff.ino.bin index 33f8b24210b0..b451f62d0ae0 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 443877c55f19..667c91864892 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,4 +1,11 @@ -/* 4.0.5 20170314 +/* 4.0.6 20170316 + * Fix to better find device by Wifi hostname + * Fix compile error when some I2C devices are disabled + * Add (experimental) support for SHT1X emulating I2C (#97) + * Add ADC to ElectroDragon (#203) + * Add support for Sonoff Dev (#206) + * + * 4.0.5 20170314 * Add command Status 11 to show power status with Vcc if define USE_ADC_VCC is enabled (default) * Add ADC input to Sonoff SV and Wemos D1 mini - Needs recompile with define USE_ADC_VCC disabled (#137) * Add MQTT host:port to timeout message (#199) diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index e29aae42b49a..bd160a70f2bc 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -12,9 +12,9 @@ //#define ALLOW_MIGRATE_TO_V3 #ifdef ALLOW_MIGRATE_TO_V3 - #define VERSION 0x03091C00 // 3.9.28 + #define VERSION 0x03091D00 // 3.9.29 #else - #define VERSION 0x04000500 // 4.0.5 + #define VERSION 0x04000600 // 4.0.6 #endif // ALLOW_MIGRATE_TO_V3 enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; @@ -149,7 +149,7 @@ enum butt_t {PRESSED, NOT_PRESSED}; #error "MQTT_MAX_PACKET_SIZE is too small in libraries/PubSubClient/src/PubSubClient.h, increase it to at least 427" #endif -#include // RTC +#include // RTC, HLW8012, OSWatch #include // MQTT, Ota, WifiManager #include // MQTT, Ota #include // Ota @@ -1528,6 +1528,9 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { +#ifdef USE_SHT + sht_mqttPresent(svalue, ssvalue, djson); +#endif // USE_SHT #ifdef USE_HTU htu_mqttPresent(svalue, ssvalue, djson); #endif // USE_HTU @@ -1544,13 +1547,6 @@ void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) /********************************************************************************************/ -void every_second_cb() -{ - // 1 second rtc interrupt routine - // Keep this code small (every_second is to large - it'll trip exception) - -} - void every_second() { char svalue[MESSZ]; @@ -1605,6 +1601,9 @@ void every_second() #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { +#ifdef USE_SHT + sht_detect(); +#endif // USE_SHT #ifdef USE_HTU htu_detect(); #endif // USE_HTU @@ -2053,7 +2052,7 @@ void GPIO_init() #ifdef USE_I2C i2c_flg = ((pin[GPIO_I2C_SCL] < 99) && (pin[GPIO_I2C_SDA] < 99)); - if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA],pin[GPIO_I2C_SCL]); + if (i2c_flg) Wire.begin(pin[GPIO_I2C_SDA], pin[GPIO_I2C_SCL]); #endif // USE_I2C #ifdef USE_WS2812 @@ -2123,7 +2122,7 @@ void setup() } else { snprintf_P(Hostname, sizeof(Hostname)-1, sysCfg.hostname); } - WIFI_Connect(Hostname); + WIFI_Connect(); getClient(MQTTClient, sysCfg.mqtt_client, sizeof(MQTTClient)); @@ -2151,7 +2150,7 @@ void setup() } blink_powersave = power; - rtc_init(every_second_cb); + rtc_init(); snprintf_P(log, sizeof(log), PSTR("APP: Project %s %s (Topic %s, Fallback %s, GroupTopic %s) Version %s"), PROJECT, sysCfg.friendlyname[0], sysCfg.mqtt_topic, MQTTClient, sysCfg.mqtt_grptopic, Version); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 89767a93d43a..aa5da9468b25 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -114,6 +114,7 @@ enum module_t { EXS_RELAY, WION, WEMOS, + SONOFF_DEV, MAXMODULE }; /********************************************************************************************/ @@ -308,7 +309,7 @@ const mytmplt modules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO14 Optional sensor GPIO_USER, // GPIO15 Optional sensor GPIO_LED1, // GPIO16 Green/Blue Led (1 = On, 0 = Off) - 0 + GPIO_ADC0 // ADC0 A0 Analog input }, { "EXS Relay", // Latching relay https://ex-store.de/ESP8266-WiFi-Relay-V31 (ESP8266) // Module Pin 1 VCC 3V3, Module Pin 6 GND @@ -352,6 +353,21 @@ const mytmplt modules[MAXMODULE] PROGMEM = { GPIO_USER, // GPIO15 D8 GPIO_USER, // GPIO16 D0 Wemos Wake GPIO_ADC0 // ADC0 A0 Analog input + }, + { "Sonoff Dev", // Sonoff Dev (ESP8266) + GPIO_KEY1, // GPIO00 E-FW Button + GPIO_USER, // GPIO01 TX Serial RXD and Optional sensor + 0, // GPIO02 + GPIO_USER, // GPIO03 RX Serial TXD and Optional sensor + GPIO_USER, // GPIO04 Optional sensor + GPIO_USER, // GPIO05 Optional sensor + 0, 0, 0, 0, 0, 0, // Flash connection + GPIO_USER, // GPIO12 + GPIO_LED1_INV, // GPIO13 BLUE LED + GPIO_USER, // GPIO14 Optional sensor + 0, // GPIO15 + 0, // GPIO16 + GPIO_ADC0 // ADC0 A0 Analog input } }; diff --git a/sonoff/support.ino b/sonoff/support.ino index 5c78c2ef3cd6..b54c4c519e5f 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -288,6 +288,7 @@ void WIFI_begin(uint8_t flag) #ifdef USE_STATIC_IP_ADDRESS WiFi.config(ipadd, ipgat, ipsub, ipdns); // Set static IP #endif // USE_STATIC_IP_ADDRESS + WiFi.hostname(Hostname); WiFi.begin(sysCfg.sta_ssid[sysCfg.sta_active], sysCfg.sta_pwd[sysCfg.sta_active]); snprintf_P(log, sizeof(log), PSTR("Wifi: Connecting to AP%d %s in mode 11%c as %s..."), sysCfg.sta_active +1, sysCfg.sta_ssid[sysCfg.sta_active], PhyMode[WiFi.getPhyMode() & 0x3], Hostname); @@ -417,10 +418,9 @@ int WIFI_State() return state; } -void WIFI_Connect(char *Hostname) +void WIFI_Connect() { WiFi.persistent(false); // Solve possible wifi init errors - WiFi.hostname(Hostname); _wifistatus = 0; _wifiretry = WIFI_RETRY_SEC; _wificounter = 1; @@ -591,8 +591,6 @@ static const char monthNames[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; uint32_t utctime = 0, loctime = 0, dsttime = 0, stdtime = 0, ntptime = 0, midnight = 1451602800; -rtcCallback rtcCb = NULL; - String getBuildDateTime() { // "2017-03-07T11:08:02" @@ -821,21 +819,13 @@ void rtc_second() midnight = loctime; } rtcTime.Year += 1970; - if (rtcCb) rtcCb(); } -void rtc_init(rtcCallback cb) +void rtc_init() { - rtcCb = cb; - -// sntp_setservername(0, (char*)NTP_SERVER1); -// sntp_setservername(1, (char*)NTP_SERVER2); -// sntp_setservername(2, (char*)NTP_SERVER3); - sntp_setservername(0, sysCfg.ntp_server[0]); sntp_setservername(1, sysCfg.ntp_server[1]); sntp_setservername(2, sysCfg.ntp_server[2]); - sntp_stop(); sntp_set_timezone(0); // UTC time sntp_init(); diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 8fd8ad553779..5e6b555172fb 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -134,6 +134,7 @@ #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/SI7013/SI7020/SI7021 sensor + #define USE_SHT // Add I2C emulating code for SHT1X 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 2eb368e9831b..de5a7d2323dd 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -452,9 +452,18 @@ void handleAjax2() #endif // USE_DHT #ifdef USE_I2C if (i2c_flg) { +#ifdef USE_SHT + tpage += sht_webPresent(); +#endif +#ifdef USE_HTU tpage += htu_webPresent(); +#endif +#ifdef USE_BMP tpage += bmp_webPresent(); +#endif +#ifdef USE_BH1750 tpage += bh1750_webPresent(); +#endif } #endif // USE_I2C String page = ""; diff --git a/sonoff/xsns_sht1x.ino b/sonoff/xsns_sht1x.ino new file mode 100644 index 000000000000..d3028c901372 --- /dev/null +++ b/sonoff/xsns_sht1x.ino @@ -0,0 +1,214 @@ +/* + Copyright (c) 2017 Theo Arends. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + - Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifdef USE_I2C +#ifdef USE_SHT +/*********************************************************************************************\ + * SHT1x - Temperature and Humidy + * + * Reading temperature and humidity takes about 320 milliseconds! + * Source: Marinus vd Broek https://github.com/ESP8266nu/ESPEasy +\*********************************************************************************************/ + +enum { + SHT1X_CMD_MEASURE_TEMP = B00000011, + SHT1X_CMD_MEASURE_RH = B00000101, + SHT1X_CMD_SOFT_RESET = B00011110 +}; + +uint8_t sht_sda_pin, sht_scl_pin, shttype = 0; + +boolean sht_reset() +{ + pinMode(sht_sda_pin, INPUT_PULLUP); + pinMode(sht_scl_pin, OUTPUT); + delay(11); + for (byte i = 0; i < 9; i++) { + digitalWrite(sht_scl_pin, HIGH); + digitalWrite(sht_scl_pin, LOW); + } + boolean success = sht_sendCommand(SHT1X_CMD_SOFT_RESET); + delay(11); + return success; +} + +boolean sht_sendCommand(const byte cmd) +{ + pinMode(sht_sda_pin, OUTPUT); + // Transmission Start sequence + digitalWrite(sht_sda_pin, HIGH); + digitalWrite(sht_scl_pin, HIGH); + digitalWrite(sht_sda_pin, LOW); + digitalWrite(sht_scl_pin, LOW); + digitalWrite(sht_scl_pin, HIGH); + digitalWrite(sht_sda_pin, HIGH); + digitalWrite(sht_scl_pin, LOW); + // Send the command (address must be 000b) + shiftOut(sht_sda_pin, sht_scl_pin, MSBFIRST, cmd); + // Wait for ACK + boolean ackerror = false; + digitalWrite(sht_scl_pin, HIGH); + pinMode(sht_sda_pin, INPUT_PULLUP); + if (digitalRead(sht_sda_pin) != LOW) ackerror = true; + digitalWrite(sht_scl_pin, LOW); + delayMicroseconds(1); // Give the sensor time to release the data line + if (digitalRead(sht_sda_pin) != HIGH) ackerror = true; + if (ackerror) { + shttype = 0; + addLog_P(LOG_LEVEL_DEBUG, PSTR("SHT1X: Sensor did not ACK command")); + } + return (!ackerror); +} + +boolean sht_awaitResult() +{ + // Maximum 320ms for 14 bit measurement + for (byte i = 0; i < 16; i++) { + if (digitalRead(sht_sda_pin) == LOW) return true; + delay(20); + } + addLog_P(LOG_LEVEL_DEBUG, PSTR("SHT1X: Data not ready")); + shttype = 0; + return false; +} + +int sht_readData() +{ + int val = 0; + + // Read most significant byte + val = shiftIn(sht_sda_pin, sht_scl_pin, 8); + val <<= 8; + // Send ACK + pinMode(sht_sda_pin, OUTPUT); + digitalWrite(sht_sda_pin, LOW); + digitalWrite(sht_scl_pin, HIGH); + digitalWrite(sht_scl_pin, LOW); + pinMode(sht_sda_pin, INPUT_PULLUP); + // Read least significant byte + val |= shiftIn(sht_sda_pin, sht_scl_pin, 8); + // Keep DATA pin high to skip CRC + digitalWrite(sht_scl_pin, HIGH); + digitalWrite(sht_scl_pin, LOW); + return val; +} + +boolean sht_readTempHum(float &t, float &h) +{ + float tempRaw, humRaw, rhLinear; + + t = NAN; + h = NAN; + + if (!sht_reset()) return false; + if (!sht_sendCommand(SHT1X_CMD_MEASURE_TEMP)) return false; + if (!sht_awaitResult()) return false; + tempRaw = sht_readData(); + // Temperature conversion coefficients from SHT1X datasheet for version 4 + const float d1 = -39.7; // 3.5V + const float d2 = 0.01; // 14-bit + t = d1 + (tempRaw * d2); + if (!sht_sendCommand(SHT1X_CMD_MEASURE_RH)) return false; + if (!sht_awaitResult()) return false; + humRaw = sht_readData(); + // Temperature conversion coefficients from SHT1X datasheet for version 4 + const float c1 = -2.0468; + const float c2 = 0.0367; + const float c3 = -1.5955E-6; + const float t1 = 0.01; + const float t2 = 0.00008; + rhLinear = c1 + c2 * humRaw + c3 * humRaw * humRaw; + h = (t - 25) * (t1 + t2 * humRaw) + rhLinear; + if(!isnan(t) && TEMP_CONVERSION) t = t * 1.8 + 32; + return (!isnan(t) && !isnan(h)); +} + +boolean sht_readCharTempHum(char* temp, char* hum) +{ + float t, h; + + boolean success = sht_readTempHum(t, h); + dtostrf(t, 1, TEMP_RESOLUTION &3, temp); + dtostrf(h, 1, HUMIDITY_RESOLUTION &3, hum); + return success; +} + +boolean sht_detect() +{ + if (shttype) return true; + + float t, h; + + sht_sda_pin = pin[GPIO_I2C_SDA]; + sht_scl_pin = pin[GPIO_I2C_SCL]; + if (sht_readTempHum(t, h)) { + shttype = 1; + addLog_P(LOG_LEVEL_DEBUG, PSTR("I2C: SHT1X found")); + } else { + Wire.begin(sht_sda_pin, sht_scl_pin); + shttype = 0; + } + return shttype; +} + +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +void sht_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) +{ + if (!shttype) return; + + char stemp[10], shum[10]; + if (sht_readCharTempHum(stemp, shum)) { + snprintf_P(svalue, ssvalue, PSTR("%s, \"SHT1X\":{\"Temperature\":%s, \"Humidity\":%s}"), + svalue, stemp, shum); + *djson = 1; +#ifdef USE_DOMOTICZ + domoticz_sensor2(stemp, shum); +#endif // USE_DOMOTICZ + } +} + +#ifdef USE_WEBSERVER +String sht_webPresent() +{ + String page = ""; + if (shttype) { + char stemp[10], shum[10]; + if (sht_readCharTempHum(stemp, shum)) { + char sensor[80]; + snprintf_P(sensor, sizeof(sensor), HTTP_SNS_TEMP, "SHT1X", stemp, (TEMP_CONVERSION) ? 'F' : 'C'); + page += sensor; + snprintf_P(sensor, sizeof(sensor), HTTP_SNS_HUM, "SHT1X", shum); + page += sensor; + } + } + return page; +} +#endif // USE_WEBSERVER +#endif // USE_SHT +#endif // USE_I2C +