diff --git a/tasmota/xsns_62_MI_HM10.ino b/tasmota/xsns_62_MI_HM10.ino index 17cc094ad..83252c4f6 100644 --- a/tasmota/xsns_62_MI_HM10.ino +++ b/tasmota/xsns_62_MI_HM10.ino @@ -20,7 +20,9 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- - + 0.9.2.0 20200317 added - MiBeacon-support, add Flora, MJ_HT_V1 and CGD1, add dew point, + add AUTO(-scan), RULES-message + --- 0.9.1.0 20200209 added - LYWSD02-support, including setting the time --- 0.9.0.0 20200130 started - initial development by Christian Baars (support LYWSD03 only) @@ -40,8 +42,7 @@ TasmotaSerial *HM10Serial; #define HM10_MAX_TASK_NUMBER 12 uint8_t HM10_TASK_LIST[HM10_MAX_TASK_NUMBER+1][2]; // first value: kind of task - second value: delay in x * 100ms -#define HM10_MAX_RX_BUF 512 -char HM10_RX_STRING[HM10_MAX_RX_BUF] = {0}; +#define HM10_MAX_RX_BUF 160 struct { uint8_t current_task_delay; // number of 100ms-cycles @@ -53,13 +54,14 @@ struct { uint32_t time; uint8_t timebuf[4]; }; + uint16_t autoScanInterval; struct { + uint32_t awaiting:8; uint32_t init:1; uint32_t pending_task:1; uint32_t connected:1; uint32_t subscribed:1; - uint32_t awaitingHT:1; - uint32_t awaitingB:1; + uint32_t autoScan:1; // TODO: more to come } mode; struct { @@ -68,15 +70,52 @@ struct { } state; } HM10; -#pragma pack(1) +#pragma pack(1) // byte-aligned structures to read the sensor data struct { uint16_t temp; uint8_t hum; } LYWSD0x_HT; + +struct { + uint8_t spare; + uint16_t temp; + uint16_t hum; +} CGD1_HT; + +struct { + uint16_t temp; + uint8_t spare; + uint32_t lux; + uint8_t moist; + uint16_t fert; +} Flora_TLMF; // temeprature, lux, moisture, fertility + +struct mi_beacon_t{ + uint16_t frame; + uint16_t productID; + uint8_t counter; + uint8_t Mac[6]; + uint8_t spare; + uint8_t type; + uint8_t ten; + uint8_t size; + union { + struct{ //0d + uint16_t temp; + uint16_t hum; + }HT; + uint8_t bat; //0a + uint16_t temp; //04 + uint16_t hum; //06 + uint32_t lux; //07 + uint8_t moist; //08 + uint16_t fert; //09 + }; +}; #pragma pack(0) struct mi_sensor_t{ - uint8_t type; //Flora = 1; MI-HT_V1=2; LYWSD02=3; LYWSD03=4 + uint8_t type; //Flora = 1; MI-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 @@ -84,13 +123,13 @@ struct mi_sensor_t{ struct { float moisture; float fertility; - uint16_t lux; + uint32_t lux; }; // Flora struct { float hum; - uint8_t bat; }; // MJ_HT_V1, LYWSD0x }; + uint8_t bat; }; std::vector MIBLEsensors; @@ -103,24 +142,30 @@ std::vector MIBLEsensors; const char S_JSON_HM10_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_HM10 "%s\":%d}"; const char S_JSON_HM10_COMMAND[] PROGMEM = "{\"" D_CMND_HM10 "%s%s\"}"; -const char kHM10_Commands[] PROGMEM = "Scan|AT|Period|Baud|Time"; +const char kHM10_Commands[] PROGMEM = "Scan|AT|Period|Baud|Time|Auto"; #define FLORA 1 #define MJ_HT_V1 2 #define LYWSD02 3 #define LYWSD03MMC 4 +#define CGG1 5 +#define CGD1 6 -uint8_t kHM10SlaveID[4][3] = { 0xC4,0x7C,0x8D, // Flora - 0x58,0x2D,0x34, // MJ_HT_V1 - 0xE7,0x2E,0x00, // LYWSD02 - 0xA4,0xC1,0x38, // LYWSD03 - }; +const uint16_t kHM10SlaveID[6]={ 0x0098, // Flora + 0x01aa, // MJ_HT_V1 + 0x045b, // LYWSD02 + 0x055b, // LYWSD03 + 0x0347, // CGG1 + 0x0576 // CGD1 + }; const char kHM10SlaveType1[] PROGMEM = "Flora"; const char kHM10SlaveType2[] PROGMEM = "MJ_HT_V1"; const char kHM10SlaveType3[] PROGMEM = "LYWSD02"; const char kHM10SlaveType4[] PROGMEM = "LYWSD03"; -const char * kHM10SlaveType[] PROGMEM = {kHM10SlaveType1,kHM10SlaveType2,kHM10SlaveType3,kHM10SlaveType4}; +const char kHM10SlaveType5[] PROGMEM = "CGG1"; +const char kHM10SlaveType6[] PROGMEM = "CGD1"; +const char * kHM10SlaveType[] PROGMEM = {kHM10SlaveType1,kHM10SlaveType2,kHM10SlaveType3,kHM10SlaveType4,kHM10SlaveType5,kHM10SlaveType6}; /*********************************************************************************************\ * enumerations @@ -131,9 +176,19 @@ enum HM10_Commands { // commands useable in console or rules CMND_HM10_AT, // send AT-command for debugging and special configuration CMND_HM10_PERIOD, // set period like TELE-period in seconds between read-cycles CMND_HM10_BAUD, // serial speed of ESP8266 (<-> HM10), does not change baud rate of HM10 - CMND_HM10_TIME // set LYWSD02-Time from ESP8266-time + CMND_HM10_TIME, // set LYWSD02-Time from ESP8266-time + CMND_HM10_AUTO // do discovery scans permanently to receive MiBeacons in seconds between read-cycles }; +enum HM10_awaitData: uint8_t { + none = 0, + tempHumLY = 1, + TLMF = 2, + bat = 3, + tempHumCGD1 = 4, + discScan = 5 + }; + /*********************************************************************************************\ * Task codes defines \*********************************************************************************************/ @@ -143,7 +198,7 @@ enum HM10_Commands { // commands useable in console or rules #define TASK_HM10_IMME1 2 // change imme to 1 #define TASK_HM10_RENEW 3 // device factory setting #define TASK_HM10_RESET 4 // device reset -#define TASK_HM10_DISC 5 // device discovery scan +#define TASK_HM10_DISC 5 // device discovery scan: AT+DISA? #define TASK_HM10_CONN 6 // connect to given MAC #define TASK_HM10_VERSION 7 // query FW version #define TASK_HM10_NAME 8 // query device name @@ -151,14 +206,23 @@ enum HM10_Commands { // commands useable in console or rules #define TASK_HM10_DISCONN 10 // disconnect #define TASK_HM10_SUB_L3 11 // subscribe to service handle 37 #define TASK_HM10_READ_HT 12 // read from handle 36 -> Hum & Temp -#define TASK_HM10_FINDALLCHARS 13 // read all available characteristics -#define TASK_HM10_UN_L3 14 // subscribe service handle 37 -#define TASK_HM10_DELAY_SUB 15 // start reading from subscription delayed +#define TASK_HM10_SCAN9 13 // longest discovery scan possible +#define TASK_HM10_UN_L3 14 // unsubscribe service handle 37 +#define TASK_HM10_DELAY_SUB_LY 15 // start reading from subscription delayed #define TASK_HM10_READ_BT_L3 16 // read from handle 3A -> Battery #define TASK_HM10_SUB_L2 17 // subscribe to service handle 3C -#define TASK_HM10_UN_L2 18 // subscribe service handle 3C +#define TASK_HM10_UN_L2 18 // unsubscribe service handle 3C #define TASK_HM10_READ_BT_L2 19 // read from handle 43 -> Battery #define TASK_HM10_TIME_L2 20 // set time of LYWSD02 to system time +#define TASK_HM10_SHOW0 21 // set verbositiy to minimum +#define TASK_HM10_READ_BF_FL 22 // read battery and firmware from flower care +#define TASK_HM10_CALL_TLMF_FL 23 // write 0xa01f to handle 0x33 to init sensor readings +#define TASK_HM10_READ_TLMF_FL 24 // read temp,lux,moist and fert from flower care +#define TASK_HM10_SUB_HT_CGD1 25 // subscribe to service handle 4b +#define TASK_HM10_UN_HT_CGD1 26 // unsubscribe service handle 4b +#define TASK_HM10_READ_B_CGD1 27 // read service handle 11 +#define TASK_HM10_DELAY_SUB_CGD1 28 // start reading from subscription delayed +#define TASK_HM10_STATUS_EVENT 29 // process status for RULES #define TASK_HM10_DONE 99 // used, if there was a task in the slot or just to wait @@ -178,6 +242,14 @@ void HM10_TaskReplaceInSlot(uint8_t task, uint8_t slot){ HM10_TASK_LIST[slot][0] = task; } +void HM10_ReverseMAC(uint8_t _mac[]){ + uint8_t _reversedMAC[6]; + for (uint8_t i=0; i<6; i++){ + _reversedMAC[5-i] = _mac[i]; + } + memcpy(_mac,_reversedMAC, sizeof(_reversedMAC)); +} + /*********************************************************************************************\ * chained tasks \*********************************************************************************************/ @@ -187,12 +259,15 @@ void HM10_Reset(void) { HM10_Launchtask(TASK_HM10_DISCONN,0,1); // disco HM10_Launchtask(TASK_HM10_IMME1,2,1); // set imme to 1 HM10_Launchtask(TASK_HM10_RESET,3,1); // reset Device HM10_Launchtask(TASK_HM10_VERSION,4,10); // read SW Version - HM10_Launchtask(TASK_HM10_DISC,5,50); // discovery + HM10_Launchtask(TASK_HM10_SCAN9,5,2); // scan time 9 seconds + HM10_Launchtask(TASK_HM10_DISC,6,2); // discovery + HM10_Launchtask(TASK_HM10_STATUS_EVENT,7,2); // status } void HM10_Discovery_Scan(void) { HM10_Launchtask(TASK_HM10_DISCONN,0,1); // disconnect - HM10_Launchtask(TASK_HM10_DISC,1,1); // discovery + HM10_Launchtask(TASK_HM10_DISC,1,5); // discovery + HM10_Launchtask(TASK_HM10_STATUS_EVENT,2,2); // status } void HM10_Read_LYWSD03(void) { @@ -221,66 +296,84 @@ void HM10_Time_LYWSD02(void) { HM10_Launchtask(TASK_HM10_DISCONN,4,5); // disconnect } +void HM10_Read_Flora(void) { + HM10_Launchtask(TASK_HM10_DISCONN,0,0); // disconnect + HM10_Launchtask(TASK_HM10_CONN,1,1); // connect + HM10_Launchtask(TASK_HM10_FEEDBACK,2,5); // get OK+CONN + HM10_Launchtask(TASK_HM10_READ_BF_FL,3,20); // read battery + HM10_Launchtask(TASK_HM10_CALL_TLMF_FL,4,30); // read TLMF + HM10_Launchtask(TASK_HM10_DISCONN,5,10); // disconnect + } + +void HM10_Read_CGD1(void) { + HM10_Launchtask(TASK_HM10_CONN,0,1); // connect + HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); // get OK+CONN + HM10_Launchtask(TASK_HM10_SUB_HT_CGD1,2,20); // subscribe + HM10_Launchtask(TASK_HM10_UN_HT_CGD1,3,10); // unsubscribe + HM10_Launchtask(TASK_HM10_READ_B_CGD1,4,5); // read Battery + HM10_Launchtask(TASK_HM10_DISCONN,5,5); // disconnect + } + /** * @brief Return the slot number of a known sensor or return create new sensor slot * * @param _serial BLE address of the sensor - * @param _type Type number of the sensor, 0xff for Auto-type + * @param _type Type number of the sensor * @return uint32_t Known or new slot in the sensors-vector */ -uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint8_t _type){ - if(_type==0xff){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: will test MAC-type")); - for (uint32_t i=0;i<4;i++){ - if(memcmp(_serial,kHM10SlaveID+i,3)==0){ - DEBUG_SENSOR_LOG(PSTR("MIBLE: MAC is type %u"), i); - _type = i+1; - } - else { - DEBUG_SENSOR_LOG(PSTR("MIBLE: MAC-type is unknown")); - } +uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint16_t _type){ + + DEBUG_SENSOR_LOG(PSTR("%s: will test ID-type: %x"),D_CMND_HM10, _type); + bool _success = false; + for (uint32_t i=0;i<6;i++){ // i < sizeof(kHM10SlaveID) gives compiler warning + if(_type == kHM10SlaveID[i]){ + DEBUG_SENSOR_LOG(PSTR("HM10: ID is type %u"), i); + _type = i+1; + _success = true; + } + else { + DEBUG_SENSOR_LOG(PSTR("%s: ID-type is not: %x"),D_CMND_HM10,kHM10SlaveID[i]); } } - if(_type==0xff) return _type; // error - - DEBUG_SENSOR_LOG(PSTR("MIBLE: vector size %u"), MIBLEsensors.size()); + if(!_success) return 0xff; + + DEBUG_SENSOR_LOG(PSTR("%s: vector size %u"),D_CMND_HM10, MIBLEsensors.size()); for(uint32_t i=0; ihardwareSerial()) { ClaimSerial(); - DEBUG_SENSOR_LOG(PSTR("HM10: claim HW")); + DEBUG_SENSOR_LOG(PSTR("%s: claim HW"),D_CMND_HM10); } HM10_Reset(); HM10.mode.pending_task = 1; @@ -305,68 +398,147 @@ void HM10SerialInit(void) { return; } -/** - * @brief convert Mac-String to byte array - * - * @param string Hex-string, must contain 12 chars (no error checking) - * @param _mac Must be a uint8_t[6], filled with zeros - */ - -void HM10MACStringToBytes(const char* string, uint8_t _mac[]) { - uint32_t index = 0; - while (index < 12) { - char c = string[index]; - uint32_t value = 0; - if(c >= '0' && c <= '9') - value = (c - '0'); - else if (c >= 'A' && c <= 'F') - value = (10 + (c - 'A')); - _mac[(index/2)] += value << (((index + 1) % 2) * 4); - // DEBUG_SENSOR_LOG(PSTR("HM10: Char: %c, Value: %x, Index/2: %u, valueadded: %x, MAC-index: %x"), c, value,(index/2),value << (((index + 1) % 2) * 4), _mac[index/2]); - index++; - } - DEBUG_SENSOR_LOG(PSTR("HM10: MAC-array: %x%x%x%x%x%x"),_mac[0],_mac[1],_mac[2],_mac[3],_mac[4],_mac[5]); -} - - /*********************************************************************************************\ * parse the response \*********************************************************************************************/ -void HM10ParseResponse(char *buf) { +void HM10parseMiBeacon(char * _buf, uint32_t _slot){ + float _tempFloat; + mi_beacon_t _beacon; + if (MIBLEsensors.at(_slot).type==2){ + memcpy((uint8_t*)&_beacon+1,(uint8_t*)_buf, sizeof(_beacon)); // shift by one byte for the MJ_HT_V1 + memcpy((uint8_t*)&_beacon.Mac,(uint8_t*)&_beacon.Mac+1,6); // but shift back the MAC + } + else{ + memcpy((void*)&_beacon,(void*)_buf, sizeof(_beacon)); + } + HM10_ReverseMAC(_beacon.Mac); + if(memcmp(_beacon.Mac,MIBLEsensors.at(_slot).serial,sizeof(_beacon.Mac))!=0){ + if (MIBLEsensors.at(_slot).showedUp>3) return; // probably false alarm from a damaged packet + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: remove garbage sensor"),D_CMND_HM10); + DEBUG_SENSOR_LOG(PSTR("%s i: %x %x %x %x %x %x"),D_CMND_HM10, MIBLEsensors.at(_slot).serial[5], MIBLEsensors.at(_slot).serial[4],MIBLEsensors.at(_slot).serial[3],MIBLEsensors.at(_slot).serial[2],MIBLEsensors.at(_slot).serial[1],MIBLEsensors.at(_slot).serial[0]); + DEBUG_SENSOR_LOG(PSTR("%s n: %x %x %x %x %x %x"),D_CMND_HM10, _beacon.Mac[5], _beacon.Mac[4], _beacon.Mac[3],_beacon.Mac[2],_beacon.Mac[1],_beacon.Mac[0]); + MIBLEsensors.erase(MIBLEsensors.begin()+_slot); + return; + } + if (MIBLEsensors.at(_slot).showedUp<4) MIBLEsensors.at(_slot).showedUp++; + + DEBUG_SENSOR_LOG(PSTR("MiBeacon type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[0],(uint8_t)_buf[1],(uint8_t)_buf[2],(uint8_t)_buf[3],(uint8_t)_buf[4],(uint8_t)_buf[5],(uint8_t)_buf[6],(uint8_t)_buf[7]); + DEBUG_SENSOR_LOG(PSTR(" type:%02x: %02x %02x %02x %02x %02x %02x %02x %02x"),_beacon.type, (uint8_t)_buf[8],(uint8_t)_buf[9],(uint8_t)_buf[10],(uint8_t)_buf[11],(uint8_t)_buf[12],(uint8_t)_buf[13],(uint8_t)_buf[14],(uint8_t)_buf[15]); + + if(MIBLEsensors.at(_slot).type==4 || MIBLEsensors.at(_slot).type==6){ + DEBUG_SENSOR_LOG(PSTR("LYWSD03 and CGD1 no support for MiBeacon, type %u"),MIBLEsensors.at(_slot).type); + return; + } + DEBUG_SENSOR_LOG(PSTR("%s at slot %u"), kHM10SlaveType[MIBLEsensors.at(_slot).type-1],_slot); + switch(_beacon.type){ + case 0x04: + _tempFloat=(float)(_beacon.temp)/10.0f; + if(_tempFloat<60){ + MIBLEsensors.at(_slot).temp=_tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode 4: temp updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode 4: U16: %u Temp"), _beacon.temp ); + break; + case 0x06: + _tempFloat=(float)(_beacon.hum)/10.0f; + if(_tempFloat<101){ + MIBLEsensors.at(_slot).hum=_tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode 6: hum updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode 6: U16: %u Hum"), _beacon.hum); + break; + case 0x07: + MIBLEsensors.at(_slot).lux=_beacon.lux & 0x00ffffff; + DEBUG_SENSOR_LOG(PSTR("Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff); + break; + case 0x08: + _tempFloat =(float)_beacon.moist; + if(_tempFloat<100){ + MIBLEsensors.at(_slot).moisture=_tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode 8: moisture updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode 8: U8: %u Moisture"), _beacon.moist); + break; + case 0x09: + _tempFloat=(float)(_beacon.fert); + if(_tempFloat<65535){ // ??? + MIBLEsensors.at(_slot).fertility=_tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode 9: fertility updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode 9: U16: %u Fertility"), _beacon.fert); + break; + case 0x0a: + if(_beacon.bat<101){ + MIBLEsensors.at(_slot).bat = _beacon.bat; + DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode a: U8: %u %%"), _beacon.bat); + break; + case 0x0d: + _tempFloat=(float)(_beacon.HT.temp)/10.0f; + if(_tempFloat<60){ + MIBLEsensors.at(_slot).temp = _tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode d: temp updated")); + } + _tempFloat=(float)(_beacon.HT.hum)/10.0f; + if(_tempFloat<100){ + MIBLEsensors.at(_slot).hum = _tempFloat; + DEBUG_SENSOR_LOG(PSTR("Mode d: hum updated")); + } + DEBUG_SENSOR_LOG(PSTR("Mode d: U16: %x Temp U16: %x Hum"), _beacon.HT.temp, _beacon.HT.hum); + break; + } +} + +void HM10ParseResponse(char *buf, uint16_t bufsize) { if (!strncmp(buf,"OK",2)) { - DEBUG_SENSOR_LOG(PSTR("HM10: got OK")); + DEBUG_SENSOR_LOG(PSTR("%s: got OK"),D_CMND_HM10); } if (!strncmp(buf,"HMSoft",6)) { //8 const char* _fw = "000"; memcpy((void *)_fw,(void *)(buf+8),3); HM10.firmware = atoi(_fw); - DEBUG_SENSOR_LOG(PSTR("HM10: Firmware: %d"), HM10.firmware); + DEBUG_SENSOR_LOG(PSTR("%s: Firmware: %d"),D_CMND_HM10, HM10.firmware); return; } - char * _pos = strstr(buf, "IS0:"); + char * _pos = strstr(buf, "ISA:"); if(_pos) { - const char* _mac = "000000000000"; - memcpy((void *)_mac,(void *)(_pos+4),12); - DEBUG_SENSOR_LOG(PSTR("HM10: found Mac: %s"), _mac); uint8_t _newMacArray[6] = {0}; - HM10MACStringToBytes(_mac, _newMacArray); - DEBUG_SENSOR_LOG(PSTR("HM10: MAC-array: %x%x%x%x%x%x"),_newMacArray[0],_newMacArray[1],_newMacArray[2],_newMacArray[3],_newMacArray[4],_newMacArray[5]); - MIBLEgetSensorSlot(_newMacArray, 0xff); + memcpy((void *)_newMacArray,(void *)(_pos+4),6); + HM10_ReverseMAC(_newMacArray); + DEBUG_SENSOR_LOG(PSTR("%s: MAC-array: %02x%02x%02x%02x%02x%02x"),D_CMND_HM10,_newMacArray[0],_newMacArray[1],_newMacArray[2],_newMacArray[3],_newMacArray[4],_newMacArray[5]); + uint16_t _type=0xffff; + + for (uint32_t idx =10;idxavailable()) { // delay(0); if(iwrite("AT+ROLE1"); break; case TASK_HM10_IMME1: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s set imme to 1"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: set imme to 1"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+IMME1"); break; case TASK_HM10_DISC: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start discovery"),D_CMND_HM10); - HM10.current_task_delay = 35; // set task delay + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: start discovery"),D_CMND_HM10); + HM10.current_task_delay = 100; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; - HM10Serial->write("AT+DISC?"); + HM10.mode.awaiting = discScan; + HM10Serial->write("AT+DISA?"); break; case TASK_HM10_VERSION: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read version"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read version"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+VERR?"); break; case TASK_HM10_NAME: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read name"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read name"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+NAME?"); break; case TASK_HM10_CONN: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s connect"),D_CMND_HM10); + char _con[20]; + sprintf_P(_con,"AT+CON%02x%02x%02x%02x%02x%02x",MIBLEsensors.at(HM10.state.sensor).serial[0],MIBLEsensors.at(HM10.state.sensor).serial[1],MIBLEsensors.at(HM10.state.sensor).serial[2],MIBLEsensors.at(HM10.state.sensor).serial[3],MIBLEsensors.at(HM10.state.sensor).serial[4],MIBLEsensors.at(HM10.state.sensor).serial[5]); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: connect %s"),D_CMND_HM10, _con); HM10.current_task_delay = 2; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; - char _con[20]; - sprintf_P(_con,"AT+CON%02x%02x%02x%02x%02x%02x",MIBLEsensors.at(HM10.state.sensor).serial[0],MIBLEsensors.at(HM10.state.sensor).serial[1],MIBLEsensors.at(HM10.state.sensor).serial[2],MIBLEsensors.at(HM10.state.sensor).serial[3],MIBLEsensors.at(HM10.state.sensor).serial[4],MIBLEsensors.at(HM10.state.sensor).serial[5]); HM10Serial->write(_con); - HM10.mode.awaitingB = false; + HM10.mode.awaiting = none; HM10.mode.connected = true; break; case TASK_HM10_DISCONN: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s disconnect"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: disconnect"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT"); break; case TASK_HM10_RESET: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s Reset Device"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: Reset Device"),D_CMND_HM10); HM10Serial->write("AT+RESET"); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; break; case TASK_HM10_SUB_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s subscribe"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe"),D_CMND_HM10); HM10.current_task_delay = 25; // set task delay - HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB,i); + HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB_LY,i); runningTaskLoop = false; HM10Serial->write("AT+NOTIFY_ON0037"); break; case TASK_HM10_UN_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s un-subscribe"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; - HM10.mode.awaitingHT = false; + HM10.mode.awaiting = none; HM10Serial->write("AT+NOTIFYOFF0037"); break; case TASK_HM10_SUB_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s subscribe"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe"),D_CMND_HM10); HM10.current_task_delay = 25; // set task delay - HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB,i); + HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB_LY,i); runningTaskLoop = false; HM10Serial->write("AT+NOTIFY_ON003C"); break; case TASK_HM10_UN_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s un-subscribe"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; - HM10.mode.awaitingHT = false; + HM10.mode.awaiting = none; HM10Serial->write("AT+NOTIFYOFF003C"); break; case TASK_HM10_TIME_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s set time"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: set time"),D_CMND_HM10); HM10.current_task_delay = 5; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; @@ -550,49 +795,114 @@ void HM10_TaskEvery100ms(){ AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s Time-string: %x%x%x%x%x"),D_CMND_HM10, HM10.timebuf[0],HM10.timebuf[1],HM10.timebuf[2],HM10.timebuf[3],(Rtc.time_timezone /60)); break; case TASK_HM10_READ_HT: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 0036"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0036"),D_CMND_HM10); HM10.current_task_delay = 0; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+READDATA0036?"); - HM10.mode.awaitingHT = true; + HM10.mode.awaiting = tempHumLY; break; case TASK_HM10_READ_BT_L3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 003A"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 003A"),D_CMND_HM10); HM10.current_task_delay = 2; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+READDATA003A?"); - HM10.mode.awaitingB = true; + HM10.mode.awaiting = bat; break; case TASK_HM10_READ_BT_L2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 0043"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0043"),D_CMND_HM10); HM10.current_task_delay = 2; // set task delay HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); runningTaskLoop = false; HM10Serial->write("AT+READDATA0043?"); - HM10.mode.awaitingB = true; + HM10.mode.awaiting = bat; + break; + case TASK_HM10_READ_BF_FL: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0038"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA0038?"); + HM10.mode.awaiting = bat; + break; + case TASK_HM10_CALL_TLMF_FL: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: write to handle 0033"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_READ_TLMF_FL,i); + runningTaskLoop = false; + HM10Serial->write("AT+SEND_DATAWR0033"); + HM10Serial->write(0xa0); + HM10Serial->write(0x1f); + HM10.mode.awaiting = none; + break; + case TASK_HM10_READ_TLMF_FL: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0035"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA0035?"); + HM10.mode.awaiting = TLMF; + break; + case TASK_HM10_READ_B_CGD1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: read handle 0011"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA0011?"); + HM10.mode.awaiting = bat; + break; + case TASK_HM10_SUB_HT_CGD1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: subscribe 4b"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB_CGD1,i); + runningTaskLoop = false; + HM10.mode.awaiting = none; + HM10Serial->write("AT+NOTIFY_ON004b"); + break; + case TASK_HM10_UN_HT_CGD1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: un-subscribe 4b"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10.mode.awaiting = none; + HM10Serial->write("AT+NOTIFYOFF004b"); + break; + case TASK_HM10_SCAN9: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: scan time to 9"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+SCAN9"); break; - // case TASK_HM10_FINDALLCHARS: - // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s find all chars"),D_CMND_HM10); - // HM10.current_task_delay = 5; // set task delay - // HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); - // runningTaskLoop = false; - // HM10Serial->write("AT+FINDALLCHARS?"); - // break; case TASK_HM10_FEEDBACK: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s get response"),D_CMND_HM10); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: get response"),D_CMND_HM10); HM10SerialHandleFeedback(); HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset runningTaskLoop = false; break; - case TASK_HM10_DELAY_SUB: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start reading"),D_CMND_HM10); + case TASK_HM10_DELAY_SUB_LY: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: start reading"),D_CMND_HM10); HM10SerialHandleFeedback(); HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset - HM10.mode.awaitingHT = true; + HM10.mode.awaiting = tempHumLY; + runningTaskLoop = false; + break; + case TASK_HM10_DELAY_SUB_CGD1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: start reading"),D_CMND_HM10); + HM10SerialHandleFeedback(); + HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay + HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset + HM10.mode.awaiting = tempHumCGD1; + runningTaskLoop = false; + break; + case TASK_HM10_STATUS_EVENT: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s: show status"),D_CMND_HM10); + HM10StatusInfo(); + HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay + HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset runningTaskLoop = false; break; case TASK_HM10_DONE: // this entry was already handled @@ -619,39 +929,74 @@ void HM10_TaskEvery100ms(){ } } +void HM10StatusInfo(){ + char stemp[20]; + snprintf_P(stemp, sizeof(stemp),PSTR("{%s:{\"found\": %u}}"),D_CMND_HM10, MIBLEsensors.size()); + AddLog_P2(LOG_LEVEL_INFO, stemp); + RulesProcessEvent(stemp); +} + /** * @brief Main loop of the driver, "high level"-loop * */ void HM10EverySecond(){ - if(HM10.firmware == 0) return; - if(HM10.mode.pending_task == 1) return; - if (MIBLEsensors.size()==0) return; - static uint32_t _counter = 0; static uint32_t _nextSensorSlot = 0; + static uint32_t _lastDiscovery = 0; + + if(HM10.firmware == 0) return; + if(HM10.mode.pending_task == 1) return; + if(MIBLEsensors.size()==0 && !HM10.mode.autoScan) return; + + if((HM10.period-_counter)>15 && HM10.mode.autoScan) { + if(_counter-_lastDiscovery>HM10.autoScanInterval){ + HM10_Discovery_Scan(); + HM10.mode.pending_task = 1; + _counter+=12; + _lastDiscovery = _counter; + return; + } + } + if(_counter==0) { HM10.state.sensor = _nextSensorSlot; _nextSensorSlot++; - if(MIBLEsensors.at(HM10.state.sensor).type==LYWSD03MMC) { - HM10.mode.pending_task = 1; - HM10_Read_LYWSD03(); - } - if(MIBLEsensors.at(HM10.state.sensor).type==LYWSD02) { - HM10.mode.pending_task = 1; - HM10_Read_LYWSD02(); + HM10.mode.pending_task = 1; + switch(MIBLEsensors.at(HM10.state.sensor).type){ + case LYWSD03MMC: + HM10_Read_LYWSD03(); + break; + case LYWSD02: + HM10_Read_LYWSD02(); + break; + case FLORA: + HM10_Read_Flora(); + break; + case CGD1: + HM10_Read_CGD1(); + break; + default: + HM10.mode.pending_task = 0; } if (HM10.state.sensor==MIBLEsensors.size()-1) { _nextSensorSlot= 0; _counter++; } - DEBUG_SENSOR_LOG(PSTR("%s active sensor now: %u"),D_CMND_HM10, HM10.state.sensor); + DEBUG_SENSOR_LOG(PSTR("%s: active sensor now: %u"),D_CMND_HM10, HM10.state.sensor); } else _counter++; - if (_counter>HM10.period) _counter = 0; + if (_counter>HM10.period) { + _counter = 0; + _lastDiscovery = 0; + } } +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + bool HM10Cmd(void) { char command[CMDSZ]; bool serviced = true; @@ -662,22 +1007,36 @@ bool HM10Cmd(void) { switch (command_code) { case CMND_HM10_PERIOD: if (XdrvMailbox.data_len > 0) { - if (command_code == CMND_HM10_PERIOD) { HM10.period = XdrvMailbox.payload; } + HM10.period = XdrvMailbox.payload; } else { - if (command_code == CMND_HM10_PERIOD) XdrvMailbox.payload = HM10.period; + XdrvMailbox.payload = HM10.period; + } + Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); + break; + case CMND_HM10_AUTO: + if (XdrvMailbox.data_len > 0) { + if (XdrvMailbox.payload>0) { + HM10.mode.autoScan = 1; + HM10.autoScanInterval = XdrvMailbox.payload; + } + else { + HM10.mode.autoScan = 0; + HM10.autoScanInterval = 0; + } + } + else { + XdrvMailbox.payload = HM10.autoScanInterval; } Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); break; case CMND_HM10_BAUD: if (XdrvMailbox.data_len > 0) { - if (command_code == CMND_HM10_BAUD) { HM10.serialSpeed = XdrvMailbox.payload; HM10Serial->begin(HM10.serialSpeed); - } } else { - if (command_code == CMND_HM10_BAUD) XdrvMailbox.payload = HM10.serialSpeed; + XdrvMailbox.payload = HM10.serialSpeed; } Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); break; @@ -702,13 +1061,13 @@ bool HM10Cmd(void) { else Response_P(S_JSON_HM10_COMMAND, ":AT",XdrvMailbox.data); break; case CMND_HM10_DISC_SCAN: - if (command_code == CMND_HM10_DISC_SCAN) { HM10_Discovery_Scan(); } + HM10_Discovery_Scan(); Response_P(S_JSON_HM10_COMMAND, command, ""); break; default: - // else for Unknown command - serviced = false; - break; + // else for Unknown command + serviced = false; + break; } } else { return false; @@ -733,21 +1092,25 @@ void HM10Show(bool json) for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { char slave[33]; sprintf_P(slave,"%s-%02x%02x%02x",kHM10SlaveType[MIBLEsensors.at(i).type-1],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); - char temperature[33]; // all sensors have temperature + char temperature[FLOATSZ]; // all sensors have temperature dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); ResponseAppend_P(PSTR(",\"%s\":{"),slave); if(MIBLEsensors.at(i).temp!=-1000.0f){ // this is the error code -> no temperature ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); } + else { + ResponseAppend_P(PSTR("}")); + continue; + } if (MIBLEsensors.at(i).type==FLORA){ - char lux[33]; - char moisture[33]; - char fertility[33]; + char lux[FLOATSZ]; + char moisture[FLOATSZ]; + char fertility[FLOATSZ]; dtostrfd((float)MIBLEsensors.at(i).lux, 0, lux); dtostrfd(MIBLEsensors.at(i).moisture, 0, moisture); dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); - if(MIBLEsensors.at(i).lux!=0xffff){ // this is the error code -> no temperature + if(MIBLEsensors.at(i).lux!=0x0ffffff){ // this is the error code -> no temperature ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%s"), lux); } if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no moisture @@ -758,15 +1121,20 @@ void HM10Show(bool json) } } if (MIBLEsensors.at(i).type>FLORA){ - char humidity[33]; + char humidity[FLOATSZ]; dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); 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 - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).bat); + if(MIBLEsensors.at(i).hum!=-1.0f && MIBLEsensors.at(i).temp!=-1000.0f){ // this is the error code -> no humidity nor temp + char dewpoint[FLOATSZ]; + dtostrfd(CalcTempHumToDew(MIBLEsensors.at(i).temp, MIBLEsensors.at(i).hum), Settings.flag2.temperature_resolution, dewpoint); + ResponseAppend_P(PSTR(",\"" D_JSON_DEWPOINT "\":%s"), dewpoint); } } + if(MIBLEsensors.at(i).bat!=0x00){ // this is the error code -> no battery + ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).bat); + } ResponseAppend_P(PSTR("}")); } #ifdef USE_WEBSERVER @@ -776,32 +1144,37 @@ void HM10Show(bool json) WSContentSend_PD(HTTP_HM10_HL); WSContentSend_PD(HTTP_HM10_SERIAL, kHM10SlaveType[MIBLEsensors.at(i).type-1], D_MAC_ADDRESS, MIBLEsensors.at(i).serial[0], MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); if(MIBLEsensors.at(i).temp!=-1000.0f){ - char temperature[33]; + char temperature[FLOATSZ]; dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); WSContentSend_PD(HTTP_SNS_TEMP, kHM10SlaveType[MIBLEsensors.at(i).type-1], temperature, TempUnit()); } if (MIBLEsensors.at(i).type==FLORA){ - if(MIBLEsensors.at(i).lux!=0xffff){ // this is the error code -> no valid value + if(MIBLEsensors.at(i).lux!=0x00ffffff){ // this is the error code -> no valid value WSContentSend_PD(HTTP_SNS_ILLUMINANCE, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).lux); } if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no valid value WSContentSend_PD(HTTP_SNS_MOISTURE, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).moisture); } if(MIBLEsensors.at(i).fertility!=-1000.0f){ // this is the error code -> no valid value - char fertility[33]; + char fertility[FLOATSZ]; dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); WSContentSend_PD(HTTP_HM10_FLORA_DATA, kHM10SlaveType[MIBLEsensors.at(i).type-1], fertility); } } if (MIBLEsensors.at(i).type>FLORA){ // everything "above" Flora if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity - char humidity[33]; + char humidity[FLOATSZ]; dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); WSContentSend_PD(HTTP_SNS_HUM, kHM10SlaveType[MIBLEsensors.at(i).type-1], humidity); } - if(MIBLEsensors.at(i).bat!=0xff){ - WSContentSend_PD(HTTP_BATTERY, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).bat); + if(MIBLEsensors.at(i).hum!=-1.0f && MIBLEsensors.at(i).temp!=-1000.0f){ // this is the error code -> no humidity nor temp + char dewpoint[FLOATSZ]; + dtostrfd(CalcTempHumToDew(MIBLEsensors.at(i).temp, MIBLEsensors.at(i).hum), Settings.flag2.temperature_resolution, dewpoint); + WSContentSend_PD(HTTP_SNS_DEW, kHM10SlaveType[MIBLEsensors.at(i).type-1], dewpoint, TempUnit()); } + } + if(MIBLEsensors.at(i).bat!=0x00){ + WSContentSend_PD(HTTP_BATTERY, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).bat); } } #endif // USE_WEBSERVER @@ -847,4 +1220,4 @@ bool Xsns62(uint8_t function) } return result; } -#endif //USE_HM10 \ No newline at end of file +#endif //USE_HM10