From 048474f7ac2534f6edb2c86a92ce895cecdf01d0 Mon Sep 17 00:00:00 2001 From: Staars Date: Fri, 6 Mar 2020 19:22:30 +0100 Subject: [PATCH 1/7] add missing PDU-type, small refactoring --- tasmota/xsns_61_MI_NRF24.ino | 124 ++++++++++++++++++++++++++++------- 1 file changed, 99 insertions(+), 25 deletions(-) diff --git a/tasmota/xsns_61_MI_NRF24.ino b/tasmota/xsns_61_MI_NRF24.ino index f1db19d74..69a99cb08 100644 --- a/tasmota/xsns_61_MI_NRF24.ino +++ b/tasmota/xsns_61_MI_NRF24.ino @@ -21,6 +21,9 @@ Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 0.9.4.0 20200304 integrate - sensor types can be ignored (default for LYWSD03), + add CGD1 (Alarm clock), correct PDU-types for LYWSD02 + --- 0.9.3.0 20200222 integrate - use now the correct id-word instead of MAC-OUI, add CGG1 --- @@ -48,7 +51,7 @@ /*********************************************************************************************\ * MINRF -* BLE-Sniffer/Bridge for MIJIA/XIAOMI Temperatur/Humidity-Sensor, Mi Flora, LYWSD02 +* BLE-Sniffer/Bridge for MIJIA/XIAOMI Temperatur/Humidity-Sensor, Mi Flora, LYWSD02, GCx * * Usage: Configure NRF24 \*********************************************************************************************/ @@ -62,12 +65,19 @@ #define LYWSD02 3 #define LYWSD03 4 #define CGG1 5 +#define CGD1 6 -const uint16_t kMINRFSlaveID[5]={ 0x0098, // Flora +/* define sensors to ignore, which can improve performance + pattern: #define IGNORE_sensorname +*/ +#define IGNORE_LYWSD03 + +const uint16_t kMINRFSlaveID[6]={ 0x0098, // Flora 0x01aa, // MJ_HT_V1 0x045b, // LYWSD02 0x055b, // LYWSD03 - 0x0347 // CGG1 + 0x0347, // CGG1 + 0x0576 // CGD1 }; const char kMINRFSlaveType1[] PROGMEM = "Flora"; @@ -75,19 +85,21 @@ const char kMINRFSlaveType2[] PROGMEM = "MJ_HT_V1"; const char kMINRFSlaveType3[] PROGMEM = "LYWSD02"; const char kMINRFSlaveType4[] PROGMEM = "LYWSD03"; const char kMINRFSlaveType5[] PROGMEM = "CGG1"; -const char * kMINRFSlaveType[] PROGMEM = {kMINRFSlaveType1,kMINRFSlaveType2,kMINRFSlaveType3,kMINRFSlaveType4,kMINRFSlaveType5}; +const char kMINRFSlaveType6[] PROGMEM = "CGD1"; +const char * kMINRFSlaveType[] PROGMEM = {kMINRFSlaveType1,kMINRFSlaveType2,kMINRFSlaveType3,kMINRFSlaveType4,kMINRFSlaveType5,kMINRFSlaveType6}; // PDU's or different channels 37-39 const uint32_t kMINRFFloPDU[3] = {0x3eaa857d,0xef3b8730,0x71da7b46}; const uint32_t kMINRFMJPDU[3] = {0x4760cd66,0xdbcc0cd3,0x33048df5}; -const uint32_t kMINRFL2PDU[3] = {0x3eaa057d,0xef3b0730,0x71da7646}; // 1 and 3 unsure +const uint32_t kMINRFL2PDU[3] = {0x3eaa057d,0xef3b0730,0x71dafb46}; // const uint32_t kMINRFL3PDU[3] = {0x4760dd78,0xdbcc1ccd,0xffffffff}; //encrypted - 58 58 const uint32_t kMINRFL3PDU[3] = {0x4760cb78,0xdbcc0acd,0x33048beb}; //unencrypted - 30 58 -const uint32_t kMINRFCGPDU[3] = {0x4760cd6e,0xdbcc0cdb,0x33048dfd}; +const uint32_t kMINRFCGGPDU[3] = {0x4760cd6e,0xdbcc0cdb,0x33048dfd}; +const uint32_t kMINRFCGDPDU[3] = {0x5da0d752,0xc10c16e7,0x29c497c1}; // start-LSFR for different channels 37-39 const uint8_t kMINRFlsfrList_A[3] = {0x4b,0x17,0x23}; // Flora, LYWSD02 -const uint8_t kMINRFlsfrList_B[3] = {0x21,0x72,0x43}; // MJ_HT_V1, LYWSD03, CGG1 +const uint8_t kMINRFlsfrList_B[3] = {0x21,0x72,0x43}; // MJ_HT_V1, LYWSD03, CGx #pragma pack(1) // important!! @@ -196,6 +208,15 @@ union LYWSD02Packet_t { // related to the whole 32-byte-packet/buffer } TH; // mode 04 or 06 }; +union CGDPacket_t { // related to the whole 32-byte-packet/buffer + struct { + uint8_t serial[6]; + uint16_t mode; + int16_t temp; // -9 - 59 °C + uint16_t hum; + } TH; // This is no MiBeacon +}; + struct bleAdvPacket_t { // for nRF24L01 max 32 bytes = 2+6+24 uint8_t pduType; uint8_t payloadSize; @@ -254,6 +275,7 @@ union FIFO_t{ floraPacket_t floraPacket; MJ_HT_V1Packet_t MJ_HT_V1Packet; LYWSD02Packet_t LYWSD02Packet; + CGDPacket_t CGDPacket; uint8_t raw[32]; }; @@ -266,7 +288,7 @@ struct { uint16_t timer; uint8_t currentChan=0; FIFO_t buffer; - uint8_t packetMode; // 0 - normal BLE-advertisements, 1 - special "flora"-packet, 2 - special "MJ_HT_V1"-packet + uint8_t packetMode; // 0 - normal BLE-advertisements, 1 - 6 "special" sensor packets #ifdef DEBUG_TASMOTA_SENSOR uint8_t streamBuffer[sizeof(buffer)]; // raw data stream bytes @@ -276,10 +298,10 @@ struct { } MINRF; struct mi_sensor_t{ - uint8_t type; //Flora = 1; MJ_HT_V1=2; LYWSD02=3; LYWSD03=4; ; CGG1=5 + uint8_t type; //Flora = 1; MJ_HT_V1=2; LYWSD02=3; LYWSD03=4; CGG1=5; CGD1=6 uint8_t serial[6]; uint8_t showedUp; - float temp; //Flora, MJ_HT_V1, LYWSD0x + float temp; //Flora, MJ_HT_V1, LYWSD0x, CGx union { struct { float moisture; @@ -289,7 +311,7 @@ struct mi_sensor_t{ struct { float hum; uint8_t bat; - }; // MJ_HT_V1, LYWSD0x + }; // MJ_HT_V1, LYWSD0x, CGx }; }; @@ -372,6 +394,9 @@ bool MINRFreceivePacket(void) case 5: MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); // "CGG1" mode break; + case 6: + MINRFwhiten((uint8_t *)&MINRF.buffer, sizeof(MINRF.buffer), kMINRFlsfrList_B[MINRF.currentChan]); // "CGD1" mode + break; } // DEBUG_SENSOR_LOG(PSTR("MINRF: LSFR:%x"),_lsfr); // if (_lsfr>254) _lsfr=0; @@ -481,7 +506,10 @@ void MINRFchangePacketModeTo(uint8_t _mode) { NRF24radio.openReadingPipe(0,kMINRFL3PDU[_nextchannel]);// 95 fe 58 30 -> LYWSD03 (= no data message) break; case 5: // special CGG1 packet - NRF24radio.openReadingPipe(0,kMINRFCGPDU[_nextchannel]); // 95 fe 50 30 -> CGG1 + NRF24radio.openReadingPipe(0,kMINRFCGGPDU[_nextchannel]); // 95 fe 50 30 -> CGG1 + break; + case 6: // special CGD1 packet + NRF24radio.openReadingPipe(0,kMINRFCGDPDU[_nextchannel]); // cd fd 08 0c -> CGD1 break; } // DEBUG_SENSOR_LOG(PSTR("MINRF: Change Mode to %u"),_mode); @@ -499,7 +527,7 @@ uint32_t MINRFgetSensorSlot(uint8_t (&_serial)[6], uint16_t _type){ DEBUG_SENSOR_LOG(PSTR("MINRF: will test ID-type: %x"), _type); bool _success = false; - for (uint32_t i=0;i<5;i++){ + for (uint32_t i=0;i<6;i++){ // i < sizeof(kMINRFSlaveID) gives compiler warning if(_type == kMINRFSlaveID[i]){ DEBUG_SENSOR_LOG(PSTR("MINRF: ID is type %u"), i); _type = i+1; @@ -536,9 +564,9 @@ uint32_t MINRFgetSensorSlot(uint8_t (&_serial)[6], uint16_t _type){ _newSensor.fertility =-1000.0f; _newSensor.lux = 0x00ffffff; break; - case 2: case 3: case 4: + case 2: case 3: case 4: case 5: case 6: _newSensor.hum=-1.0f; - _newSensor.bat=0xff; + _newSensor.bat=0x00; break; default: break; @@ -574,7 +602,7 @@ void MINRFhandleFloraPacket(void){ DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); if(_slot==0xff) return; - static float _tempFloat; + float _tempFloat; switch(MINRF.buffer.floraPacket.L.mode) { // we can use any struct with a mode, they are all same at this point case 4: _tempFloat=(float)(MINRF.buffer.floraPacket.T.data)/10.0f; @@ -617,7 +645,7 @@ void MINRFhandleMJ_HT_V1Packet(void){ DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); if(_slot==0xff) return; - static float _tempFloat; + float _tempFloat; switch(MINRF.buffer.MJ_HT_V1Packet.TH.mode) { // we can use any struct with a mode, they are all same at this point case 0x0d: _tempFloat=(float)(MINRF.buffer.MJ_HT_V1Packet.TH.temp)/10.0f; @@ -653,7 +681,7 @@ void MINRFhandleLYWSD02Packet(void){ DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); if(_slot==0xff) return; - static float _tempFloat; + float _tempFloat; switch(MINRF.buffer.LYWSD02Packet.TH.mode) { // we can use any struct with a mode, they are all same at this point case 4: _tempFloat=(float)(MINRF.buffer.LYWSD02Packet.TH.data)/10.0f; @@ -695,7 +723,7 @@ void MINRFhandleCGG1Packet(void){ // we assume, that the packet structure is equ DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); if(_slot==0xff) return; - static float _tempFloat; + float _tempFloat; switch(MINRF.buffer.MJ_HT_V1Packet.TH.mode) { // we can use any struct with a mode, they are all same at this point case 0x0d: _tempFloat=(float)(MINRF.buffer.MJ_HT_V1Packet.TH.temp)/10.0f; @@ -720,6 +748,31 @@ void MINRFhandleCGG1Packet(void){ // we assume, that the packet structure is equ } } +void MINRFhandleCGD1Packet(void){ // + if(MINRF.buffer.CGDPacket.TH.mode!=0x0401){ // not really a mode + DEBUG_SENSOR_LOG(PSTR("MINRF: unexpected CGD1-packet")); + MINRF_LOG_BUFFER(MINRF.buffer.raw); + return; + } + MINRFreverseMAC(MINRF.buffer.CGDPacket.TH.serial); + uint32_t _slot = MINRFgetSensorSlot(MINRF.buffer.CGDPacket.TH.serial, 0x0576); // This must be hard-coded, no object-id in Cleargrass-packet + DEBUG_SENSOR_LOG(PSTR("MINRF: Sensor slot: %u"), _slot); + if(_slot==0xff) return; + + float _tempFloat; + _tempFloat=(float)(MINRF.buffer.CGDPacket.TH.temp)/10.0f; + if(_tempFloat<60){ + MIBLEsensors.at(_slot).temp = _tempFloat; + DEBUG_SENSOR_LOG(PSTR("CGD1: temp updated")); + } + _tempFloat=(float)(MINRF.buffer.CGDPacket.TH.hum)/10.0f; + if(_tempFloat<100){ + MIBLEsensors.at(_slot).hum = _tempFloat; + DEBUG_SENSOR_LOG(PSTR("CGD1: hum updated")); + } + DEBUG_SENSOR_LOG(PSTR("CGD1: U16: %x Temp U16: %x Hum"), MINRF.buffer.CGDPacket.TH.temp, MINRF.buffer.CGDPacket.TH.hum); +} + /*********************************************************************************************\ * Main loop of the driver \*********************************************************************************************/ @@ -769,11 +822,32 @@ void MINRF_EVERY_50_MSECOND() { // Every 50mseconds else if (MINRF.packetMode == CGG1){ MINRFhandleCGG1Packet(); } - if (MINRF.packetMode == CGG1){ - MINRFinitBLE(1); // no real ble packets in release mode, otherwise for developing use 0 + else if (MINRF.packetMode == CGD1){ + MINRFhandleCGD1Packet(); } - else { - MINRFinitBLE(++MINRF.packetMode); + +#ifdef IGNORE_FLORA + if (MINRF.packetMode+1 == FLORA) MINRF.packetMode++; +#endif // IGNORE_LYWSD03 +#ifdef IGNORE_MJ_HT_V1 + if (MINRF.packetMode+1 == MJ_HT_V1) MINRF.packetMode++; +#endif //IGNORE_MJ_HT_V1 +#ifdef IGNORE_LYWSD02 + if (MINRF.packetMode+1 == LYWSD02) MINRF.packetMode++; +#endif // IGNORE_LYWSD02 +#ifdef IGNORE_LYWSD03 + if (MINRF.packetMode+1 == LYWSD03) MINRF.packetMode++; +#endif // IGNORE_LYWSD03 +#ifdef IGNORE_CGG1 + if (MINRF.packetMode+1 == CGG1) MINRF.packetMode++; +#endif // IGNORE_CGG1 +#ifdef IGNORE_CGD1 + if (MINRF.packetMode+1 == CGD1) MINRF.packetMode=0; +#endif // IGNORE_CGD1 + MINRFinitBLE(++MINRF.packetMode); + +if (MINRF.packetMode > CGD1){ + MINRFinitBLE(1); // no real ble packets in release mode, otherwise for developing use 0 } MINRFhopChannel(); @@ -828,7 +902,7 @@ void MINRFShow(bool json) if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); } - if(MIBLEsensors.at(i).bat!=0xff){ // this is the error code -> no battery + if(MIBLEsensors.at(i).bat!=0x00){ // this is the error code -> no battery ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).bat); } } @@ -868,7 +942,7 @@ void MINRFShow(bool json) dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); WSContentSend_PD(HTTP_SNS_HUM, kMINRFSlaveType[MIBLEsensors.at(i).type-1], humidity); } - if(MIBLEsensors.at(i).bat!=0xff){ + if(MIBLEsensors.at(i).bat!=0x00){ // without "juice" nothing can be done WSContentSend_PD(HTTP_BATTERY, kMINRFSlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).bat); } } From cd14bde1f709224802ab18f25e32f8381dfc48f7 Mon Sep 17 00:00:00 2001 From: Alexander Schliebner Date: Fri, 6 Mar 2020 21:13:12 +0100 Subject: [PATCH 2/7] Update xdrv_10_scripter.ino MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added mapping function `mp` ´´´ mp(x str1 str2 ... str) ´´´ It addresses a standard task with less code and much flexibility: mapping an arbitrary incoming numeric value into the allowed range. The numeric value `x` passed as the first parameter is compared to the rules in the order they are provided as subsequent sting parameters. If the value matches the criteria, the defined value is returned. Subsequent rules are skipped. If `x` matches none of the rules, `x` is returned unchanged. Rules consist of one of the comparison operators `< > =` followed by a numeric value `v1`, optionally followed by a colon and another numeric value `v2`. ``` <|>|=v1[:v2] ``` Example 1: `"<8:0"` - this rule reads: If x is less than 8, return 0. Example 2: `">100"` - this rule reads: If x is greater than 100, return 100. Example 3: ``` y=mp(x "<8:0" ">100") ``` Assigns 0 to y if x is less than 8. Assigns 100 to y if x is greater than 100. Assigns x to y for all values of x that do not meet the above criteria (8 to 100). The above code of example 3 does the same as the following code - with just one line of code and 15 characters less: ``` y=x if x<8 { y=0 } if x>100 { y=100 } ``` --- tasmota/xdrv_10_scripter.ino | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index d850dfaea..074e32baa 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -1496,6 +1496,40 @@ chknext: fvar=!global_state.mqtt_down; goto exit; } + if (!strncmp(vname,"mp(",3)) { + lp+=3; + float fvar1; + lp=GetNumericResult(lp,OPER_EQU,&fvar1,0); + SCRIPT_SKIP_SPACES + while (*lp!=')') { + char str[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,str,0); + SCRIPT_SKIP_SPACES + char *pstr=str; + pstr++; + float fvar2; + pstr=GetNumericResult(pstr,OPER_EQU,&fvar2,0); + while (*pstr==' ') pstr++; + fvar=fvar1; + if ((str[0]=='<' && fvar1' && fvar1>fvar2) || + (str[0]=='=' && fvar1==fvar2)) + { + if (*pstr==':') { + pstr++; + while (*pstr==' ') pstr++; + float fvar3; + pstr=GetNumericResult(pstr,OPER_EQU,&fvar3,0); + fvar=fvar3; + } else { + fvar=fvar2; + } + break; + } + } + len=0; + goto exit; + } break; case 'p': if (!strncmp(vname,"pin[",4)) { From 7df46f051d58fe64148d5c97d0677178a37b57fe Mon Sep 17 00:00:00 2001 From: Alexander Schliebner Date: Sat, 7 Mar 2020 16:53:49 +0100 Subject: [PATCH 3/7] Optimized function 'mp' Leaner syntax of function `mp` and simplified implementation. New documentation: Mapping function `mp` It addresses a standard task with less code and much flexibility: mapping an arbitrary incoming numeric value into a defined schema of allowed/reasonable ranges. The numeric value `x` passed as the first parameter is compared to the mprules in the order they are provided as subsequent parameters. If the value matches the criteria, the defined value is returned. Subsequent mprules are skipped. If `x` matches none of the mprules, `x` is returned unchanged. ``` mp(x mprule1 mprule2 ... mprule) ``` An mprule starts with one of the comparison operators `<`, `>` or `=`, followed by a numeric value `v1`, optionally followed by a second numeric value `v2`: ``` <|>|=v1[ v2] ``` Example 1: `<8 0` - this rule reads: If x is less than 8, return 0. Example 2: `>100` - this rule reads: If x is greater than 100, return 100. Example 3: ``` y=mp(x <8 0 >100) ``` Assigns 0 to y if x is less than 8. Assigns 100 to y if x is greater than 100. Assigns x to y for all values of x that do not meet the above criteria (8 to 100). The above code of example 3 does the same as the following code - with just one line of code and 19 characters less: ``` y=x if x<8 { y=0 } if x>100 { y=100 } ``` Every of the above mentioned numeric values `x`, `v1` and `v2` can be a literal, an expression or a variable. --- tasmota/xdrv_10_scripter.ino | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 074e32baa..be65a3e37 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -1502,30 +1502,27 @@ chknext: lp=GetNumericResult(lp,OPER_EQU,&fvar1,0); SCRIPT_SKIP_SPACES while (*lp!=')') { - char str[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,str,0); - SCRIPT_SKIP_SPACES - char *pstr=str; - pstr++; + char *opp=lp; + lp++; float fvar2; - pstr=GetNumericResult(pstr,OPER_EQU,&fvar2,0); - while (*pstr==' ') pstr++; + lp=GetNumericResult(lp,OPER_EQU,&fvar2,0); + SCRIPT_SKIP_SPACES fvar=fvar1; - if ((str[0]=='<' && fvar1' && fvar1>fvar2) || - (str[0]=='=' && fvar1==fvar2)) + if ((*opp=='<' && fvar1' && fvar1>fvar2) || + (*opp=='=' && fvar1==fvar2)) { - if (*pstr==':') { - pstr++; - while (*pstr==' ') pstr++; + if (*lp!='<' && *lp!='>' && *lp!='=') { float fvar3; - pstr=GetNumericResult(pstr,OPER_EQU,&fvar3,0); + lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); + SCRIPT_SKIP_SPACES fvar=fvar3; } else { fvar=fvar2; } break; } + while (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) lp++; } len=0; goto exit; From 2335f2fedd0b592bdbb4fb2e23a0ad56ca3730c0 Mon Sep 17 00:00:00 2001 From: Alexander Schliebner Date: Sat, 7 Mar 2020 18:52:24 +0100 Subject: [PATCH 4/7] Bugfix in function 'mp' If optional parameter v2 was omitted, evaluation failed. --- tasmota/xdrv_10_scripter.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index be65a3e37..30ed26598 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -1512,7 +1512,7 @@ chknext: (*opp=='>' && fvar1>fvar2) || (*opp=='=' && fvar1==fvar2)) { - if (*lp!='<' && *lp!='>' && *lp!='=') { + if (*lp!='<' && *lp!='>' && *lp!='=' && *lp!=')' && *lp!=SCRIPT_EOL) { float fvar3; lp=GetNumericResult(lp,OPER_EQU,&fvar3,0); SCRIPT_SKIP_SPACES From bf86700e906b02917ba83e21cb06c8e7662c9998 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Mar 2020 12:28:14 +0100 Subject: [PATCH 5/7] Consolidate DHT sensor driver --- RELEASENOTES.md | 3 +- .../{xsns_06_dht_v5.ino => xsns_06_dht.ino} | 0 tasmota/xsns_06_dht_old.ino | 307 --------------- tasmota/xsns_06_dht_v2.ino | 358 ------------------ tasmota/xsns_06_dht_v3.ino | 304 --------------- tasmota/xsns_06_dht_v4.ino | 293 -------------- 6 files changed, 1 insertion(+), 1264 deletions(-) rename tasmota/{xsns_06_dht_v5.ino => xsns_06_dht.ino} (100%) delete mode 100644 tasmota/xsns_06_dht_old.ino delete mode 100644 tasmota/xsns_06_dht_v2.ino delete mode 100644 tasmota/xsns_06_dht_v3.ino delete mode 100644 tasmota/xsns_06_dht_v4.ino diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2fc828a40..e474c75ec 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -55,6 +55,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ### Version 8.1.0.10 - Change default my_user_config.h driver and sensor support removing most sensors and adding most drivers +- Change DHT driver (#7468, #7717) - Change Lights: simplified gamma correction and 10 bits internal computation - Change commands ``Prefix``, ``Ssid``, ``StateText``, ``NTPServer``, and ``FriendlyName`` displaying all items - Change IRremoteESP8266 library updated to v2.7.4 @@ -108,8 +109,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add ``ZbZNPReceived``and ``ZbZCLReceived`` being published to MQTT when ``SetOption66 1`` - 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) - Add initial support for Sensors AHT10 and AHT15 by Martin Wagner (#7596) - Add support for Wemos Motor Shield V1 by Denis Sborets (#7764) - Add Zigbee enhanced commands decoding, added ``ZbPing`` diff --git a/tasmota/xsns_06_dht_v5.ino b/tasmota/xsns_06_dht.ino similarity index 100% rename from tasmota/xsns_06_dht_v5.ino rename to tasmota/xsns_06_dht.ino diff --git a/tasmota/xsns_06_dht_old.ino b/tasmota/xsns_06_dht_old.ino deleted file mode 100644 index b38f01236..000000000 --- a/tasmota/xsns_06_dht_old.ino +++ /dev/null @@ -1,307 +0,0 @@ -/* - 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_OLD -/*********************************************************************************************\ - * 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) - * Source: Adafruit Industries https://github.com/adafruit/DHT-sensor-library -\*********************************************************************************************/ - -#define XSNS_06 6 - -#define DHT_MAX_SENSORS 4 -#define DHT_MAX_RETRY 8 - -uint32_t dht_max_cycles; -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]; - -void DhtReadPrep(void) -{ - for (uint32_t i = 0; i < dht_sensors; i++) { - if (!dht_dual_mode) { - digitalWrite(Dht[i].pin, HIGH); - } else { - digitalWrite(dht_pin_out, HIGH); - } - } -} - -int32_t DhtExpectPulse(uint8_t sensor, bool level) -{ - int32_t count = 0; - - while (digitalRead(Dht[sensor].pin) == level) { - if (count++ >= (int32_t)dht_max_cycles) { - return -1; // Timeout - } - } - return count; -} - -bool DhtRead(uint8_t sensor) -{ - int32_t cycles[80]; - uint8_t error = 0; - - dht_data[0] = dht_data[1] = dht_data[2] = dht_data[3] = dht_data[4] = 0; - -// digitalWrite(Dht[sensor].pin, HIGH); -// delay(250); - - if (Dht[sensor].lastresult > DHT_MAX_RETRY) { - Dht[sensor].lastresult = 0; - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); // Retry read prep - } else { - digitalWrite(dht_pin_out, HIGH); - } - delay(250); - } - if (!dht_dual_mode) { - pinMode(Dht[sensor].pin, OUTPUT); - digitalWrite(Dht[sensor].pin, LOW); - } else { - digitalWrite(dht_pin_out, LOW); - } - - if (GPIO_SI7021 == Dht[sensor].type) { - delayMicroseconds(500); - } else { - delay(20); - } - - noInterrupts(); - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); - delayMicroseconds(40); - pinMode(Dht[sensor].pin, INPUT_PULLUP); - } else { - digitalWrite(dht_pin_out, HIGH); - delayMicroseconds(40); - } - delayMicroseconds(10); - if (-1 == DhtExpectPulse(sensor, LOW)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE)); - error = 1; - } - else if (-1 == DhtExpectPulse(sensor, HIGH)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_HIGH " " D_PULSE)); - error = 1; - } - else { - for (uint32_t i = 0; i < 80; i += 2) { - cycles[i] = DhtExpectPulse(sensor, LOW); - cycles[i+1] = DhtExpectPulse(sensor, HIGH); - } - } - interrupts(); - - if (error) { return false; } - - for (uint32_t i = 0; i < 40; ++i) { - int32_t lowCycles = cycles[2*i]; - int32_t highCycles = cycles[2*i+1]; - if ((-1 == lowCycles) || (-1 == highCycles)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_PULSE)); - return false; - } - dht_data[i/8] <<= 1; - if (highCycles > lowCycles) { - dht_data[i / 8] |= 1; - } - } - - 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) { - dht_max_cycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for reading pulses from DHT sensor. - - 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 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 diff --git a/tasmota/xsns_06_dht_v2.ino b/tasmota/xsns_06_dht_v2.ino deleted file mode 100644 index 3b692f224..000000000 --- a/tasmota/xsns_06_dht_v2.ino +++ /dev/null @@ -1,358 +0,0 @@ -/* - 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_V2 -/*********************************************************************************************\ - * 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) - * Source: Adafruit Industries https://github.com/adafruit/DHT-sensor-library -\*********************************************************************************************/ - -#define XSNS_06 6 - -#define DHT_MAX_SENSORS 4 -#define DHT_MAX_RETRY 8 - -uint32_t dht_max_cycles; -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]; - -void DhtReadPrep(void) -{ - for (uint32_t i = 0; i < dht_sensors; i++) { - if (!dht_dual_mode) { - digitalWrite(Dht[i].pin, HIGH); - } else { - digitalWrite(dht_pin_out, HIGH); - } - } -} - -int32_t DhtExpectPulse(uint8_t sensor, bool level) -{ - int32_t count = 0; - - while (digitalRead(Dht[sensor].pin) == level) { - if (count++ >= (int32_t)dht_max_cycles) { - return -1; // Timeout - } - } - return count; -} - -bool DhtRead(uint8_t sensor) -{ - int32_t cycles[80]; - uint8_t error = 0; - - dht_data[0] = dht_data[1] = dht_data[2] = dht_data[3] = dht_data[4] = 0; - - if (Dht[sensor].lastresult > DHT_MAX_RETRY) { - Dht[sensor].lastresult = 0; - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); // Retry read prep - } else { - digitalWrite(dht_pin_out, HIGH); - } - delay(250); - } - - // Activate sensor using its protocol - noInterrupts(); - 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_SI7021: // Start protocol for iTead SI7021 - /* - Protocol: - Reverse-engineered on https://github.com/arendst/Tasmota/issues/735#issuecomment-348718383: - 1. MCU PULLS LOW data bus for at 500us to activate sensor - 2. MCU PULLS UP data bus for ~40us to ask sensor for response - 3. SENSOR starts sending data (LOW 40us then HIGH ~25us for "0" or ~75us for "1") - 4. SENSOR sends "1" start bit as a response - 5. SENSOR sends 16 bits (2 bytes) of a humidity with one decimal (i.e. 35.6% is sent as 356) - 6. SENSOR sends 16 bits (2 bytes) of a temperature with one decimal (i.e. 23.4C is sent as 234) - 7. SENSOR sends 8 bits (1 byte) checksum of 4 data bytes - */ -// digitalWrite(Dht[sensor].pin, LOW); - delayMicroseconds(500); - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); - } else { - digitalWrite(dht_pin_out, HIGH); - } - delayMicroseconds(40); - break; - - case GPIO_DHT22: // Start protocol for DHT21, DHT22, AM2301, AM2302, AM2321 - /* - Protocol: - 1. MCU PULLS LOW data bus for 1 to 10ms to activate sensor - 2. MCU PULLS UP data bus for 20-40us to ask sensor for response - 3. SENSOR PULLS LOW data bus for 80us as a response - 4. SENSOR PULLS UP data bus for 80us for data sending preparation - 5. SENSOR starts sending data (LOW 50us then HIGH 26-28us for "0" or 70us for "1") - */ -// digitalWrite(Dht[sensor].pin, LOW); - delayMicroseconds(1100); // data sheet says "at least 1ms to 10ms" - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); - } else { - digitalWrite(dht_pin_out, HIGH); - } - delayMicroseconds(30); // data sheet says "20 to 40us" - break; - - case GPIO_DHT11: // Start protocol for DHT11 - /* - Protocol: - 1. MCU PULLS LOW data bus for at least 18ms to activate sensor - 2. MCU PULLS UP data bus for 20-40us to ask sensor for response - 3. SENSOR PULLS LOW data bus for 80us as a response - 4. SENSOR PULLS UP data bus for 80us for data sending preparation - 5. SENSOR starts sending data (LOW 50us then HIGH 26-28us for "0" or 70 us for "1") - */ - default: -// digitalWrite(Dht[sensor].pin, LOW); - delay(20); // data sheet says at least 18ms, 20ms just to be safe - if (!dht_dual_mode) { - digitalWrite(Dht[sensor].pin, HIGH); - } else { - digitalWrite(dht_pin_out, HIGH); - } - delayMicroseconds(30); // data sheet says "20 to 40us" - break; - } - - // Listen to the sensor response - pinMode(Dht[sensor].pin, INPUT_PULLUP); - - if (-1 == DhtExpectPulse(sensor, LOW)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE)); - error = 1; - } - else if (-1 == DhtExpectPulse(sensor, HIGH)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_HIGH " " D_PULSE)); - error = 1; - } - else { - for (uint32_t i = 0; i < 80; i += 2) { - cycles[i] = DhtExpectPulse(sensor, LOW); - cycles[i+1] = DhtExpectPulse(sensor, HIGH); - } - } - interrupts(); - if (error) { return false; } - - // Decode response - for (uint32_t i = 0; i < 40; ++i) { - int32_t lowCycles = cycles[2*i]; - int32_t highCycles = cycles[2*i+1]; - if ((-1 == lowCycles) || (-1 == highCycles)) { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_PULSE)); - return false; - } - dht_data[i/8] <<= 1; - if (highCycles > lowCycles) { - dht_data[i / 8] |= 1; - } - } - - // Check response - 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) { - dht_max_cycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for reading pulses from DHT sensor. - - 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 "(v2) " 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 \ No newline at end of file diff --git a/tasmota/xsns_06_dht_v3.ino b/tasmota/xsns_06_dht_v3.ino deleted file mode 100644 index 8b30cee7f..000000000 --- a/tasmota/xsns_06_dht_v3.ino +++ /dev/null @@ -1,304 +0,0 @@ -/* - 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_V3 -/*********************************************************************************************\ - * 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 diff --git a/tasmota/xsns_06_dht_v4.ino b/tasmota/xsns_06_dht_v4.ino deleted file mode 100644 index 488919554..000000000 --- a/tasmota/xsns_06_dht_v4.ino +++ /dev/null @@ -1,293 +0,0 @@ -/* - 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_V4 -/*********************************************************************************************\ - * 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 and stripped -\*********************************************************************************************/ - -#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(uint32_t sensor, uint32_t level) -{ - unsigned long timeout = micros() + 100; - while (digitalRead(Dht[sensor].pin) != level) { - if (micros() > timeout) { return false; } - delayMicroseconds(1); - } - return true; -} - -bool DhtRead(uint32_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: // DHT11 - delay(19); // minimum 18ms - break; - case GPIO_DHT22: // DHT21, DHT22, AM2301, AM2302, AM2321 - delay(2); // minimum 1ms - break; - case GPIO_SI7021: // iTead 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: // DHT11 - case GPIO_DHT22: // DHT21, DHT22, AM2301, AM2302, AM2321 - delayMicroseconds(50); - break; - case GPIO_SI7021: // iTead SI7021 - delayMicroseconds(20); // See: https://github.com/letscontrolit/ESPEasy/issues/1798 - break; - } - - uint32_t level = 9; - noInterrupts(); - for (uint32_t i = 0; i < 3; i++) { - level = i &1; - if (!DhtExpectPulse(sensor, level)) { break; } // Expect LOW, HIGH, LOW - level = 9; - } - if (9 == level) { - int data = 0; - for (uint32_t i = 0; i < 5; i++) { - data = 0; - for (uint32_t j = 0; j < 8; j++) { - level = 1; - if (!DhtExpectPulse(sensor, level)) { break; } // Expect HIGH - - delayMicroseconds(35); // Was 30 - if (digitalRead(Dht[sensor].pin)) { - data |= (1 << (7 - j)); - } - - level = 0; - if (!DhtExpectPulse(sensor, level)) { break; } // Expect LOW - level = 9; - } - if (level < 2) { break; } - - dht_data[i] = data; - } - } - interrupts(); - if (level < 2) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " %s " D_PULSE), (0 == level) ? D_START_SIGNAL_LOW : D_START_SIGNAL_HIGH); - 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(uint32_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); - if (Dht[sensor].h > 100) { Dht[sensor].h = 100.0; } - if (Dht[sensor].h < 0) { Dht[sensor].h = 0.0; } - 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 "(v4) " D_SENSORS_FOUND " %d"), dht_sensors); - } else { - dht_active = false; - } -} - -void DhtEverySecond(void) -{ - if (uptime &1) { - } 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 From 260345974763560e6db89a503cca03f9b1dc88d5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Mar 2020 13:32:20 +0100 Subject: [PATCH 6/7] Revert switchmode 6 according to issue 7778 Revert switchmode 6 according to issue 7778 (#7831) --- RELEASENOTES.md | 1 - tasmota/CHANGELOG.md | 2 +- tasmota/support_switch.ino | 14 +++++++++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e474c75ec..56c3a65b1 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -62,7 +62,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Change Zigbee command prefix from ``Zigbee*`` to ``Zb*`` - Change MQTT message size with additional 200 characters - Change display of some date and time messages from "Wed Feb 19 10:45:12 2020" to "2020-02-19T10:45:12" -- Change switchmode 6 according to issue 7778 (#7831) - 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) - Fix ``White`` added to light status (#7142) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 90f2a711a..cba4ec13b 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -4,7 +4,7 @@ - Change default my_user_config.h driver and sensor support removing most sensors and adding most drivers - Change IRremoteESP8266 library updated to v2.7.4 -- Change switchmode 6 according to issue 7778 (#7831) +- Revert switchmode 6 according to issue 7778 (#7831) - Add support for Jarolift rollers by Keeloq algorithm - Add Zigbee features and improvements and remove support for Zigbee commands starting with ``Zigbee...`` - Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders by Jon Little (#7814) diff --git a/tasmota/support_switch.ino b/tasmota/support_switch.ino index 49b9428b0..e873ea200 100644 --- a/tasmota/support_switch.ino +++ b/tasmota/support_switch.ino @@ -218,9 +218,20 @@ void SwitchHandler(uint8_t mode) } if ((NOT_PRESSED == button) && (PRESSED == Switch.last_state[i]) && (Switch.hold_timer[i])) { Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer... - switchflag = POWER_TOGGLE; // ...and Toggle + switchflag = POWER_TOGGLE; // ...and Toggle } break; + case PUSHBUTTONHOLD_INV: + if ((NOT_PRESSED == button) && (PRESSED == Switch.last_state[i])) { + Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press... + } + if ((PRESSED == button) && (NOT_PRESSED == Switch.last_state[i]) && (Switch.hold_timer[i])) { + Switch.hold_timer[i] = 0; // Button released and hold timer not expired : stop timer. + switchflag = POWER_TOGGLE; // ...and Toggle + } + break; +/* + // Reverted Fix switchmode 6 according to issue 7778 (#7831) case PUSHBUTTONHOLD_INV: if ((PRESSED == button) && (NOT_PRESSED == Switch.last_state[i])) { Switch.hold_timer[i] = loops_per_second * Settings.param[P_HOLD_TIME] / 10; // Start timer on button press... @@ -230,6 +241,7 @@ void SwitchHandler(uint8_t mode) Switch.hold_timer[i] = 0; // Button released : stop timer. } break; +*/ case TOGGLEMULTI: case FOLLOWMULTI: case FOLLOWMULTI_INV: From 2d4a6a29ebc7153dbe2717e3615574ac1c84ba1d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 8 Mar 2020 14:49:57 +0100 Subject: [PATCH 7/7] Fix Sonoff D1 driver (#7598) Fix Sonoff D1 driver (#7598) --- tasmota/xdrv_37_sonoff_d1.ino | 141 +++++++++++++--------------------- 1 file changed, 55 insertions(+), 86 deletions(-) diff --git a/tasmota/xdrv_37_sonoff_d1.ino b/tasmota/xdrv_37_sonoff_d1.ino index d00d58162..9ebc4b4f3 100644 --- a/tasmota/xdrv_37_sonoff_d1.ino +++ b/tasmota/xdrv_37_sonoff_d1.ino @@ -1,7 +1,7 @@ /* xdrv_37_sonoff_d1.ino - sonoff D1 dimmer support for Tasmota - Copyright (C) 2020 Theo Arends and robbz23 (protocol analysis) + 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 @@ -29,83 +29,43 @@ * 64 - Dimmer percentage (01 to 64 = 1 to 100%) * FF FF FF FF FF FF FF FF - Not used * 6C - CRC over bytes 2 to F (Addition) - * - * Based on Gravitate1: - * When I switch the light ON via the app, I get: - * AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C - * - * When I switch it OFF, I get: - * AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B - * - * When I set it to 1%, I get: - * AA 55 01 04 00 0A FF 01 FF FF FF FF FF FF FF FF 07 - * AB 55 FD F7 FF FF F5 01 FF FF FF FF FF FF FF FF 09 - * - * When I set it to 6%, I get: - * AA 55 01 04 00 0A FF 06 FF FF FF FF FF FF FF FF 0C - * AB 55 FD F7 FF FF F5 06 FF FF FF FF FF FF FF FF 0E - * - * When I set it to 100%, I get: - * AA 55 01 04 00 0A FF 64 FF FF FF FF FF FF FF FF 6A - * AB 55 FD F7 FF FF F5 64 FF FF FF FF FF FF FF FF 6C - * - * Based on robbz23: - * 00:17:59 CMD: Baudrate 9600 - * 00:17:59 SER: Set to 8N1 9600 bit/s - * 00:17:59 RSL: stat/tasmota_D9E56D/RESULT = {"Baudrate":9600} - * - * 00:25:32 CMD: SerialSend5 aa 55 01 04 00 0a 01 22 ffffffffffffffff 29 - * 00:25:32 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} - * - * 00:26:35 CMD: SerialSend5 aa 55 01 04 00 0a 01 22 ffffffffffffffff 2a - * 00:26:35 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} - * 00:26:35 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 00 05} - * - * 00:28:58 CMD: SerialSend5 aa 55 01 04 00 0a 01 01 ffffffffffffffff 09 - * 00:28:58 RSL: stat/tasmota_D9E56D/RESULT = {"SerialSend":"Done"} - * 00:28:58 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 00 05} - * - * 00:29:12 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 3C FF FF FF FF FF FF FF FF 44} - * 00:29:43 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 01 FF FF FF FF FF FF FF FF 09} - * 00:29:53 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C} - * - * 00:30:02 RSL: tele/tasmota_D9E56D/RESULT = {"SerialReceived":AA 55 01 04 00 0A FF 1E FF FF FF FF FF FF FF FF 24} \*********************************************************************************************/ #define XDRV_37 37 struct SONOFFD1 { - uint8_t receive_flag = 0; - uint8_t dimmer; + uint8_t receive_len = 0; + uint8_t power = 255; // Not initialized + uint8_t dimmer = 255; // Not initialized } SnfD1; /********************************************************************************************/ void SonoffD1Received(void) { - char svalue[32]; + if (serial_in_byte_counter < 8) { return; } // Received ack from Rf chip (aa 55 01 04 00 00 05) + + uint8_t action = serial_in_buffer[6] & 1; + if (action != SnfD1.power) { + SnfD1.power = action; + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SD1: Remote power (%d, %d)"), SnfD1.power, SnfD1.dimmer); + + ExecuteCommandPower(1, action, SRC_SWITCH); + } - uint8_t action = serial_in_buffer[6]; uint8_t dimmer = serial_in_buffer[7]; - - if (action < 2) { - // AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C - Power On, Dimmer 100% - // AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B - Power Off, Dimmer 100% - bool is_switch_change = (action != power); - if (is_switch_change) { - ExecuteCommandPower(1, action, SRC_SWITCH); - } - } - else if (0xFF == action) { + if (dimmer != SnfD1.dimmer) { SnfD1.dimmer = dimmer; - bool is_brightness_change = SnfD1.dimmer != Settings.light_dimmer; - if (power && (SnfD1.dimmer > 0) && is_brightness_change) { - char scmnd[20]; - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), SnfD1.dimmer); - ExecuteCommand(scmnd, SRC_SWITCH); - } + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SD1: Remote dimmer (%d, %d)"), SnfD1.power, SnfD1.dimmer); + + char scmnd[20]; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), SnfD1.dimmer); + ExecuteCommand(scmnd, SRC_SWITCH); } +/* // Send Acknowledge - Copy first 5 bytes, reset byte 6 and store crc in byte 7 // AA 55 01 04 00 00 05 serial_in_buffer[5] = 0; // Ack @@ -114,41 +74,38 @@ void SonoffD1Received(void) if ((i > 1) && (i < 6)) { serial_in_buffer[6] += serial_in_buffer[i]; } Serial.write(serial_in_buffer[i]); } +*/ } bool SonoffD1SerialInput(void) { - uint8_t packet_length = 0; - if (0xAA == serial_in_byte) { // 0xAA - Start of text serial_in_byte_counter = 0; - SnfD1.receive_flag = true; + SnfD1.receive_len = 7; } - if (SnfD1.receive_flag) { + if (SnfD1.receive_len) { serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (serial_in_byte_counter == 6) { - packet_length = 7 + serial_in_byte; // 8 or 17 + if (6 == serial_in_byte_counter) { + SnfD1.receive_len += serial_in_byte; // 8 or 17 } - if (serial_in_byte_counter == packet_length) { + if (serial_in_byte_counter == SnfD1.receive_len) { // Sonoff D1 codes - // AA 55 01 04 00 0A 01 64 FF FF FF FF FF FF FF FF 6C - Power On, Dimmer 100% - // AA 55 01 04 00 0A 00 64 FF FF FF FF FF FF FF FF 6B - Power Off, Dimmer 100% - // AA 55 01 04 00 0A FF 01 FF FF FF FF FF FF FF FF 07 - Power ignore, Dimmer 1% - // AB 55 FD F7 FF FF F5 01 FF FF FF FF FF FF FF FF 09 - Response 2 - // AA 55 01 04 00 0A FF 06 FF FF FF FF FF FF FF FF 0C - Power ignore, Dimmer 6% - // AB 55 FD F7 FF FF F5 06 FF FF FF FF FF FF FF FF 0E - Response 2 - // AA 55 01 04 00 0A FF 64 FF FF FF FF FF FF FF FF 6A - Power ignore, Dimmer 100% - // AB 55 FD F7 FF FF F5 64 FF FF FF FF FF FF FF FF 6C - Response 2 + // aa 55 01 04 00 0a 01 01 ff ff ff ff ff ff ff ff 09 - Power On, Dimmer 1% + // aa 55 01 04 00 0a 01 28 ff ff ff ff ff ff ff ff 30 - Power On, Dimmer 40% + // aa 55 01 04 00 0a 01 3c ff ff ff ff ff ff ff ff 44 - Power On, Dimmer 60% + // aa 55 01 04 00 0a 01 64 ff ff ff ff ff ff ff ff 6c - Power On, Dimmer 100% + // aa 55 01 04 00 0a 00 64 ff ff ff ff ff ff ff ff 6b - Power Off (with last dimmer 100%) + // aa 55 01 04 00 0a 01 64 ff ff ff ff ff ff ff ff 6c - Power On (with last dimmer 100%) AddLogSerial(LOG_LEVEL_DEBUG); uint8_t crc = 0; - for (uint32_t i = 2; i < packet_length -1; i++) { + for (uint32_t i = 2; i < SnfD1.receive_len -1; i++) { crc += serial_in_buffer[i]; } - if (crc == serial_in_buffer[packet_length -1]) { + if (crc == serial_in_buffer[SnfD1.receive_len -1]) { SonoffD1Received(); - SnfD1.receive_flag = false; + SnfD1.receive_len = 0; return true; } } @@ -159,13 +116,13 @@ bool SonoffD1SerialInput(void) /********************************************************************************************/ -void SonoffD1Send(uint8_t lpower, uint8_t dimmer) +void SonoffD1Send() { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 uint8_t buffer[17] = { 0xAA,0x55,0x01,0x04,0x00,0x0A,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00 }; - buffer[6] = lpower; - buffer[7] = dimmer; + buffer[6] = SnfD1.power; + buffer[7] = SnfD1.dimmer; for (uint32_t i = 0; i < sizeof(buffer); i++) { if ((i > 1) && (i < sizeof(buffer) -1)) { buffer[16] += buffer[i]; } @@ -175,17 +132,29 @@ void SonoffD1Send(uint8_t lpower, uint8_t dimmer) bool SonoffD1SendPower(void) { - SonoffD1Send(XdrvMailbox.index &1, 0xFF); + uint8_t action = XdrvMailbox.index &1; + if (action != SnfD1.power) { + SnfD1.power = action; + +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SD1: Tasmota power (%d, %d)"), SnfD1.power, SnfD1.dimmer); + + SonoffD1Send(); + } return true; } bool SonoffD1SendDimmer(void) { - uint8_t dimmer = changeUIntScale(((uint16_t *)XdrvMailbox.data)[0], 0, 255, 0, 100); + uint8_t dimmer = LightGetDimmer(1); dimmer = (dimmer < Settings.dimmer_hw_min) ? Settings.dimmer_hw_min : dimmer; dimmer = (dimmer > Settings.dimmer_hw_max) ? Settings.dimmer_hw_max : dimmer; + if (dimmer != SnfD1.dimmer) { + SnfD1.dimmer = dimmer; - SonoffD1Send(0xFF, dimmer); +// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SD1: Tasmota dimmer (%d, %d)"), SnfD1.power, SnfD1.dimmer); + + SonoffD1Send(); + } return true; }