diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 7febc7a3bfb8..a6ad45ca492d 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -434,6 +434,8 @@ struct TasmotaGlobal_t { #ifdef USE_BERRY bool berry_fast_loop_enabled = false; // is Berry fast loop enabled, i.e. control is passed at each loop iteration #endif // USE_BERRY + + bool NeedSeparatorLine = false; // Determine if a separator line should be send to WebUI after sensor/driver output } TasmotaGlobal; TSettings* Settings = nullptr; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index 69bdaddb2e44..0d15e278fb23 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -833,6 +833,8 @@ void _WSContentSendBuffer(bool decimal, const char * formatP, va_list arg) { int len = strlen(content); if (0 == len) { return; } // No content + TasmotaGlobal.NeedSeparatorLine = true; + if (decimal && (D_DECIMAL_SEPARATOR[0] != '.')) { for (uint32_t i = 0; i < len; i++) { if ('.' == content[i]) { @@ -1470,6 +1472,7 @@ bool HandleRootStatusRefresh(void) WSContentSend_P(PSTR("{t}")); if (Settings->web_time_end) { WSContentSend_P(PSTR("{s}" D_TIMER_TIME "{m}%s{e}"), GetDateAndTime(DT_LOCAL).substring(Settings->web_time_start, Settings->web_time_end).c_str()); + WSContentSend_P("
{e}"); } XsnsXdrvCall(FUNC_WEB_SENSOR); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino index 66bf50acd7bc..a5b0fd3e13d9 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_03_energy.ino @@ -1409,7 +1409,7 @@ void EnergyShow(bool json) { // {s}Head1Head2{e} // {s}Head1Head2Head3{e} // {s}Head1Head2Head3Head4{e} - WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} =
) + WSContentSend_P(PSTR("
{t}{s}")); // First column is empty ({t} = , {s} =
) bool label_o = voltage_common; bool no_label = (1 == Energy->phase_count); char number[4]; @@ -1448,7 +1448,7 @@ void EnergyShow(bool json) { WSContentSend_PD(HTTP_SNS_EXPORT_ACTIVE, WebEnergyFmt(Energy->export_active, Settings->flag2.energy_resolution, single)); } XnrgCall(FUNC_WEB_COL_SENSOR); - WSContentSend_P(PSTR("

{t}")); // {t} = - Define for next FUNC_WEB_SENSOR + WSContentSend_P(PSTR("
{t}")); // {t} = - Define for next FUNC_WEB_SENSOR XnrgCall(FUNC_WEB_SENSOR); #endif // USE_WEBSERVER } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 2fdc52b07028..162f5bd63f19 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -1141,6 +1141,7 @@ void ShutterToggle(bool dir) void ShutterShow(){ for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, (Settings->shutter_options[i] & 1) ? D_OPEN : D_CLOSE,(Settings->shutter_options[i] & 1) ? D_CLOSE : D_OPEN, (Settings->shutter_options[i] & 1) ? (100 - ShutterRealToPercentPosition(-9999, i)) : ShutterRealToPercentPosition(-9999, i), i+1); + TasmotaGlobal.NeedSeparatorLine = false; // Do not diplay sensor separation } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino index a2cbe27fef34..aa4b28027e63 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_39_thermostat.ino @@ -2054,7 +2054,7 @@ const char HTTP_THERMOSTAT_DUTY_CYCLE[] PROGMEM = "{s}" D_THERMOSTAT_DUTY_CY const char HTTP_THERMOSTAT_CYCLE_TIME[] PROGMEM = "{s}" D_THERMOSTAT_CYCLE_TIME "{m}%d " D_UNIT_MINUTE "{e}"; const char HTTP_THERMOSTAT_CONTROL_METHOD[] PROGMEM = "{s}" D_THERMOSTAT_CONTROL_METHOD "{m}%s{e}"; const char HTTP_THERMOSTAT_PI_AUTOTUNE[] PROGMEM = "{s}" D_THERMOSTAT_PI_AUTOTUNE "{m}%s{e}"; -const char HTTP_THERMOSTAT_HL[] PROGMEM = "{s}
{m}
{e}"; +const char HTTP_THERMOSTAT_HL_THIN[] PROGMEM = "{s}
{m}
{e}"; #endif // USE_WEBSERVER @@ -2078,7 +2078,7 @@ void ThermostatShow(uint8_t ctr_output, bool json) } #ifdef USE_WEBSERVER - WSContentSend_P(HTTP_THERMOSTAT_HL); + if (ctr_output) WSContentSend_P(HTTP_THERMOSTAT_HL_THIN); if (Thermostat[ctr_output].status.thermostat_mode == THERMOSTAT_OFF) { WSContentSend_P(HTTP_THERMOSTAT_INFO, ctr_output + 1, D_DISABLED ); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino index 978dcab58b6c..aa464318f582 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_85_esp32_ble_eq3_trv.ino @@ -989,7 +989,7 @@ int EQ3SendResult(char *requested, const char *result){ } #ifdef USE_WEBSERVER -const char HTTP_EQ3_HL[] PROGMEM = "{s}
{m}
{e}"; +const char HTTP_EQ3_HL_THIN[] PROGMEM = "{s}
{m}
{e}"; const char HTTP_EQ3_ALIAS[] PROGMEM = "{s}EQ3 %d Alias{m}%s{e}"; const char HTTP_EQ3_MAC[] PROGMEM = "{s}EQ3 %d " D_MAC_ADDRESS "{m}%s{e}"; const char HTTP_EQ3_RSSI[] PROGMEM = "{s}EQ3 %d " D_RSSI "{m}%d dBm{e}"; @@ -1000,10 +1000,12 @@ const char HTTP_EQ3_BATTERY[] PROGMEM = "{s}EQ3 %d " D_BATTERY "{m}%s{e}"; void EQ3Show(void) { char c_unit = D_UNIT_CELSIUS[0]; // ToDo: Check if fahrenheit is possible -> temp_format==TEMP_CELSIUS ? D_UNIT_CELSIUS[0] : D_UNIT_FAHRENHEIT[0]; + bool FirstSensorShown = false; for (int i = 0; i < EQ3_NUM_DEVICESLOTS; i++) { if (EQ3Devices[i].timeoutTime) { - WSContentSend_P(HTTP_EQ3_HL); + if (FirstSensorShown) WSContentSend_P(HTTP_EQ3_HL_THIN); + FirstSensorShown = true; const char *alias = BLE_ESP32::getAlias(EQ3Devices[i].addr); if (alias && *alias){ WSContentSend_PD(HTTP_EQ3_ALIAS, i + 1, alias); diff --git a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino index 06c3e10921b3..c3910c1798c3 100644 --- a/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino +++ b/tasmota/tasmota_xsns_sensor/xsns_62_esp32_mi_ble.ino @@ -2723,34 +2723,35 @@ void CmndMi32Keys(void){ * Presentation \*********************************************************************************************/ +const char HTTP_MI32_HL[] PROGMEM = "

{e}"; +const char HTTP_MI32_HL_THIN[] PROGMEM = "{s}
{m}
{e}"; const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 " MI32_VERSION "{m}%u%s / %u{e}"; const char HTTP_MI32_ALIAS[] PROGMEM = "{s}%s Alias{m}%s{e}"; -const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}"; -const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}"; -const char HTTP_BATTERY[] PROGMEM = "{s}%s " D_BATTERY "{m}%u %%{e}"; -const char HTTP_LASTBUTTON[] PROGMEM = "{s}%s Last Button{m}%u {e}"; -const char HTTP_EVENTS[] PROGMEM = "{s}%s Events{m}%u {e}"; -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}"; +const char HTTP_MI32_MAC[] PROGMEM = "{s}%s " D_MAC_ADDRESS "{m}%s{e}"; +const char HTTP_MI32_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}"; +const char HTTP_MI32_BATTERY[] PROGMEM = "{s}%s " D_BATTERY "{m}%u %%{e}"; +const char HTTP_MI32_LASTBUTTON[] PROGMEM = "{s}%s Last Button{m}%u{e}"; +const char HTTP_MI32_EVENTS[] PROGMEM = "{s}%s Events{m}%u{e}"; +const char HTTP_MI32_NMT[] PROGMEM = "{s}%s No motion{m}> %u " D_SECONDS "{e}"; +const char HTTP_MI32_FLORA_DATA[] PROGMEM = "{s}%s Fertility{m}%u " D_UNIT_MICROSIEMENS_PER_CM "{e}"; const char HTTP_MI32_LIGHT[] PROGMEM = "{s}%s " D_LIGHT "{m}%d{e}"; const char HTTP_MISCALE_WEIGHT[] PROGMEM = "{s}%s " D_WEIGHT "{m}%*_f %s{e}"; const char HTTP_MISCALE_WEIGHT_REMOVED[] PROGMEM = "{s}%s Weight removed{m}%s{e}"; const char HTTP_MISCALE_WEIGHT_STABILIZED[] PROGMEM = "{s}%s Weight stabilized{m}%s{e}"; const char HTTP_MISCALE_IMPEDANCE[] PROGMEM = "{s}%s Impedance{m}%u{e}"; const char HTTP_MISCALE_IMPEDANCE_STABILIZED[] PROGMEM = "{s}%s Impedance stabilized{m}%s{e}"; -const char HTTP_SJWS01LM_FLOODING[] PROGMEM = "{s}%s Flooding{m}%u {e}"; +const char HTTP_SJWS01LM_FLOODING[] PROGMEM = "{s}%s Flooding{m}%u{e}"; //const char HTTP_NEEDKEY[] PROGMEM = "{s}%s %s{m} {e}"; +// "\">%s{m}{e}"; //const char HTTP_NEEDKEY[] PROGMEM = "{s}%s %s{m} {e}"; +// "\">%s{m}{e}"; const char HTTP_NEEDKEY[] PROGMEM = "{s}%s %s{m} {e}"; + "\">%s{m}{e}"; const char HTTP_PAIRING[] PROGMEM = "{s}%s Pair Button Pressed{m} {e}"; @@ -3521,7 +3522,7 @@ void MI32Show(bool json) WSContentSend_P(HTTP_MI32, i + 1, stemp, numsensors); for (i; iMAC,6,_MAC,18);//,':'); - WSContentSend_P(HTTP_MI32_MAC, typeName, D_MAC_ADDRESS, _MAC); - WSContentSend_PD(HTTP_RSSI, typeName, p->RSSI); + WSContentSend_P(HTTP_MI32_MAC, typeName, _MAC); + WSContentSend_PD(HTTP_MI32_RSSI, typeName, p->RSSI); // for some reason, display flora differently switch(p->type){ @@ -3597,11 +3598,11 @@ void MI32Show(bool json) #endif //USE_MI_DECRYPTION if (p->feature.events){ - WSContentSend_PD(HTTP_EVENTS, typeName, p->events); + WSContentSend_PD(HTTP_MI32_EVENTS, typeName, p->events); } if (p->feature.NMT){ // no motion time - if(p->NMT>0) WSContentSend_PD(HTTP_NMT, typeName, p->NMT); + if(p->NMT>0) WSContentSend_PD(HTTP_MI32_NMT, typeName, p->NMT); } if (p->feature.lux){ @@ -3626,10 +3627,10 @@ void MI32Show(bool json) } } if(p->bat!=0x00){ - WSContentSend_PD(HTTP_BATTERY, typeName, p->bat); + WSContentSend_PD(HTTP_MI32_BATTERY, typeName, p->bat); } if (p->feature.Btn){ - WSContentSend_PD(HTTP_LASTBUTTON, typeName, p->Btn); + WSContentSend_PD(HTTP_MI32_LASTBUTTON, typeName, p->Btn); } if (p->feature.flooding) { diff --git a/tasmota/tasmota_xx2c_global/xdrv_interface.ino b/tasmota/tasmota_xx2c_global/xdrv_interface.ino index 03ff1b2d9e2e..3e7fbef7bb12 100644 --- a/tasmota/tasmota_xx2c_global/xdrv_interface.ino +++ b/tasmota/tasmota_xx2c_global/xdrv_interface.ino @@ -1140,6 +1140,7 @@ bool XdrvCall(uint32_t function) { #endif // USE_PROFILE_FUNCTION for (uint32_t x = 0; x < xdrv_present; x++) { + TasmotaGlobal.NeedSeparatorLine = false; #ifdef USE_PROFILE_FUNCTION uint32_t profile_function_start = millis(); @@ -1159,9 +1160,10 @@ bool XdrvCall(uint32_t function) { if (FUNC_ACTIVE == function) { bitWrite(Xdrv_active[x / 32], x % 32, result); } - if (result && (function > FUNC_return_result)) { - break; - } + + if (result && (function > FUNC_return_result)) break; + + if (FUNC_WEB_SENSOR == function && TasmotaGlobal.NeedSeparatorLine) WSContentSend_P("

{e}"); } PROFILE_DRIVER("drv", function, profile_driver_start); diff --git a/tasmota/tasmota_xx2c_global/xsns_interface.ino b/tasmota/tasmota_xx2c_global/xsns_interface.ino index 2f020b92d3bd..83617f05ba0c 100644 --- a/tasmota/tasmota_xx2c_global/xsns_interface.ino +++ b/tasmota/tasmota_xx2c_global/xsns_interface.ino @@ -1123,6 +1123,7 @@ bool XsnsCall(uint32_t function) { for (uint32_t x = 0; x < xsns_present; x++) { if (XsnsEnabled(0, x)) { // Skip disabled sensor if ((FUNC_WEB_SENSOR == function) && !XsnsEnabled(1, x)) { continue; } // Skip web info for disabled sensors + TasmotaGlobal.NeedSeparatorLine = false; #ifdef USE_PROFILE_FUNCTION uint32_t profile_function_start = millis(); @@ -1139,9 +1140,9 @@ bool XsnsCall(uint32_t function) { PROFILE_FUNCTION("sns", index, function, profile_function_start); #endif // USE_PROFILE_FUNCTION - if (result && (function > FUNC_return_result)) { - break; - } + if (result && (function > FUNC_return_result)) break; + + if (FUNC_WEB_SENSOR == function && TasmotaGlobal.NeedSeparatorLine) WSContentSend_P("

{e}"); } }