diff --git a/tasmota/xdrv_79_esp32_ble.ino b/tasmota/xdrv_79_esp32_ble.ino index 2aba0896c..8593d94f0 100644 --- a/tasmota/xdrv_79_esp32_ble.ino +++ b/tasmota/xdrv_79_esp32_ble.ino @@ -1259,8 +1259,11 @@ void postAdvertismentDetails(){ TasAutoMutex localmutex(&BLEOperationsRecursiveMutex, "BLEPostAdd"); if (BLEAdvertismentDetailsJsonSet){ - strncpy(TasmotaGlobal.mqtt_data, BLEAdvertismentDetailsJson, sizeof(TasmotaGlobal.mqtt_data)); - TasmotaGlobal.mqtt_data[sizeof(TasmotaGlobal.mqtt_data)-1] = 0; + +// strncpy(TasmotaGlobal.mqtt_data, BLEAdvertismentDetailsJson, sizeof(TasmotaGlobal.mqtt_data)); +// TasmotaGlobal.mqtt_data[sizeof(TasmotaGlobal.mqtt_data)-1] = 0; + Response_P(BLEAdvertismentDetailsJson); + BLEAdvertismentDetailsJsonSet = 0; // we got the data, give before MQTT call. localmutex.give(); @@ -3142,6 +3145,7 @@ void CmndBLEOperation(void){ \*********************************************************************************************/ static void BLEPostMQTTSeenDevices(int type) { int remains = 0; +/* nextSeenDev = 0; memset(TasmotaGlobal.mqtt_data, 0, sizeof(TasmotaGlobal.mqtt_data)); @@ -3156,6 +3160,19 @@ static void BLEPostMQTTSeenDevices(int type) { MqttPublishPrefixTopicRulesProcess_P((1== type) ? TELE : STAT, PSTR("BLE")); } while (remains); // } +*/ + + // Once TasmotaGlobal.mqtt_data is changed from (limited by MESSZ) char array to (unlimited) String the below code can be simplified + char dest[ResponseSize()]; + int maxlen = ResponseSize() -64; + + do { + remains = getSeenDevicesToJson(dest, maxlen); + ResponseTime_P(dest); + // no retain - this is present devices, not historic + MqttPublishPrefixTopicRulesProcess_P((1== type) ? TELE : STAT, PSTR("BLE")); + } while (remains); + } static void BLEPostMQTT(bool onlycompleted) { diff --git a/tasmota/xsns_27_apds9960.ino b/tasmota/xsns_27_apds9960.ino index b1619ff40..2182d923c 100644 --- a/tasmota/xsns_27_apds9960.ino +++ b/tasmota/xsns_27_apds9960.ino @@ -1784,7 +1784,7 @@ void APDS9960_loop(void) { enableGestureSensor(); APDS9960_overload = false; Response_P(PSTR("{\"Gesture\":\"On\"}")); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, TasmotaGlobal.mqtt_data); // only after the long break we report, that we are online again + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, APDS9960_TAG); // only after the long break we report, that we are online again gesture_mode = 1; } @@ -1796,7 +1796,7 @@ void APDS9960_loop(void) { disableGestureSensor(); recovery_loop_counter = APDS9960_LONG_RECOVERY; // long pause after overload/long press - number of stateloops Response_P(PSTR("{\"Gesture\":\"Off\"}")); - MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, TasmotaGlobal.mqtt_data); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, APDS9960_TAG); gesture_mode = 0; } } diff --git a/tasmota/xsns_61_MI_NRF24.ino b/tasmota/xsns_61_MI_NRF24.ino index 7282435fe..77503717d 100644 --- a/tasmota/xsns_61_MI_NRF24.ino +++ b/tasmota/xsns_61_MI_NRF24.ino @@ -1682,6 +1682,14 @@ const char HTTP_MINRF_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%dus/cm{e const char HTTP_MINRF_HL[] PROGMEM = "{s}
{m}
{e}"; const char HTTP_NRF24NEW[] PROGMEM = "{s}%sL01%c{m}%u%s / %u{e}"; +void MINRFShowContinuation(bool *commaflg) { + if (*commaflg) { + ResponseAppend_P(PSTR(",")); + } else { + *commaflg = true; + } +} + void MINRFShow(bool json) { if (json) { @@ -1706,9 +1714,9 @@ void MINRFShow(bool json) if(MIBLEsensors[i].type != YEERC) break; // send every RC code, even if there is a potentially false MAC } - ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":"),kMINRFDeviceType[MIBLEsensors[i].type-1],MIBLEsensors[i].MAC[3],MIBLEsensors[i].MAC[4],MIBLEsensors[i].MAC[5]); - - uint32_t _positionCurlyBracket = ResponseLength(); // ... this will be a ',' first, but later be replaced + bool commaflg = false; + ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"), + kMINRFDeviceType[MIBLEsensors[i].type-1],MIBLEsensors[i].MAC[3],MIBLEsensors[i].MAC[4],MIBLEsensors[i].MAC[5]); if((!MINRF.mode.triggeredTele && !MINRF.option.minimalSummary)||MINRF.mode.triggeredTele){ bool tempHumSended = false; @@ -1719,7 +1727,7 @@ void MINRFShow(bool json) ||(!hass_mode==2) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",")); + MINRFShowContinuation(&commaflg); ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); tempHumSended = true; } @@ -1732,7 +1740,8 @@ void MINRFShow(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"), + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%*_f"), Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp); } } @@ -1742,7 +1751,8 @@ void MINRFShow(bool json) if (!isnan(MIBLEsensors[i].hum)) { char hum[FLOATSZ]; dtostrfd(MIBLEsensors[i].hum, Settings.flag2.humidity_resolution, hum); - ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), hum); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_HUMIDITY "\":%s"), hum); } } } @@ -1753,7 +1763,8 @@ void MINRFShow(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ) { // this is the error code -> no lux - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); } } } @@ -1764,7 +1775,8 @@ void MINRFShow(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); } } } @@ -1775,29 +1787,37 @@ void MINRFShow(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"Fertility\":%u"), MIBLEsensors[i].fertility); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Fertility\":%u"), MIBLEsensors[i].fertility); } } } if (MIBLEsensors[i].feature.Btn){ if(MIBLEsensors[i].eventType.Btn){ - ResponseAppend_P(PSTR(",\"Btn\":%u"),MIBLEsensors[i].Btn); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Btn\":%u"),MIBLEsensors[i].Btn); } } } // minimal summary if (MIBLEsensors[i].feature.PIR){ if(MIBLEsensors[i].eventType.motion || !MINRF.mode.triggeredTele){ - if(MINRF.mode.triggeredTele) ResponseAppend_P(PSTR(",\"PIR\":1")); // only real-time - ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); + if(MINRF.mode.triggeredTele) { + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":1")); // only real-time + } + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Events\":%u"),MIBLEsensors[i].events); } else if(MIBLEsensors[i].eventType.noMotion && MINRF.mode.triggeredTele){ - ResponseAppend_P(PSTR(",\"PIR\":0")); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":0")); } } if (MIBLEsensors[i].feature.NMT || !MINRF.mode.triggeredTele){ if(MIBLEsensors[i].eventType.NMT){ - ResponseAppend_P(PSTR(",\"NMT\":%u"), MIBLEsensors[i].NMT); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"NMT\":%u"), MIBLEsensors[i].NMT); } } if (MIBLEsensors[i].feature.bat){ @@ -1807,13 +1827,13 @@ void MINRFShow(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); + MINRFShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Battery\":%u"), MIBLEsensors[i].bat); } } } - if(_positionCurlyBracket==ResponseLength()) ResponseAppend_P(PSTR(",")); // write some random char, to be overwritten in the next step - ResponseAppend_P(PSTR("}")); - TasmotaGlobal.mqtt_data[_positionCurlyBracket] = '{'; + ResponseJsonEnd(); + MIBLEsensors[i].eventType.raw = 0; if(MIBLEsensors[i].shallSendMQTT==1){ MIBLEsensors[i].shallSendMQTT = 0; diff --git a/tasmota/xsns_62_MI_HM10.ino b/tasmota/xsns_62_MI_HM10.ino index ffb2bd81e..e9b0519d6 100644 --- a/tasmota/xsns_62_MI_HM10.ino +++ b/tasmota/xsns_62_MI_HM10.ino @@ -453,23 +453,7 @@ void HM10_ReverseMAC(uint8_t _mac[]){ } memcpy(_mac,_reversedMAC, sizeof(_reversedMAC)); } -#ifdef USE_HOME_ASSISTANT -/** - * @brief For HASS only, changes last entry of JSON in mqtt_data to 'null' - */ -void HM10nullifyEndOfMQTT_DATA(){ - char *p = TasmotaGlobal.mqtt_data + ResponseLength(); - while(true){ - *p--; - if(p[0]==':'){ - p[1] = 0; - break; - } - } - ResponseAppend_P(PSTR("null")); -} -#endif // USE_HOME_ASSISTANT /*********************************************************************************************\ * chained tasks \*********************************************************************************************/ @@ -1058,7 +1042,7 @@ void HM10showScanResults(){ ToHex_P(_scanResult.MAC,6,_MAC,18,':'); ResponseAppend_P(PSTR("%s{\"MAC\":\"%s\",\"CID\":\"0x%04x\",\"SVC\":\"0x%04x\",\"UUID\":\"0x%04x\",\"RSSI\":%d}"), (add_comma)?",":"", _MAC, _scanResult.CID, _scanResult.SVC, _scanResult.UUID, _scanResult.RSSI); - add_comma = true; + add_comma = true; } ResponseAppend_P(PSTR("]}")); MIBLEscanResult.clear(); @@ -1072,7 +1056,7 @@ void HM10showBlockList(){ char _MAC[18]; ToHex_P(_scanResult.buf,6,_MAC,18,':'); ResponseAppend_P(PSTR("%s\"%s\""), (add_comma)?",":"", _MAC); - add_comma = true; + add_comma = true; } ResponseAppend_P(PSTR("]")); HM10.mode.shallShowBlockList = 0; @@ -1750,6 +1734,14 @@ const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}"; const char HTTP_HM10_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%u us/cm{e}"; const char HTTP_HM10_HL[] PROGMEM = "{s}
{m}
{e}"; +void HM10ShowContinuation(bool *commaflg) { + if (*commaflg) { + ResponseAppend_P(PSTR(",")); + } else { + *commaflg = true; + } +} + void HM10Show(bool json) { if (json) { @@ -1781,12 +1773,11 @@ void HM10Show(bool json) if(HM10.mode.triggeredTele && MIBLEsensors[i].eventType.raw == 0) continue; if(HM10.mode.triggeredTele && MIBLEsensors[i].shallSendMQTT==0) continue; - ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":"), // do not add the '{' now ... + bool commaflg = false; + ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"), kHM10DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].MAC[3], MIBLEsensors[i].MAC[4], MIBLEsensors[i].MAC[5]); - uint32_t _positionCurlyBracket = ResponseLength(); // ... this will be a ',' first, but later be replaced - if((!HM10.mode.triggeredTele && !HM10.option.minimalSummary)||HM10.mode.triggeredTele){ bool tempHumSended = false; if(MIBLEsensors[i].feature.tempHum){ @@ -1796,7 +1787,7 @@ void HM10Show(bool json) ||(hass_mode!=-1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",")); + HM10ShowContinuation(&commaflg); ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); tempHumSended = true; } @@ -1809,7 +1800,8 @@ void HM10Show(bool json) ||(hass_mode!=-1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"), + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%*_f"), Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp); } } @@ -1823,99 +1815,124 @@ void HM10Show(bool json) ) { char hum[FLOATSZ]; dtostrfd(MIBLEsensors[i].hum, Settings.flag2.humidity_resolution, hum); - ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), hum); + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_HUMIDITY "\":%s"), hum); } } } if (MIBLEsensors[i].feature.lux){ if(MIBLEsensors[i].eventType.lux || !HM10.mode.triggeredTele || HM10.option.allwaysAggregate){ - if (MIBLEsensors[i].lux!=0x0ffffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].lux == 0x0ffffff)) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].lux != 0x0ffffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { // this is the error code -> no lux - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].lux==0x0ffffff) HM10nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); } } } if (MIBLEsensors[i].feature.moist){ if(MIBLEsensors[i].eventType.moist || !HM10.mode.triggeredTele || HM10.option.allwaysAggregate){ - if (MIBLEsensors[i].moisture!=0xff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].moisture == 0xff)) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_MOISTURE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].moisture != 0xff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].moisture==0xff) HM10nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); } } } if (MIBLEsensors[i].feature.fert){ if(MIBLEsensors[i].eventType.fert || !HM10.mode.triggeredTele || HM10.option.allwaysAggregate){ - if (MIBLEsensors[i].fertility!=0xffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].fertility == 0xffff)) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Fertility\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].fertility != 0xffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"Fertility\":%u"), MIBLEsensors[i].fertility); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].fertility==0xffff) HM10nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Fertility\":%u"), MIBLEsensors[i].fertility); } } } if (MIBLEsensors[i].feature.Btn){ if(MIBLEsensors[i].eventType.Btn){ - ResponseAppend_P(PSTR(",\"Btn\":%u"),MIBLEsensors[i].Btn); + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Btn\":%u"),MIBLEsensors[i].Btn); } } } // minimal summary if (MIBLEsensors[i].feature.PIR){ if(MIBLEsensors[i].eventType.motion || !HM10.mode.triggeredTele){ - if(HM10.mode.triggeredTele) ResponseAppend_P(PSTR(",\"PIR\":1")); // only real-time - ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); + if(HM10.mode.triggeredTele) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":1")); // only real-time + } + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Events\":%u"),MIBLEsensors[i].events); } else if(MIBLEsensors[i].eventType.noMotion && HM10.mode.triggeredTele){ - ResponseAppend_P(PSTR(",\"PIR\":0")); + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":0")); } } if (MIBLEsensors[i].type == FLORA && !HM10.mode.triggeredTele) { if (MIBLEsensors[i].firmware[0] != '\0') { // this is the error code -> no firmware - ResponseAppend_P(PSTR(",\"Firmware\":\"%s\""), MIBLEsensors[i].firmware); + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Firmware\":\"%s\""), MIBLEsensors[i].firmware); } } if (MIBLEsensors[i].feature.NMT || !HM10.mode.triggeredTele){ if(MIBLEsensors[i].eventType.NMT){ - ResponseAppend_P(PSTR(",\"NMT\":%u"), MIBLEsensors[i].NMT); + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"NMT\":%u"), MIBLEsensors[i].NMT); } } if (MIBLEsensors[i].feature.bat){ if(MIBLEsensors[i].eventType.bat || !HM10.mode.triggeredTele || HM10.option.allwaysAggregate){ - if (MIBLEsensors[i].bat != 0x00 #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].bat == 0x00)) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Battery\":null")); + } else #endif //USE_HOME_ASSISTANT - ) { // this is the error code -> no battery - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); + if ((MIBLEsensors[i].bat != 0x00) #ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].bat == 0x00) HM10nullifyEndOfMQTT_DATA(); + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT + ) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Battery\":%u"), MIBLEsensors[i].bat); } } } - if (HM10.option.showRSSI) ResponseAppend_P(PSTR(",\"RSSI\":%d"), MIBLEsensors[i].rssi); + if (HM10.option.showRSSI) { + HM10ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"RSSI\":%d"), MIBLEsensors[i].rssi); + } + ResponseJsonEnd(); - - if(_positionCurlyBracket==ResponseLength()) ResponseAppend_P(PSTR(",")); // write some random char, to be overwritten in the next step - ResponseAppend_P(PSTR("}")); - TasmotaGlobal.mqtt_data[_positionCurlyBracket] = '{'; MIBLEsensors[i].eventType.raw = 0; if(MIBLEsensors[i].shallSendMQTT==1){ MIBLEsensors[i].shallSendMQTT = 0; diff --git a/tasmota/xsns_62_esp32_mi.ino b/tasmota/xsns_62_esp32_mi.ino index 3a9a3a68a..f77b959a2 100644 --- a/tasmota/xsns_62_esp32_mi.ino +++ b/tasmota/xsns_62_esp32_mi.ino @@ -628,24 +628,6 @@ int MI32_decryptPacket(char *_buf, uint16_t _bufSize, uint32_t _type){ } #endif // USE_MI_DECRYPTION -#ifdef USE_HOME_ASSISTANT -/** - * @brief For HASS only, changes last entry of JSON in mqtt_data to 'null' - */ - -void MI32nullifyEndOfMQTT_DATA(){ - char *p = TasmotaGlobal.mqtt_data + ResponseLength(); - while(true){ - *p--; - if(p[0]==':'){ - p[1] = 0; - break; - } - } - ResponseAppend_P(PSTR("null")); -} -#endif // USE_HOME_ASSISTANT - /*********************************************************************************************\ * common functions \*********************************************************************************************/ @@ -1993,6 +1975,14 @@ const char HTTP_NMT[] PROGMEM = "{s}%s No motion{m}> %u seconds{e}"; const char HTTP_MI32_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%u us/cm{e}"; const char HTTP_MI32_HL[] PROGMEM = "{s}
{m}
{e}"; +void MI32ShowContinuation(bool *commaflg) { + if (*commaflg) { + ResponseAppend_P(PSTR(",")); + } else { + *commaflg = true; + } +} + void MI32Show(bool json) { if (json) { @@ -2026,12 +2016,11 @@ void MI32Show(bool json) if(MI32.mode.triggeredTele && MIBLEsensors[i].eventType.raw == 0) continue; if(MI32.mode.triggeredTele && MIBLEsensors[i].shallSendMQTT==0) continue; - ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":"), // do not add the '{' now ... + bool commaflg = false; + ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"), kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].MAC[3], MIBLEsensors[i].MAC[4], MIBLEsensors[i].MAC[5]); - uint32_t _positionCurlyBracket = ResponseLength(); // ... this will be a ',' first, but later be replaced - if((!MI32.mode.triggeredTele && !MI32.option.minimalSummary)||MI32.mode.triggeredTele){ bool tempHumSended = false; if(MIBLEsensors[i].feature.tempHum){ @@ -2041,7 +2030,7 @@ void MI32Show(bool json) ||(hass_mode!=-1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",")); + MI32ShowContinuation(&commaflg); ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); tempHumSended = true; } @@ -2054,7 +2043,8 @@ void MI32Show(bool json) ||(hass_mode!=-1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"), + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%*_f"), Settings.flag2.temperature_resolution, &MIBLEsensors[i].temp); } } @@ -2068,49 +2058,62 @@ void MI32Show(bool json) ) { char hum[FLOATSZ]; dtostrfd(MIBLEsensors[i].hum, Settings.flag2.humidity_resolution, hum); - ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), hum); + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_HUMIDITY "\":%s"), hum); } } } if (MIBLEsensors[i].feature.lux){ if(MIBLEsensors[i].eventType.lux || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (MIBLEsensors[i].lux!=0x0ffffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].lux == 0x0ffffff)) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].lux != 0x0ffffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { // this is the error code -> no lux - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].lux==0x0ffffff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); } } } if (MIBLEsensors[i].feature.moist){ if(MIBLEsensors[i].eventType.moist || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (MIBLEsensors[i].moisture!=0xff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].moisture == 0xff)) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_MOISTURE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].moisture != 0xff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].moisture==0xff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); } } } if (MIBLEsensors[i].feature.fert){ if(MIBLEsensors[i].eventType.fert || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (MIBLEsensors[i].fertility!=0xffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].fertility == 0xffff)) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Fertility\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((MIBLEsensors[i].fertility != 0xffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { - ResponseAppend_P(PSTR(",\"Fertility\":%u"), MIBLEsensors[i].fertility); -#ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].fertility==0xffff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Fertility\":%u"), MIBLEsensors[i].fertility); } } } @@ -2120,50 +2123,63 @@ void MI32Show(bool json) ||(hass_mode==2) #endif //USE_HOME_ASSISTANT ){ - ResponseAppend_P(PSTR(",\"Btn\":%u"),MIBLEsensors[i].Btn); + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Btn\":%u"),MIBLEsensors[i].Btn); } } } // minimal summary if (MIBLEsensors[i].feature.PIR){ if(MIBLEsensors[i].eventType.motion || !MI32.mode.triggeredTele){ - if(MI32.mode.triggeredTele) ResponseAppend_P(PSTR(",\"PIR\":1")); // only real-time - ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); + if(MI32.mode.triggeredTele) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":1")); // only real-time + } + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Events\":%u"),MIBLEsensors[i].events); } else if(MIBLEsensors[i].eventType.noMotion && MI32.mode.triggeredTele){ - ResponseAppend_P(PSTR(",\"PIR\":0")); + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"PIR\":0")); } } if (MIBLEsensors[i].type == FLORA && !MI32.mode.triggeredTele) { if (MIBLEsensors[i].firmware[0] != '\0') { // this is the error code -> no firmware - ResponseAppend_P(PSTR(",\"Firmware\":\"%s\""), MIBLEsensors[i].firmware); + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Firmware\":\"%s\""), MIBLEsensors[i].firmware); } } if (MIBLEsensors[i].feature.NMT || !MI32.mode.triggeredTele){ if(MIBLEsensors[i].eventType.NMT){ - ResponseAppend_P(PSTR(",\"NMT\":%u"), MIBLEsensors[i].NMT); + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"NMT\":%u"), MIBLEsensors[i].NMT); } } if (MIBLEsensors[i].feature.bat){ if(MIBLEsensors[i].eventType.bat || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (MIBLEsensors[i].bat != 0x00 #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (MIBLEsensors[i].bat == 0x00)) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Battery\":null")); + } else #endif //USE_HOME_ASSISTANT - ) { // this is the error code -> no battery - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); + if ((MIBLEsensors[i].bat != 0x00) #ifdef USE_HOME_ASSISTANT - if (MIBLEsensors[i].bat == 0x00) MI32nullifyEndOfMQTT_DATA(); + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT + ) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"Battery\":%u"), MIBLEsensors[i].bat); } } } - if (MI32.option.showRSSI) ResponseAppend_P(PSTR(",\"RSSI\":%d"), MIBLEsensors[i].RSSI); + if (MI32.option.showRSSI) { + MI32ShowContinuation(&commaflg); + ResponseAppend_P(PSTR("\"RSSI\":%d"), MIBLEsensors[i].RSSI); + } + ResponseJsonEnd(); - if(_positionCurlyBracket==ResponseLength()) ResponseAppend_P(PSTR(",")); // write some random char, to be overwritten in the next step - ResponseAppend_P(PSTR("}")); - TasmotaGlobal.mqtt_data[_positionCurlyBracket] = '{'; MIBLEsensors[i].eventType.raw = 0; if(MIBLEsensors[i].shallSendMQTT==1){ MIBLEsensors[i].shallSendMQTT = 0; diff --git a/tasmota/xsns_62_esp32_mi_ble.ino b/tasmota/xsns_62_esp32_mi_ble.ino index 912b9c798..db1675098 100644 --- a/tasmota/xsns_62_esp32_mi_ble.ino +++ b/tasmota/xsns_62_esp32_mi_ble.ino @@ -5,7 +5,7 @@ Copyright (C) 2020 Christian Baars and Theo Arends - Also Simon Hailes and Robert Klauco + Also Simon Hailes and Robert Klauco 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 @@ -1332,27 +1332,6 @@ int MIParsePacket(const uint8_t* slotmac, struct mi_beacon_data_t *parsed, const return 1; } - - - -#ifdef USE_HOME_ASSISTANT -/** - * @brief For HASS only, changes last entry of JSON in mqtt_data to 'null' - */ - -void MI32nullifyEndOfMQTT_DATA(){ - char *p = TasmotaGlobal.mqtt_data + ResponseLength(); - while(true){ - *p--; - if(p[0]==':'){ - p[1] = 0; - break; - } - } - ResponseAppend_P(PSTR("null")); -} -#endif // USE_HOME_ASSISTANT - /*********************************************************************************************\ * common functions \*********************************************************************************************/ @@ -1674,7 +1653,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){ char tmp[20]; BLE_ESP32::dump(tmp, 20, (uint8_t*)&(parsed->payload), parsed->payload.size+3); if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: MI%d payload %s"), _slot, tmp); - + // clear this for every payload MIBLEsensors[_slot].pairing = 0; MIBLEsensors[_slot].eventType.PairBtn = 0; @@ -1693,7 +1672,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){ uint8_t motion = parsed->payload.data[0]; res = 0; }break; - case 0x000f: // 'Someone is moving (with light)' + case 0x000f: // 'Someone is moving (with light)' MIBLEsensors[_slot].eventType.motion = 1; MIBLEsensors[_slot].lastTime = millis(); MIBLEsensors[_slot].events++; @@ -1999,13 +1978,13 @@ void MI32EverySecond(bool restart){ // show tas style sensor MQTT MI32ShowSomeSensors(); } - - if (MI32.option.MQTTType == 1 + + if (MI32.option.MQTTType == 1 #ifdef USE_HOME_ASSISTANT || Settings.flag.hass_discovery #endif - ) { + ) { // these two share a counter // discovery only sent if hass_discovery MI32DiscoveryOneMISensor(); @@ -2545,15 +2524,17 @@ void MI32GetOneSensorJson(int slot, int hidename){ } if (p->feature.lux){ if(p->eventType.lux || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (p->lux!=0x0ffffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (p->lux == 0x0ffffff)) { + ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((p->lux != 0x0ffffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { // this is the error code -> no lux ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), p->lux); -#ifdef USE_HOME_ASSISTANT - if (p->lux==0x0ffffff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT } } } @@ -2568,29 +2549,33 @@ void MI32GetOneSensorJson(int slot, int hidename){ } if (p->feature.moist){ if(p->eventType.moist || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (p->moisture!=0xff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (p->moisture == 0xff)) { + ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((p->moisture != 0xff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), p->moisture); -#ifdef USE_HOME_ASSISTANT - if (p->moisture==0xff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT } } } if (p->feature.fert){ if(p->eventType.fert || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (p->fertility!=0xffff #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (p->fertility == 0xffff)) { + ResponseAppend_P(PSTR(",\"Fertility\":null")); + } else +#endif //USE_HOME_ASSISTANT + if ((p->fertility != 0xffff) +#ifdef USE_HOME_ASSISTANT + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT ) { ResponseAppend_P(PSTR(",\"Fertility\":%u"), p->fertility); -#ifdef USE_HOME_ASSISTANT - if (p->fertility==0xffff) MI32nullifyEndOfMQTT_DATA(); -#endif //USE_HOME_ASSISTANT } } } @@ -2632,15 +2617,17 @@ void MI32GetOneSensorJson(int slot, int hidename){ } if (p->feature.bat){ if(p->eventType.bat || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ - if (p->bat != 0x00 #ifdef USE_HOME_ASSISTANT - ||(hass_mode!=-1) + if ((hass_mode != -1) && (p->bat == 0x00)) { + ResponseAppend_P(PSTR(",\"Battery\":null")); + } else #endif //USE_HOME_ASSISTANT - ) { // this is the error code -> no battery - ResponseAppend_P(PSTR(",\"Battery\":%u"), p->bat); + if ((p->bat != 0x00) #ifdef USE_HOME_ASSISTANT - if (p->bat == 0x00) MI32nullifyEndOfMQTT_DATA(); + || (hass_mode != -1) #endif //USE_HOME_ASSISTANT + ) { + ResponseAppend_P(PSTR(",\"Battery\":%u"), p->bat); } } } @@ -2888,7 +2875,7 @@ void MI32DiscoveryOneMISensor(){ return; } uint8_t isBinary = 0; - + ResponseClear(); switch(i/3){ diff --git a/tasmota/xsns_75_prometheus.ino b/tasmota/xsns_75_prometheus.ino index a358f9697..b28b61685 100644 --- a/tasmota/xsns_75_prometheus.ino +++ b/tasmota/xsns_75_prometheus.ino @@ -132,9 +132,7 @@ void HandleMetrics(void) { ResponseClear(); MqttShowSensor(); //Pull sensor data - char json[ResponseLength()+1]; - snprintf_P(json, sizeof(json), TasmotaGlobal.mqtt_data); - String jsonStr = json; + String jsonStr = TasmotaGlobal.mqtt_data; JsonParser parser((char *)jsonStr.c_str()); JsonParserObject root = parser.getRootObject(); if (root) { // did JSON parsing went ok?