From a50a7d486f16caf5147a84140f47f5c1c0db7949 Mon Sep 17 00:00:00 2001 From: Hadinger Date: Wed, 12 Feb 2020 22:38:17 +0100 Subject: [PATCH 1/4] Fix wrong encoding of Zigbee persistent data --- tasmota/CHANGELOG.md | 1 + tasmota/xdrv_23_zigbee_3_devices.ino | 10 +++++----- tasmota/xdrv_23_zigbee_4_persistence.ino | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 3a12aff9b..667c5b69c 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -7,6 +7,7 @@ ### 8.1.0.7 20200210 - Add new DHT driver. The old driver can still be used using define USE_DHT_OLD (#7468) +- Fix wrong encoding of Zigbee persistent data ### 8.1.0.6 20200205 diff --git a/tasmota/xdrv_23_zigbee_3_devices.ino b/tasmota/xdrv_23_zigbee_3_devices.ino index 984842380..4814bdb8a 100644 --- a/tasmota/xdrv_23_zigbee_3_devices.ino +++ b/tasmota/xdrv_23_zigbee_3_devices.ino @@ -138,7 +138,7 @@ private: static bool findInVector(const std::vector & vecOfElements, const T & element); template < typename T> - static int32_t findEndpointInVector(const std::vector & vecOfElements, const T & element); + static int32_t findEndpointInVector(const std::vector & vecOfElements, uint8_t element); // find the first endpoint match for a cluster static int32_t findClusterEndpoint(const std::vector & vecOfElements, uint16_t element); @@ -180,12 +180,12 @@ bool Z_Devices::findInVector(const std::vector & vecOfElements, const T & e } template < typename T> -int32_t Z_Devices::findEndpointInVector(const std::vector & vecOfElements, const T & element) { +int32_t Z_Devices::findEndpointInVector(const std::vector & vecOfElements, uint8_t element) { // Find given element in vector int32_t found = 0; for (auto &elem : vecOfElements) { - if ((elem >> 16) & 0xFF == element) { return found; } + if ( ((elem >> 16) & 0xFF) == element) { return found; } found++; } @@ -427,7 +427,7 @@ void Z_Devices::addEndoint(uint16_t shortaddr, uint8_t endpoint) { Z_Device &device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found _updateLastSeen(device); - if (findEndpointInVector(device.endpoints, ep_profile) < 0) { + if (findEndpointInVector(device.endpoints, endpoint) < 0) { device.endpoints.push_back(ep_profile); dirty(); } @@ -439,7 +439,7 @@ void Z_Devices::addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t Z_Device &device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found _updateLastSeen(device); - int32_t found = findEndpointInVector(device.endpoints, ep_profile); + int32_t found = findEndpointInVector(device.endpoints, endpoint); if (found < 0) { device.endpoints.push_back(ep_profile); dirty(); diff --git a/tasmota/xdrv_23_zigbee_4_persistence.ino b/tasmota/xdrv_23_zigbee_4_persistence.ino index fcf1dcdc3..a45ce6709 100644 --- a/tasmota/xdrv_23_zigbee_4_persistence.ino +++ b/tasmota/xdrv_23_zigbee_4_persistence.ino @@ -31,7 +31,7 @@ // // [Array of devices] // [Offset = 2] -// uint8 - length of revice record +// uint8 - length of device record // uint16 - short address // uint64 - long IEEE address // uint8 - number of endpoints @@ -43,6 +43,7 @@ // // str - ModelID (null terminated C string, 32 chars max) // str - Manuf (null terminated C string, 32 chars max) +// str - FriendlyName (null terminated C string, 32 chars max) // reserved for extensions // Memory footprint From 51211dfd55d7ad537e4a19dc567cec7e875eaf0b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 13 Feb 2020 12:46:06 +0100 Subject: [PATCH 2/4] Attempt to fix slow wifi connection caused by #7602 Attempt to fix slow wifi connection caused by #7602 --- tasmota/support_wifi.ino | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino index f261738b6..376e7c6b1 100644 --- a/tasmota/support_wifi.ino +++ b/tasmota/support_wifi.ino @@ -429,6 +429,10 @@ void WifiCheckIp(void) WifiSetState(1); Wifi.counter = WIFI_CHECK_SEC; Wifi.retry = Wifi.retry_init; + if (Wifi.status != WL_CONNECTED) { + AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECTED)); + } + Wifi.status = WL_CONNECTED; #ifdef USE_DISCOVERY #ifdef WEBSERVER_ADVERTISE if (2 == Wifi.mdns_begun) { @@ -450,9 +454,29 @@ void WifiCheckIp(void) break; case WL_NO_SSID_AVAIL: AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_AP_NOT_REACHED)); + + if (WIFI_WAIT == Settings.sta_config) { + Wifi.retry = Wifi.retry_init; + } else { + if (Wifi.retry > (Wifi.retry_init / 2)) { + Wifi.retry = Wifi.retry_init / 2; + } + else if (Wifi.retry) { + Wifi.retry = 0; + } + } + break; case WL_CONNECT_FAILED: AddLog_P(LOG_LEVEL_INFO, S_LOG_WIFI, PSTR(D_CONNECT_FAILED_WRONG_PASSWORD)); + + if (Wifi.retry > (Wifi.retry_init / 2)) { + Wifi.retry = Wifi.retry_init / 2; + } + else if (Wifi.retry) { + Wifi.retry = 0; + } + break; default: // WL_IDLE_STATUS and WL_DISCONNECTED // log on the 1/2 or full interval From a7c85a673e9b7cb7f6583bf5a3eadf4e12e71a45 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Thu, 13 Feb 2020 17:19:02 +0200 Subject: [PATCH 3/4] Use dev version of PlatormIO Core I would be thankful if you use the development version of PIO Core. It's very stable and you should not have any problems with it. This should help us to be informed about any critical changes in PIO Core which can affect this project. Please report us any issues if they are related to PIO Core. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ffd47f546..88e971a06 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ python: sudo: false install: - pip install -U platformio - - platformio upgrade + - platformio upgrade --dev - platformio update cache: false From 7cc783a53261b07365c154bc3893c9b3ed8212fe Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 13 Feb 2020 17:02:07 +0100 Subject: [PATCH 4/4] Add another new DHT driver based on ESPEasy Add another new DHT driver based on ESPEasy. The old driver can still be used using define USE_DHT_OLD. The previous new driver can be used with define USE_DHT_V2 (#7717) --- RELEASENOTES.md | 2 + tasmota/CHANGELOG.md | 2 + tasmota/xdrv_01_webserver.ino | 2 +- .../{xsns_06_dht.ino => xsns_06_dht_v2.ino} | 4 +- tasmota/xsns_06_dht_v3.ino | 304 ++++++++++++++++++ 5 files changed, 311 insertions(+), 3 deletions(-) rename tasmota/{xsns_06_dht.ino => xsns_06_dht_v2.ino} (99%) create mode 100644 tasmota/xsns_06_dht_v3.ino diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 9104a5bb1..0962f6617 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -59,6 +59,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Change IRremoteESP8266 library updated to v2.7.3 - Change Zigbee command prefix from ``Zigbee*`` to ``Zb*`` - Change wifi connectivity stability (#7602) +- Change some wifi code to attempt faster connection (#7621) - Change MQTT message size with additional 200 characters - Fix Sonoff Bridge, Sc, L1, iFan03 and CSE7766 serial interface to forced speed, config and disable logging - Fix commands ``Display`` and ``Counter`` from overruling command processing (#7322) @@ -101,3 +102,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add optional Wifi AccessPoint passphrase define WIFI_AP_PASSPHRASE in my_user_config.h (#7690) - Add support for FiF LE-01MR energy meter by saper-2 (#7584) - Add new DHT driver. The old driver can still be used using define USE_DHT_OLD (#7468) +- Add another new DHT driver based on ESPEasy. The old driver can still be used using define USE_DHT_OLD. The previous new driver can be used with define USE_DHT_V2 (#7717) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 667c5b69c..0366cfb7f 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -3,6 +3,8 @@ ### 8.1.0.8 20200212 - Change MQTT message size with additional 200 characters +- Change some wifi code to attempt faster connection (#7621) +- Add another new DHT driver based on ESPEasy. The old driver can still be used using define USE_DHT_OLD. The previous new driver can be used with define USE_DHT_V2 (#7717) ### 8.1.0.7 20200210 diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 132c6a426..fc143f73a 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -31,7 +31,7 @@ #define WIFI_SOFT_AP_CHANNEL 1 // Soft Access Point Channel number between 1 and 11 as used by WifiManager web GUI #endif -const uint16_t CHUNKED_BUFFER_SIZE = 400; // Chunk buffer size (should be smaller than half mqtt_date size) +const uint16_t CHUNKED_BUFFER_SIZE = 400; // Chunk buffer size (should be smaller than half mqtt_date size = MESSZ) const uint16_t HTTP_REFRESH_TIME = 2345; // milliseconds #define HTTP_RESTART_RECONNECT_TIME 9000 // milliseconds diff --git a/tasmota/xsns_06_dht.ino b/tasmota/xsns_06_dht_v2.ino similarity index 99% rename from tasmota/xsns_06_dht.ino rename to tasmota/xsns_06_dht_v2.ino index 44fbfe576..3b692f224 100644 --- a/tasmota/xsns_06_dht.ino +++ b/tasmota/xsns_06_dht_v2.ino @@ -17,7 +17,7 @@ along with this program. If not, see . */ -#ifdef USE_DHT +#ifdef USE_DHT_V2 /*********************************************************************************************\ * DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321), SI7021 - Temperature and Humidy * @@ -274,7 +274,7 @@ void DhtInit(void) snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s%c%02d"), Dht[i].stype, IndexSeparator(), Dht[i].pin); } } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_SENSORS_FOUND " %d"), dht_sensors); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT "(v2) " D_SENSORS_FOUND " %d"), dht_sensors); } else { dht_active = false; } diff --git a/tasmota/xsns_06_dht_v3.ino b/tasmota/xsns_06_dht_v3.ino new file mode 100644 index 000000000..c777f732e --- /dev/null +++ b/tasmota/xsns_06_dht_v3.ino @@ -0,0 +1,304 @@ +/* + xsns_06_dht.ino - DHTxx, AM23xx and SI7021 temperature and humidity sensor support for Tasmota + + Copyright (C) 2020 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_DHT +/*********************************************************************************************\ + * DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321), SI7021 - Temperature and Humidy + * + * Reading temperature or humidity takes about 250 milliseconds! + * Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) + * + * This version is based on ESPEasy _P005_DHT.ino 20191201 +\*********************************************************************************************/ + +#define XSNS_06 6 + +#define DHT_MAX_SENSORS 4 +#define DHT_MAX_RETRY 8 + +uint8_t dht_data[5]; +uint8_t dht_sensors = 0; +uint8_t dht_pin_out = 0; // Shelly GPIO00 output only +bool dht_active = true; // DHT configured +bool dht_dual_mode = false; // Single pin mode + +struct DHTSTRUCT { + uint8_t pin; + uint8_t type; + char stype[12]; + uint32_t lastreadtime; + uint8_t lastresult; + float t = NAN; + float h = NAN; +} Dht[DHT_MAX_SENSORS]; + +bool DhtExpectPulse(uint8_t sensor, int level) +{ + unsigned long timeout = micros() + 100; + while (digitalRead(Dht[sensor].pin) != level) { + if (micros() > timeout) { return false; } + delayMicroseconds(1); + } + return true; +} + +int DhtReadDat(uint8_t sensor) +{ + uint8_t result = 0; + for (uint32_t i = 0; i < 8; i++) { + if (!DhtExpectPulse(sensor, HIGH)) { return -1; } + + delayMicroseconds(35); // was 30 + if (digitalRead(Dht[sensor].pin)) { + result |= (1 << (7 - i)); + } + + if (!DhtExpectPulse(sensor, LOW)) { return -1; } + } + return result; +} + +bool DhtRead(uint8_t sensor) +{ + dht_data[0] = dht_data[1] = dht_data[2] = dht_data[3] = dht_data[4] = 0; + + if (!dht_dual_mode) { + pinMode(Dht[sensor].pin, OUTPUT); + digitalWrite(Dht[sensor].pin, LOW); + } else { + digitalWrite(dht_pin_out, LOW); + } + + switch (Dht[sensor].type) { + case GPIO_DHT11: + delay(19); // minimum 18ms + break; + case GPIO_DHT22: + delay(2); // minimum 1ms + break; + case GPIO_SI7021: + delayMicroseconds(500); + break; + } + + if (!dht_dual_mode) { + pinMode(Dht[sensor].pin, INPUT_PULLUP); + } else { + digitalWrite(dht_pin_out, HIGH); + } + + switch (Dht[sensor].type) { + case GPIO_DHT11: + case GPIO_DHT22: + delayMicroseconds(50); + break; + case GPIO_SI7021: + // See: https://github.com/letscontrolit/ESPEasy/issues/1798 + delayMicroseconds(20); + break; + } + + noInterrupts(); + if (!DhtExpectPulse(sensor, LOW)) { + interrupts(); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE)); + return false; + } + if (!DhtExpectPulse(sensor, HIGH)) { + interrupts(); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_HIGH " " D_PULSE)); + return false; + } + if (!DhtExpectPulse(sensor, LOW)) { + interrupts(); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE)); + return false; + } + + int data = 0; + for (uint32_t i = 0; i < 5; i++) { + data = DhtReadDat(sensor); + if (-1 == data) { + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_PULSE)); + break; + } + dht_data[i] = data; + } + interrupts(); + if (-1 == data) { return false; } + + uint8_t checksum = (dht_data[0] + dht_data[1] + dht_data[2] + dht_data[3]) & 0xFF; + if (dht_data[4] != checksum) { + char hex_char[15]; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_CHECKSUM_FAILURE " %s =? %02X"), + ToHex_P(dht_data, 5, hex_char, sizeof(hex_char), ' '), checksum); + return false; + } + + return true; +} + +void DhtReadTempHum(uint8_t sensor) +{ + if ((NAN == Dht[sensor].h) || (Dht[sensor].lastresult > DHT_MAX_RETRY)) { // Reset after 8 misses + Dht[sensor].t = NAN; + Dht[sensor].h = NAN; + } + if (DhtRead(sensor)) { + switch (Dht[sensor].type) { + case GPIO_DHT11: + Dht[sensor].h = dht_data[0]; + Dht[sensor].t = dht_data[2] + ((float)dht_data[3] * 0.1f); // Issue #3164 + break; + case GPIO_DHT22: + case GPIO_SI7021: + Dht[sensor].h = ((dht_data[0] << 8) | dht_data[1]) * 0.1; + Dht[sensor].t = (((dht_data[2] & 0x7F) << 8 ) | dht_data[3]) * 0.1; + if (dht_data[2] & 0x80) { + Dht[sensor].t *= -1; + } + break; + } + Dht[sensor].t = ConvertTemp(Dht[sensor].t); + Dht[sensor].h = ConvertHumidity(Dht[sensor].h); + Dht[sensor].lastresult = 0; + } else { + Dht[sensor].lastresult++; + } +} + +/********************************************************************************************/ + +bool DhtPinState() +{ + if ((XdrvMailbox.index >= GPIO_DHT11) && (XdrvMailbox.index <= GPIO_SI7021)) { + if (dht_sensors < DHT_MAX_SENSORS) { + Dht[dht_sensors].pin = XdrvMailbox.payload; + Dht[dht_sensors].type = XdrvMailbox.index; + dht_sensors++; + XdrvMailbox.index = GPIO_DHT11; + } else { + XdrvMailbox.index = 0; + } + return true; + } + return false; +} + +void DhtInit(void) +{ + if (dht_sensors) { + if (pin[GPIO_DHT11_OUT] < 99) { + dht_pin_out = pin[GPIO_DHT11_OUT]; + dht_dual_mode = true; // Dual pins mode as used by Shelly + dht_sensors = 1; // We only support one sensor in pseudo mode + pinMode(dht_pin_out, OUTPUT); + } + + for (uint32_t i = 0; i < dht_sensors; i++) { + pinMode(Dht[i].pin, INPUT_PULLUP); + Dht[i].lastreadtime = 0; + Dht[i].lastresult = 0; + GetTextIndexed(Dht[i].stype, sizeof(Dht[i].stype), Dht[i].type, kSensorNames); + if (dht_sensors > 1) { + snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s%c%02d"), Dht[i].stype, IndexSeparator(), Dht[i].pin); + } + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT "(v3) " D_SENSORS_FOUND " %d"), dht_sensors); + } else { + dht_active = false; + } +} + +void DhtEverySecond(void) +{ + if (uptime &1) { + // <1mS +// DhtReadPrep(); + } else { + for (uint32_t i = 0; i < dht_sensors; i++) { + // DHT11 and AM2301 25mS per sensor, SI7021 5mS per sensor + DhtReadTempHum(i); + } + } +} + +void DhtShow(bool json) +{ + for (uint32_t i = 0; i < dht_sensors; i++) { + char temperature[33]; + dtostrfd(Dht[i].t, Settings.flag2.temperature_resolution, temperature); + char humidity[33]; + dtostrfd(Dht[i].h, Settings.flag2.humidity_resolution, humidity); + + if (json) { + ResponseAppend_P(JSON_SNS_TEMPHUM, Dht[i].stype, temperature, humidity); +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && (0 == i)) { + DomoticzTempHumSensor(temperature, humidity); + } +#endif // USE_DOMOTICZ +#ifdef USE_KNX + if ((0 == tele_period) && (0 == i)) { + KnxSensor(KNX_TEMPERATURE, Dht[i].t); + KnxSensor(KNX_HUMIDITY, Dht[i].h); + } +#endif // USE_KNX +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_TEMP, Dht[i].stype, temperature, TempUnit()); + WSContentSend_PD(HTTP_SNS_HUM, Dht[i].stype, humidity); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns06(uint8_t function) +{ + bool result = false; + + if (dht_active) { + switch (function) { + case FUNC_EVERY_SECOND: + DhtEverySecond(); + break; + case FUNC_JSON_APPEND: + DhtShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + DhtShow(0); + break; +#endif // USE_WEBSERVER + case FUNC_INIT: + DhtInit(); + break; + case FUNC_PIN_STATE: + result = DhtPinState(); + break; + } + } + return result; +} + +#endif // USE_DHT