From 3f68c0001e1d90853d63e5155eebf3eb0c396d82 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:49:38 +0200 Subject: [PATCH 1/6] formatting --- src/mqtt.cpp | 6 +++--- src/web/WebCustomizationService.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 284cf9748..63e52670a 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -988,7 +988,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // create the topic, depending on the type and whether the device entity is writable (a command) // https://developers.home-assistant.io/docs/core/entity char topic[MQTT_TOPIC_MAX_SIZE]; - // if it's a command then we can use Number, Switch. Otherwise stick to Sensor + // if it's a command then we can use Number, Switch, Select. Otherwise stick to Sensor if (has_cmd) { switch (type) { case DeviceValueType::INT: @@ -996,13 +996,13 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, case DeviceValueType::SHORT: case DeviceValueType::USHORT: case DeviceValueType::ULONG: - // number - https://www.home-assistant.io/integrations/number.mqtt/ + // number - https://www.home-assistant.io/integrations/number.mqtt // https://developers.home-assistant.io/docs/core/entity/number snprintf(topic, sizeof(topic), "number/%s/%s/config", mqtt_base_.c_str(), uniq); break; case DeviceValueType::BOOL: - // switch - https://www.home-assistant.io/integrations/switch.mqtt/ + // switch - https://www.home-assistant.io/integrations/switch.mqtt snprintf(topic, sizeof(topic), "switch/%s/%s/config", mqtt_base_.c_str(), uniq); break; case DeviceValueType::ENUM: diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 78a0616b5..89cc6af8a 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -208,7 +208,7 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request, J request->send(response); } -// takes a list of masked ids send from the webUI +// takes a list of masked ids sent from the webUI // saves it in the customization service // and updates the entity list real-time void WebCustomizationService::masked_entities(AsyncWebServerRequest * request, JsonVariant & json) { From cf10791c9504b28d86e218734856a9232d90c0d0 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:49:57 +0200 Subject: [PATCH 2/6] remove tooltip, add icons for fav and cmd --- interface/src/project/DashboardData.tsx | 32 +++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx index eccda938c..4023227fc 100644 --- a/interface/src/project/DashboardData.tsx +++ b/interface/src/project/DashboardData.tsx @@ -20,8 +20,7 @@ import { ListItem, ListItemText, Grid, - useMediaQuery, - Tooltip + useMediaQuery } from '@mui/material'; import TableCell, { tableCellClasses } from '@mui/material/TableCell'; @@ -38,6 +37,8 @@ import CancelIcon from '@mui/icons-material/Cancel'; import SendIcon from '@mui/icons-material/TrendingFlat'; import SaveIcon from '@mui/icons-material/Save'; import RemoveIcon from '@mui/icons-material/RemoveCircleOutline'; +import FavoriteIcon from '@mui/icons-material/Favorite'; +import PlayArrowIcon from '@mui/icons-material/PlayArrow'; import DeviceIcon from './DeviceIcon'; @@ -219,7 +220,7 @@ const DashboardData: FC = () => { {deviceValue.l && ( { {!deviceValue.l && ( { }; const renderNameCell = (dv: DeviceValue) => { + var mask = Number(dv.n.slice(0, 2)); + var name = dv.n.slice(2); if (dv.v === undefined && dv.c) { return ( - - command: {dv.n} + + {name}  + ); } + + if ((mask & 8) === 8) { + return ( + + {name}  + + + ); + } + return ( - {dv.n} + {name} ); }; @@ -526,9 +540,7 @@ const DashboardData: FC = () => { {dv.c && me.admin && ( - - - + )} From bad6346e7aac0b57478420ac5f24cc4216dbead8 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:50:06 +0200 Subject: [PATCH 3/6] update test data --- mock-api/server.js | 164 ++++++++++++++++++++++----------------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/mock-api/server.js b/mock-api/server.js index 2539f9a54..e227eda81 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -455,31 +455,31 @@ const emsesp_devicedata_1 = { { v: '(0)', u: 0, - n: 'error code', + n: '00error code', c: '', }, { v: '14:54:39 06/06/2021', u: 0, - n: 'date/time', + n: '00date/time', c: '', }, { v: 18, u: 1, - n: 'hc1 selected room temperature', + n: '00hc1 selected room temperature', c: 'hc1/seltemp', }, { v: 22.6, u: 1, - n: 'hc1 current room temperature', + n: '00hc1 current room temperature', c: '', }, { v: 'auto', u: 0, - n: 'hc1 mode', + n: '00hc1 mode', c: 'hc1/mode', }, ], @@ -488,81 +488,81 @@ const emsesp_devicedata_1 = { const emsesp_devicedata_2 = { label: 'Boiler: Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i', data: [ - { u: 0, n: 'reset', c: 'reset', l: ['-', 'maintenance', 'error'] }, - { v: 'false', u: 0, n: 'heating active' }, - { v: 'false', u: 0, n: 'tapwater active' }, - { v: 5, u: 1, n: 'selected flow temperature', c: 'selflowtemp' }, - { v: 0, u: 3, n: 'burner selected max power', c: 'selburnpow' }, - { v: 0, u: 3, n: 'heating pump modulation' }, - { v: 53.4, u: 1, n: 'current flow temperature' }, - { v: 52.7, u: 1, n: 'return temperature' }, - { v: 1.3, u: 10, n: 'system pressure' }, - { v: 54.9, u: 1, n: 'actual boiler temperature' }, - { v: 'false', u: 0, n: 'gas' }, - { v: 'false', u: 0, n: 'gas stage 2' }, - { v: 0, u: 9, n: 'flame current' }, - { v: 'false', u: 0, n: 'heating pump' }, - { v: 'false', u: 0, n: 'fan' }, - { v: 'false', u: 0, n: 'ignition' }, - { v: 'false', u: 0, n: 'oil preheating' }, - { v: 'true', u: 0, n: 'heating activated', c: 'heatingactivated', l: ['off', 'on'] }, - { v: 80, u: 1, n: 'heating temperature', c: 'heatingtemp' }, - { v: 70, u: 3, n: 'burner pump max power', c: 'pumpmodmax' }, - { v: 30, u: 3, n: 'burner pump min power', c: 'pumpmodmin' }, - { v: 1, u: 8, n: 'pump delay', c: 'pumpdelay' }, - { v: 10, u: 8, n: 'burner min period', c: 'burnminperiod' }, - { v: 0, u: 3, n: 'burner min power', c: 'burnminpower' }, - { v: 50, u: 3, n: 'burner max power', c: 'burnmaxpower' }, - { v: -6, u: 2, n: 'hysteresis on temperature', c: 'boilhyston' }, - { v: 6, u: 2, n: 'hysteresis off temperature', c: 'boilhystoff' }, - { v: 0, u: 1, n: 'set flow temperature' }, - { v: 0, u: 3, n: 'burner set power' }, - { v: 0, u: 3, n: 'burner current power' }, - { v: 326323, u: 0, n: 'burner starts' }, - { v: 553437, u: 8, n: 'total burner operating time' }, - { v: 451286, u: 8, n: 'total heat operating time' }, - { v: 4672173, u: 8, n: 'total UBA operating time' }, - { v: '1C(210) 06.06.2020 12:07 (0 min)', u: 0, n: 'last error code' }, - { v: '0H', u: 0, n: 'service code' }, - { v: 203, u: 0, n: 'service code number' }, - { v: 'H00', u: 0, n: 'maintenance message' }, - { v: 'manual', u: 0, n: 'maintenance scheduled', c: 'maintenance', l: ['off', 'time', 'date', 'manual'] }, - { v: 6000, u: 7, n: 'time to next maintenance', c: 'maintenancetime' }, - { v: '01.01.2012', u: 0, n: 'next maintenance date', c: 'maintenancedate', o: 'Format: < dd.mm.yyyy >' }, - { v: 'true', u: 0, n: 'dhw turn on/off', c: 'wwtapactivated', l: ['off', 'on'] }, - { v: 62, u: 1, n: 'dhw set temperature' }, - { v: 60, u: 1, n: 'dhw selected temperature', c: 'wwseltemp' }, - { v: 'flow', u: 0, n: 'dhw type' }, - { v: 'hot', u: 0, n: 'dhw comfort', c: 'wwcomfort', l: ['hot', 'eco', 'intelligent'] }, - { v: 40, u: 2, n: 'dhw flow temperature offset', c: 'wwflowtempoffset' }, - { v: 100, u: 3, n: 'dhw max power', c: 'wwmaxpower' }, - { v: 'false', u: 0, n: 'dhw circulation pump available', c: 'wwcircpump', l: ['off', 'on'] }, - { v: '3-way valve', u: 0, n: 'dhw charging type' }, - { v: -5, u: 2, n: 'dhw hysteresis on temperature', c: 'wwhyston' }, - { v: 0, u: 2, n: 'dhw hysteresis off temperature', c: 'wwhystoff' }, - { v: 70, u: 1, n: 'dhw disinfection temperature', c: 'wwdisinfectiontemp' }, + { v: 'false', u: 0, n: '08heating active' }, + { v: 'false', u: 0, n: '08tapwater active' }, + { u: 0, n: '00reset', c: 'reset', l: ['-', 'maintenance', 'error'] }, + { v: 5, u: 1, n: '00selected flow temperature', c: 'selflowtemp' }, + { v: 0, u: 3, n: '00burner selected max power', c: 'selburnpow' }, + { v: 0, u: 3, n: '00heating pump modulation' }, + { v: 53.4, u: 1, n: '00current flow temperature' }, + { v: 52.7, u: 1, n: '00return temperature' }, + { v: 1.3, u: 10, n: '00system pressure' }, + { v: 54.9, u: 1, n: '00actual boiler temperature' }, + { v: 'false', u: 0, n: '00gas' }, + { v: 'false', u: 0, n: '00gas stage 2' }, + { v: 0, u: 9, n: '00flame current' }, + { v: 'false', u: 0, n: '00heating pump' }, + { v: 'false', u: 0, n: '00fan' }, + { v: 'false', u: 0, n: '00ignition' }, + { v: 'false', u: 0, n: '00oil preheating' }, + { v: 'true', u: 0, n: '00heating activated', c: 'heatingactivated', l: ['off', 'on'] }, + { v: 80, u: 1, n: '00heating temperature', c: 'heatingtemp' }, + { v: 70, u: 3, n: '00burner pump max power', c: 'pumpmodmax' }, + { v: 30, u: 3, n: '00burner pump min power', c: 'pumpmodmin' }, + { v: 1, u: 8, n: '00pump delay', c: 'pumpdelay' }, + { v: 10, u: 8, n: '00burner min period', c: 'burnminperiod' }, + { v: 0, u: 3, n: '00burner min power', c: 'burnminpower' }, + { v: 50, u: 3, n: '00burner max power', c: 'burnmaxpower' }, + { v: -6, u: 2, n: '00hysteresis on temperature', c: 'boilhyston' }, + { v: 6, u: 2, n: '00hysteresis off temperature', c: 'boilhystoff' }, + { v: 0, u: 1, n: '00set flow temperature' }, + { v: 0, u: 3, n: '00burner set power' }, + { v: 0, u: 3, n: '00burner current power' }, + { v: 326323, u: 0, n: '00burner starts' }, + { v: 553437, u: 8, n: '00total burner operating time' }, + { v: 451286, u: 8, n: '00total heat operating time' }, + { v: 4672173, u: 8, n: '00total UBA operating time' }, + { v: '1C(210) 06.06.2020 12:07 (0 min)', u: 0, n: '00last error code' }, + { v: '0H', u: 0, n: '00service code' }, + { v: 203, u: 0, n: '00service code number' }, + { v: 'H00', u: 0, n: '00maintenance message' }, + { v: 'manual', u: 0, n: '00maintenance scheduled', c: 'maintenance', l: ['off', 'time', 'date', 'manual'] }, + { v: 6000, u: 7, n: '00time to next maintenance', c: 'maintenancetime' }, + { v: '01.01.2012', u: 0, n: '00next maintenance date', c: 'maintenancedate', o: 'Format: < dd.mm.yyyy >' }, + { v: 'true', u: 0, n: '00dhw turn on/off', c: 'wwtapactivated', l: ['off', 'on'] }, + { v: 62, u: 1, n: '00dhw set temperature' }, + { v: 60, u: 1, n: '00dhw selected temperature', c: 'wwseltemp' }, + { v: 'flow', u: 0, n: '00dhw type' }, + { v: 'hot', u: 0, n: '00dhw comfort', c: 'wwcomfort', l: ['hot', 'eco', 'intelligent'] }, + { v: 40, u: 2, n: '00dhw flow temperature offset', c: 'wwflowtempoffset' }, + { v: 100, u: 3, n: '00dhw max power', c: 'wwmaxpower' }, + { v: 'false', u: 0, n: '00dhw circulation pump available', c: 'wwcircpump', l: ['off', 'on'] }, + { v: '3-way valve', u: 0, n: '00dhw charging type' }, + { v: -5, u: 2, n: '00dhw hysteresis on temperature', c: 'wwhyston' }, + { v: 0, u: 2, n: '00dhw hysteresis off temperature', c: 'wwhystoff' }, + { v: 70, u: 1, n: '00dhw disinfection temperature', c: 'wwdisinfectiontemp' }, { v: 'off', u: 0, - n: 'dhw circulation pump mode', + n: '00dhw circulation pump mode', c: 'wwcircmode', l: ['off', '1x3min', '2x3min', '3x3min', '4x3min', '5x3min', '6x3min', 'continuous'], }, - { v: 'false', u: 0, n: 'dhw circulation active', c: 'wwcirc', l: ['off', 'on'] }, - { v: 47.3, u: 1, n: 'dhw current intern temperature' }, - { v: 0, u: 4, n: 'dhw current tap water flow' }, - { v: 47.3, u: 1, n: 'dhw storage intern temperature' }, - { v: 'true', u: 0, n: 'dhw activated', c: 'wwactivated', l: ['off', 'on'] }, - { v: 'false', u: 0, n: 'dhw one time charging', c: 'wwonetime', l: ['off', 'on'] }, - { v: 'false', u: 0, n: 'dhw disinfecting', c: 'wwdisinfecting', l: ['off', 'on'] }, - { v: 'false', u: 0, n: 'dhw charging' }, - { v: 'false', u: 0, n: 'dhw recharging' }, - { v: 'true', u: 0, n: 'dhw temperature ok' }, - { v: 'false', u: 0, n: 'dhw active' }, - { v: 'true', u: 0, n: 'dhw 3way valve active' }, - { v: 0, u: 3, n: 'dhw set pump power' }, - { v: 288768, u: 0, n: 'dhw starts' }, - { v: 102151, u: 8, n: 'dhw active time' }, + { v: 'false', u: 0, n: '00dhw circulation active', c: 'wwcirc', l: ['off', 'on'] }, + { v: 47.3, u: 1, n: '00dhw current intern temperature' }, + { v: 0, u: 4, n: '00dhw current tap water flow' }, + { v: 47.3, u: 1, n: '00dhw storage intern temperature' }, + { v: 'true', u: 0, n: '00dhw activated', c: 'wwactivated', l: ['off', 'on'] }, + { v: 'false', u: 0, n: '00dhw one time charging', c: 'wwonetime', l: ['off', 'on'] }, + { v: 'false', u: 0, n: '00dhw disinfecting', c: 'wwdisinfecting', l: ['off', 'on'] }, + { v: 'false', u: 0, n: '00dhw charging' }, + { v: 'false', u: 0, n: '00dhw recharging' }, + { v: 'true', u: 0, n: '00dhw temperature ok' }, + { v: 'false', u: 0, n: '00dhw active' }, + { v: 'true', u: 0, n: '00dhw 3way valve active' }, + { v: 0, u: 3, n: '00dhw set pump power' }, + { v: 288768, u: 0, n: '00dhw starts' }, + { v: 102151, u: 8, n: '00dhw active time' }, ], } @@ -572,19 +572,19 @@ const emsesp_devicedata_4 = { { v: 16, u: 1, - n: 'hc2 selected room temperature', + n: '00hc2 selected room temperature', c: 'hc2/seltemp', }, { v: 18.6, u: 1, - n: 'hc2 current room temperature', + n: '00hc2 current room temperature', c: '', }, { v: 'off', u: 0, - n: 'hc2 mode', + n: '00hc2 mode', c: 'hc2/mode', }, ], @@ -593,21 +593,21 @@ const emsesp_devicedata_4 = { const emsesp_deviceentities_1 = [ { v: '(0)', - n: 'error code', + n: '00error code', s: 'errorcode', m: 0, i: 1, }, { v: '14:54:39 06/06/2021', - n: 'date/time', + n: '00date/time', s: 'datetime', m: 0, i: 2, }, { v: 18.22, - n: 'hc1 selected room temperature', + n: '00hc1 selected room temperature', s: 'hc1/seltemp', m: 0, w: true, @@ -615,14 +615,14 @@ const emsesp_deviceentities_1 = [ }, { v: 22.6, - n: 'hc1 current room temperature', + n: '00hc1 current room temperature', s: 'hc1/curtemp', m: 0, i: 4, }, { v: 'auto', - n: 'hc1 mode', + n: '00hc1 mode', s: 'hc1/mode', m: 0, w: true, From 592c5ca7783ce7f7d6297ccd4f310c3bfe1127dd Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:50:33 +0200 Subject: [PATCH 4/6] fix devicevalue sorting the Michael way (thanks) --- src/emsdevice.cpp | 209 +++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 106 deletions(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 5e8c44174..ca5e147ae 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -637,119 +637,116 @@ void EMSdevice::generate_values_web(JsonObject & output) { output["label"] = to_string_short(); JsonArray data = output.createNestedArray("data"); - // sort the device values - std::sort(devicevalues_.begin(), devicevalues_.end(), [](const emsesp::DeviceValue & a, const emsesp::DeviceValue & b __attribute__((unused))) { - return a.has_state(DeviceValueState::DV_FAVORITE); - }); + // do two passes. First for all entities marked as favourites, then for all others. This sorts the list. + for (uint8_t i = 0; i < 2; i++) { + for (auto & dv : devicevalues_) { + bool state = (!i && dv.has_state(DeviceValueState::DV_FAVORITE)) || (i && !dv.has_state(DeviceValueState::DV_FAVORITE)); + if (state && (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD)))) { + JsonObject obj = data.createNestedObject(); // create the object, we know there is a value + uint8_t fahrenheit = 0; - for (auto & dv : devicevalues_) { - // check conditions: - // 1. full_name cannot be empty - // 2. it must have a valid value, if it is not a command like 'reset' + // handle Booleans (true, false) + if (dv.type == DeviceValueType::BOOL) { + bool value_b = *(bool *)(dv.value_p); + if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { + obj["v"] = value_b ? "true" : "false"; + } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { + obj["v"] = value_b ? 1 : 0; + } else { + char s[7]; + obj["v"] = Helpers::render_boolean(s, value_b); + } + } - if (!dv.has_state(DeviceValueState::DV_WEB_EXCLUDE) && dv.full_name && (dv.hasValue() || (dv.type == DeviceValueType::CMD))) { - JsonObject obj = data.createNestedObject(); // create the object, we know there is a value - uint8_t fahrenheit = 0; + // handle TEXT strings + else if (dv.type == DeviceValueType::STRING) { + obj["v"] = (char *)(dv.value_p); + } - // handle Booleans (true, false) - if (dv.type == DeviceValueType::BOOL) { - bool value_b = *(bool *)(dv.value_p); - if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { - obj["v"] = value_b ? "true" : "false"; - } else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) { - obj["v"] = value_b ? 1 : 0; + // handle ENUMs + else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { + obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; + } + + // handle numbers + else { + // If a divider is specified, do the division to 2 decimals places and send back as double/float + // otherwise force as an integer whole + // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler + int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; + + if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + obj["v"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); + } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { + uint32_t time_value = *(uint32_t *)(dv.value_p); + obj["v"] = (divider > 0) ? time_value / divider : time_value; // sometimes we need to divide by 60 + } + } + + // add the unit of measure (uom) + obj["u"] = fahrenheit ? (uint8_t)DeviceValueUOM::FAHRENHEIT : dv.uom; + + auto mask = Helpers::hextoa((uint8_t)(dv.state >> 4), false); // create mask to a 2-char string + + // add name, prefixing the tag if it exists + if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { + obj["n"] = mask + read_flash_string(dv.full_name); + } else if (dv.tag < DeviceValueTAG::TAG_HC1) { + obj["n"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); } else { - char s[7]; - obj["v"] = Helpers::render_boolean(s, value_b); + obj["n"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); } - } - // handle TEXT strings - else if (dv.type == DeviceValueType::STRING) { - obj["v"] = (char *)(dv.value_p); - } - - // handle ENUMs - else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) { - obj["v"] = dv.options[*(uint8_t *)(dv.value_p)]; - } - - // handle numbers - else { - // If a divider is specified, do the division to 2 decimals places and send back as double/float - // otherwise force as an integer whole - // the nested if's is necessary due to the way the ArduinoJson templates are pre-processed by the compiler - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (dv.uom == DeviceValueUOM::DEGREES) ? 2 : (dv.uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; - - if ((dv.type == DeviceValueType::INT) && Helpers::hasValue(*(int8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int8_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::UINT) && Helpers::hasValue(*(uint8_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint8_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::SHORT) && Helpers::hasValue(*(int16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(int16_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::USHORT) && Helpers::hasValue(*(uint16_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint16_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::ULONG) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - obj["v"] = Helpers::round2(*(uint32_t *)(dv.value_p), divider, fahrenheit); - } else if ((dv.type == DeviceValueType::TIME) && Helpers::hasValue(*(uint32_t *)(dv.value_p))) { - uint32_t time_value = *(uint32_t *)(dv.value_p); - obj["v"] = (divider > 0) ? time_value / divider : time_value; // sometimes we need to divide by 60 - } - } - - // add the unit of measure (uom) - obj["u"] = fahrenheit ? (uint8_t)DeviceValueUOM::FAHRENHEIT : dv.uom; - - // add name, prefixing the tag if it exists - if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) { - obj["n"] = dv.full_name; - } else if (dv.tag < DeviceValueTAG::TAG_HC1) { - obj["n"] = tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); - } else { - obj["n"] = tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name); - } - - // add commands and options - if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { - // add the name of the Command function - if (dv.tag >= DeviceValueTAG::TAG_HC1) { - obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); - } else { - obj["c"] = dv.short_name; - } - // add the Command options - if (dv.type == DeviceValueType::ENUM || (dv.type == DeviceValueType::CMD && dv.options_size > 1)) { - JsonArray l = obj.createNestedArray("l"); - for (uint8_t i = 0; i < dv.options_size; i++) { - if (!read_flash_string(dv.options[i]).empty()) { - l.add(read_flash_string(dv.options[i])); + // add commands and options + if (dv.has_cmd && !dv.has_state(DeviceValueState::DV_READONLY)) { + // add the name of the Command function + if (dv.tag >= DeviceValueTAG::TAG_HC1) { + obj["c"] = tag_to_mqtt(dv.tag) + "/" + read_flash_string(dv.short_name); + } else { + obj["c"] = dv.short_name; + } + // add the Command options + if (dv.type == DeviceValueType::ENUM || (dv.type == DeviceValueType::CMD && dv.options_size > 1)) { + JsonArray l = obj.createNestedArray("l"); + for (uint8_t i = 0; i < dv.options_size; i++) { + if (!read_flash_string(dv.options[i]).empty()) { + l.add(read_flash_string(dv.options[i])); + } + } + } else if (dv.type == DeviceValueType::BOOL) { + JsonArray l = obj.createNestedArray("l"); + l.add("off"); + l.add("on"); + } + // add command help template + else if (dv.type == DeviceValueType::STRING || dv.type == DeviceValueType::CMD) { + if (dv.options_size == 1) { + obj["h"] = dv.options[0]; } } - } else if (dv.type == DeviceValueType::BOOL) { - JsonArray l = obj.createNestedArray("l"); - l.add("off"); - l.add("on"); - } - // add command help template - else if (dv.type == DeviceValueType::STRING || dv.type == DeviceValueType::CMD) { - if (dv.options_size == 1) { - obj["h"] = dv.options[0]; - } - } - // add steps to numeric values with divider/multiplier - else { - int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; - char s[10]; - if (divider > 0) { - obj["s"] = Helpers::render_value(s, (float)1 / divider, 1); - } else if (divider < 0) { - obj["s"] = Helpers::render_value(s, (-1) * divider, 0); - } - int16_t dv_set_min, dv_set_max; - if (dv.get_min_max(dv_set_min, dv_set_max)) { - obj["m"] = Helpers::render_value(s, dv_set_min, 0); - obj["x"] = Helpers::render_value(s, dv_set_max, 0); + // add steps to numeric values with divider/multiplier + else { + int8_t divider = (dv.options_size == 1) ? Helpers::atoint(read_flash_string(dv.options[0]).c_str()) : 0; + char s[10]; + if (divider > 0) { + obj["s"] = Helpers::render_value(s, (float)1 / divider, 1); + } else if (divider < 0) { + obj["s"] = Helpers::render_value(s, (-1) * divider, 0); + } + int16_t dv_set_min, dv_set_max; + if (dv.get_min_max(dv_set_min, dv_set_max)) { + obj["m"] = Helpers::render_value(s, dv_set_min, 0); + obj["x"] = Helpers::render_value(s, dv_set_max, 0); + } } } } @@ -853,7 +850,7 @@ void EMSdevice::generate_values_web_all(JsonArray & output) { // this is called before loading in the exclude entities list from the customization service void EMSdevice::reset_entity_masks() { for (auto & dv : devicevalues_) { - dv.state &= 0x0F; + dv.state &= 0x0F; // clear high nibble } } From 1cc031b27b224661a1936f26991413a0bed6c08a Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:50:51 +0200 Subject: [PATCH 5/6] minor optimizations --- .../src/project/SettingsCustomization.tsx | 47 +++++++------------ 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index 368ec39c9..baf3a7480 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -14,8 +14,7 @@ import { DialogContent, DialogTitle, ToggleButton, - ToggleButtonGroup, - Tooltip + ToggleButtonGroup } from '@mui/material'; import TableCell, { tableCellClasses } from '@mui/material/TableCell'; @@ -117,10 +116,14 @@ const SettingsCustomization: FC = () => { return ( <> - + - You can mark an entity as a favorite to be listed first in the Web Dashboard, or remove it from the - Dashboard, or disable it's write operation or exclude it from the MQTT and API outputs. + You can mark an entity as a favorite to be listed first in the Dashboard ( + ) ,or remove it entirely from the Dashboard ( + ) ,or disable it's write operation ( + ) or have it excluded from the MQTT and API outputs ( + + ). { const setMask = (de: DeviceEntity, newMask: string[]) => { var new_mask = 0; - if (newMask.includes('1')) { - new_mask |= 1; + for (let entry of newMask) { + new_mask |= Number(entry); } - if (newMask.includes('2')) { - new_mask |= 2; - } - if (newMask.includes('4')) { - new_mask |= 4; - } - if (newMask.includes('8')) { - new_mask |= 8; - } - de.m = new_mask; setMasks(newMask); }; @@ -220,35 +213,27 @@ const SettingsCustomization: FC = () => { {deviceEntities.map((de) => ( - + { setMask(de, mask); }} > - - - + - - - + - - - + - - - + From 86430c640824496fa68546b55aa719efc8801606 Mon Sep 17 00:00:00 2001 From: proddy Date: Mon, 28 Mar 2022 17:52:07 +0200 Subject: [PATCH 6/6] updated packages --- interface/package-lock.json | 92 +++++++++++++++++++------------------ interface/package.json | 2 +- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/interface/package-lock.json b/interface/package-lock.json index fe89c4fac..313bff332 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -12,7 +12,7 @@ "@emotion/styled": "^11.8.1", "@msgpack/msgpack": "^2.7.2", "@mui/icons-material": "^5.5.1", - "@mui/material": "^5.5.2", + "@mui/material": "^5.5.3", "@types/lodash": "^4.14.180", "@types/node": "^17.0.23", "@types/react": "^17.0.43", @@ -2849,13 +2849,14 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-alpha.73", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.73.tgz", - "integrity": "sha512-TEUCIIEAWrngAqpIa+dY3nofGSNj70LC3KC9WcCzyXPK3M4AG2GNi7ndd/g/0DtC55kbxrudzlV8TG3vrB2Vjw==", + "version": "5.0.0-alpha.74", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.74.tgz", + "integrity": "sha512-pw3T1xNXpW8pLo9+BvtyazZb0CSjNJsjbzznlbV/aNkBfjNPXQVI3X1NDm3WSI8y6M96WDIVO7XrHAohOwALSQ==", "dependencies": { "@babel/runtime": "^7.17.2", "@emotion/is-prop-valid": "^1.1.2", - "@mui/utils": "^5.4.4", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.5.3", "@popperjs/core": "^2.11.4", "clsx": "^1.1.1", "prop-types": "^15.7.2", @@ -2905,15 +2906,15 @@ } }, "node_modules/@mui/material": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.2.tgz", - "integrity": "sha512-r4p1u9eDlSqW3TS/Iq9yolifWHpuW6e0BSeqEJW3EEIcKfPVVk4WNUNJ+s8DtN7dBoDcveXxcQVVjYXTIv1d9g==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.3.tgz", + "integrity": "sha512-eADa3kUYbbr1jNjcufn0a7HeU8cSo0agbrkj720hodxVFNIfzq7a2e58Z+PaZqll55kMGBvlYJ7rTcXU399x5A==", "dependencies": { "@babel/runtime": "^7.17.2", - "@mui/base": "5.0.0-alpha.73", - "@mui/system": "^5.5.2", + "@mui/base": "5.0.0-alpha.74", + "@mui/system": "^5.5.3", "@mui/types": "^7.1.3", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "@types/react-transition-group": "^4.4.4", "clsx": "^1.1.1", "csstype": "^3.0.11", @@ -2949,12 +2950,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.4.4.tgz", - "integrity": "sha512-V/gxttr6736yJoU9q+4xxXsa0K/w9Hn9pg99zsOHt7i/O904w2CX5NHh5WqDXtoUzVcayLF0RB17yr6l79CE+A==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.5.3.tgz", + "integrity": "sha512-Wf7NurY7lk8SBWelSBY2U02zxLt1773JpIcXTHuEC9/GZdQA4CXCJGl2cVQzheKhee5rZ+8JwGulrRiVl1m+4A==", "dependencies": { "@babel/runtime": "^7.17.2", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "prop-types": "^15.7.2" }, "engines": { @@ -3005,15 +3006,15 @@ } }, "node_modules/@mui/system": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.2.tgz", - "integrity": "sha512-OATYFI36nliud8xh0u+ZNqDo0jWjxpO0vZLlzqNB+ZtkR5Q/+1X3GgboA9ruiB8Rq+udnJlMBQNGW0qqjvAOHQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.3.tgz", + "integrity": "sha512-J9JcySJuEqfEoP334K/2gEWm2vOx73Uqjii3qlFVhWRBOAJ0Pjyk0sN5W/eVRbwhUm95DNgh2V5s8dRK3vzyVw==", "dependencies": { "@babel/runtime": "^7.17.2", - "@mui/private-theming": "^5.4.4", + "@mui/private-theming": "^5.5.3", "@mui/styled-engine": "^5.5.2", "@mui/types": "^7.1.3", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "clsx": "^1.1.1", "csstype": "^3.0.11", "prop-types": "^15.7.2" @@ -3057,9 +3058,9 @@ } }, "node_modules/@mui/utils": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.4.4.tgz", - "integrity": "sha512-hfYIXEuhc2mXMGN5nUPis8beH6uE/zl3uMWJcyHX0/LN/+QxO9zhYuV6l8AsAaphHFyS/fBv0SW3Nid7jw5hKQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.5.3.tgz", + "integrity": "sha512-t627eVRpl3SlxVya0cIVNs8jPl4KCEiGaTSWY9iKKTcMNaeDbuRML+zv/CFHDPr1zFv+FjJSP02ySB+tZ8xIag==", "dependencies": { "@babel/runtime": "^7.17.2", "@types/prop-types": "^15.7.4", @@ -19706,13 +19707,14 @@ "integrity": "sha512-rYEi46+gIzufyYUAoHDnRzkWGxajpD9vVXFQ3g1vbjrBm6P7MBmm+s/fqPa46sxa+8FOUdEuRQKaugo5a4JWpw==" }, "@mui/base": { - "version": "5.0.0-alpha.73", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.73.tgz", - "integrity": "sha512-TEUCIIEAWrngAqpIa+dY3nofGSNj70LC3KC9WcCzyXPK3M4AG2GNi7ndd/g/0DtC55kbxrudzlV8TG3vrB2Vjw==", + "version": "5.0.0-alpha.74", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.74.tgz", + "integrity": "sha512-pw3T1xNXpW8pLo9+BvtyazZb0CSjNJsjbzznlbV/aNkBfjNPXQVI3X1NDm3WSI8y6M96WDIVO7XrHAohOwALSQ==", "requires": { "@babel/runtime": "^7.17.2", "@emotion/is-prop-valid": "^1.1.2", - "@mui/utils": "^5.4.4", + "@mui/types": "^7.1.3", + "@mui/utils": "^5.5.3", "@popperjs/core": "^2.11.4", "clsx": "^1.1.1", "prop-types": "^15.7.2", @@ -19728,15 +19730,15 @@ } }, "@mui/material": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.2.tgz", - "integrity": "sha512-r4p1u9eDlSqW3TS/Iq9yolifWHpuW6e0BSeqEJW3EEIcKfPVVk4WNUNJ+s8DtN7dBoDcveXxcQVVjYXTIv1d9g==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.5.3.tgz", + "integrity": "sha512-eADa3kUYbbr1jNjcufn0a7HeU8cSo0agbrkj720hodxVFNIfzq7a2e58Z+PaZqll55kMGBvlYJ7rTcXU399x5A==", "requires": { "@babel/runtime": "^7.17.2", - "@mui/base": "5.0.0-alpha.73", - "@mui/system": "^5.5.2", + "@mui/base": "5.0.0-alpha.74", + "@mui/system": "^5.5.3", "@mui/types": "^7.1.3", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "@types/react-transition-group": "^4.4.4", "clsx": "^1.1.1", "csstype": "^3.0.11", @@ -19747,12 +19749,12 @@ } }, "@mui/private-theming": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.4.4.tgz", - "integrity": "sha512-V/gxttr6736yJoU9q+4xxXsa0K/w9Hn9pg99zsOHt7i/O904w2CX5NHh5WqDXtoUzVcayLF0RB17yr6l79CE+A==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.5.3.tgz", + "integrity": "sha512-Wf7NurY7lk8SBWelSBY2U02zxLt1773JpIcXTHuEC9/GZdQA4CXCJGl2cVQzheKhee5rZ+8JwGulrRiVl1m+4A==", "requires": { "@babel/runtime": "^7.17.2", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "prop-types": "^15.7.2" } }, @@ -19767,15 +19769,15 @@ } }, "@mui/system": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.2.tgz", - "integrity": "sha512-OATYFI36nliud8xh0u+ZNqDo0jWjxpO0vZLlzqNB+ZtkR5Q/+1X3GgboA9ruiB8Rq+udnJlMBQNGW0qqjvAOHQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.5.3.tgz", + "integrity": "sha512-J9JcySJuEqfEoP334K/2gEWm2vOx73Uqjii3qlFVhWRBOAJ0Pjyk0sN5W/eVRbwhUm95DNgh2V5s8dRK3vzyVw==", "requires": { "@babel/runtime": "^7.17.2", - "@mui/private-theming": "^5.4.4", + "@mui/private-theming": "^5.5.3", "@mui/styled-engine": "^5.5.2", "@mui/types": "^7.1.3", - "@mui/utils": "^5.4.4", + "@mui/utils": "^5.5.3", "clsx": "^1.1.1", "csstype": "^3.0.11", "prop-types": "^15.7.2" @@ -19788,9 +19790,9 @@ "requires": {} }, "@mui/utils": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.4.4.tgz", - "integrity": "sha512-hfYIXEuhc2mXMGN5nUPis8beH6uE/zl3uMWJcyHX0/LN/+QxO9zhYuV6l8AsAaphHFyS/fBv0SW3Nid7jw5hKQ==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.5.3.tgz", + "integrity": "sha512-t627eVRpl3SlxVya0cIVNs8jPl4KCEiGaTSWY9iKKTcMNaeDbuRML+zv/CFHDPr1zFv+FjJSP02ySB+tZ8xIag==", "requires": { "@babel/runtime": "^7.17.2", "@types/prop-types": "^15.7.4", diff --git a/interface/package.json b/interface/package.json index 8a82ef70d..2cdaa7403 100644 --- a/interface/package.json +++ b/interface/package.json @@ -8,7 +8,7 @@ "@emotion/styled": "^11.8.1", "@msgpack/msgpack": "^2.7.2", "@mui/icons-material": "^5.5.1", - "@mui/material": "^5.5.2", + "@mui/material": "^5.5.3", "@types/lodash": "^4.14.180", "@types/node": "^17.0.23", "@types/react": "^17.0.43",