diff --git a/interface/.typesafe-i18n.json b/interface/.typesafe-i18n.json index d3f04322e..50a90e48b 100644 --- a/interface/.typesafe-i18n.json +++ b/interface/.typesafe-i18n.json @@ -1,5 +1,5 @@ { - "adapter": "react", - "baseLocale": "en", - "$schema": "https://unpkg.com/typesafe-i18n@5.14.0/schema/typesafe-i18n.json" -} \ No newline at end of file + "adapter": "react", + "baseLocale": "en", + "$schema": "https://unpkg.com/typesafe-i18n@5.14.0/schema/typesafe-i18n.json" +} diff --git a/interface/package-lock.json b/interface/package-lock.json index 2dad40071..6e6893306 100644 --- a/interface/package-lock.json +++ b/interface/package-lock.json @@ -12,10 +12,10 @@ "@emotion/styled": "^11.10.4", "@msgpack/msgpack": "^2.8.0", "@mui/icons-material": "^5.10.6", - "@mui/material": "^5.10.7", + "@mui/material": "^5.10.8", "@table-library/react-table-library": "4.0.18", "@types/lodash": "^4.14.186", - "@types/node": "^18.7.23", + "@types/node": "^18.8.2", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", "@types/react-router-dom": "^5.3.3", @@ -3103,9 +3103,9 @@ } }, "node_modules/@mui/base": { - "version": "5.0.0-alpha.99", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.99.tgz", - "integrity": "sha512-D04H6O1c0Jv561yI0SVbpa8MpqpW3G43CwJxV2o6ALfI0DMJ45w07dGafmDchb6aCWTRTdggd3rjgmuzyNwPiQ==", + "version": "5.0.0-alpha.100", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.100.tgz", + "integrity": "sha512-bSoJEKCENtmJrJDECHUe9PiqztIUACuSskyqw9ypqE7Dz3WxL3e8puFsWBkUsz+WOCjXh4B4Xljn88Ucxxv5HA==", "dependencies": { "@babel/runtime": "^7.19.0", "@emotion/is-prop-valid": "^1.2.0", @@ -3135,9 +3135,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.7.tgz", - "integrity": "sha512-3N0UYVy3MbrHzM3j6f7fIUCZ+bQ1/sSZq143tLxwSssW3Z4AqE83brpr5flEY1Lx+Aowv/cPyQMmZxzRlFCGqw==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.8.tgz", + "integrity": "sha512-V5D7OInO4P9PdT/JACg7fwjbOORm3GklaMVgdGomjyxiyetgRND5CC9r35e1LK/DqHdoyDuhbFzdfrqWtpmEIw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui" @@ -3169,14 +3169,14 @@ } }, "node_modules/@mui/material": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.7.tgz", - "integrity": "sha512-o1jcQGii+q7ORrXhBiMmGzFDaboc1qTgOOC3zDW+NR9ryVzWzL7qEeqoORbgDB5zk9OBsXCjB91fUH/ls5xMwg==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.8.tgz", + "integrity": "sha512-sF/Ka0IJjGXV52zoT4xAWEqXVRjNYbIjATo9L4Q5oQC5iJpGrKJFY16uNtWWB0+vp/nayAuPGZHrxtV+t3ecdQ==", "dependencies": { "@babel/runtime": "^7.19.0", - "@mui/base": "5.0.0-alpha.99", - "@mui/core-downloads-tracker": "^5.10.7", - "@mui/system": "^5.10.7", + "@mui/base": "5.0.0-alpha.100", + "@mui/core-downloads-tracker": "^5.10.8", + "@mui/system": "^5.10.8", "@mui/types": "^7.2.0", "@mui/utils": "^5.10.6", "@types/react-transition-group": "^4.4.5", @@ -3239,9 +3239,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.7.tgz", - "integrity": "sha512-CCrtW+vvCKEm6pOE/QcutQ+ORC/iE6D1ghscN4l7LE2JXPvTXO/z0yu8Wxug1JEDlWm4r1Qa0PzJe1P9bjKzNA==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz", + "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==", "dependencies": { "@babel/runtime": "^7.19.0", "@emotion/cache": "^11.10.3", @@ -3270,13 +3270,13 @@ } }, "node_modules/@mui/system": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.7.tgz", - "integrity": "sha512-kwyhjjKGsgtBRFl6vSqidDZcNKU5S1juTgm4Xi2fyWxaEbIQb9Sh9y0iVP2bNCJzgDr0alLaENOZOEaDWHISAQ==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.8.tgz", + "integrity": "sha512-hRQ354zcrYP/KHqK8FheICSvE9raQaUgQaV+A3oD4JETaFUCVI9Ytt+RcQYgTqx02xlCXIjl8LK1rPjTneySqw==", "dependencies": { "@babel/runtime": "^7.19.0", "@mui/private-theming": "^5.10.6", - "@mui/styled-engine": "^5.10.7", + "@mui/styled-engine": "^5.10.8", "@mui/types": "^7.2.0", "@mui/utils": "^5.10.6", "clsx": "^1.2.1", @@ -4029,9 +4029,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "node_modules/@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" + "version": "18.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.2.tgz", + "integrity": "sha512-cRMwIgdDN43GO4xMWAfJAecYn8wV4JbsOGHNfNUIDiuYkUYAR5ec4Rj7IO2SAhFPEfpPtLtUTbbny/TCT7aDwA==" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -19643,9 +19643,9 @@ "integrity": "sha512-h9u4u/jiIRKbq25PM+zymTyW6bhTzELvOoUd+AvYriWOAKpLGnIamaET3pnHYoI5iYphAHBI4ayx0MehR+VVPQ==" }, "@mui/base": { - "version": "5.0.0-alpha.99", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.99.tgz", - "integrity": "sha512-D04H6O1c0Jv561yI0SVbpa8MpqpW3G43CwJxV2o6ALfI0DMJ45w07dGafmDchb6aCWTRTdggd3rjgmuzyNwPiQ==", + "version": "5.0.0-alpha.100", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.100.tgz", + "integrity": "sha512-bSoJEKCENtmJrJDECHUe9PiqztIUACuSskyqw9ypqE7Dz3WxL3e8puFsWBkUsz+WOCjXh4B4Xljn88Ucxxv5HA==", "requires": { "@babel/runtime": "^7.19.0", "@emotion/is-prop-valid": "^1.2.0", @@ -19658,9 +19658,9 @@ } }, "@mui/core-downloads-tracker": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.7.tgz", - "integrity": "sha512-3N0UYVy3MbrHzM3j6f7fIUCZ+bQ1/sSZq143tLxwSssW3Z4AqE83brpr5flEY1Lx+Aowv/cPyQMmZxzRlFCGqw==" + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.10.8.tgz", + "integrity": "sha512-V5D7OInO4P9PdT/JACg7fwjbOORm3GklaMVgdGomjyxiyetgRND5CC9r35e1LK/DqHdoyDuhbFzdfrqWtpmEIw==" }, "@mui/icons-material": { "version": "5.10.6", @@ -19671,14 +19671,14 @@ } }, "@mui/material": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.7.tgz", - "integrity": "sha512-o1jcQGii+q7ORrXhBiMmGzFDaboc1qTgOOC3zDW+NR9ryVzWzL7qEeqoORbgDB5zk9OBsXCjB91fUH/ls5xMwg==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.10.8.tgz", + "integrity": "sha512-sF/Ka0IJjGXV52zoT4xAWEqXVRjNYbIjATo9L4Q5oQC5iJpGrKJFY16uNtWWB0+vp/nayAuPGZHrxtV+t3ecdQ==", "requires": { "@babel/runtime": "^7.19.0", - "@mui/base": "5.0.0-alpha.99", - "@mui/core-downloads-tracker": "^5.10.7", - "@mui/system": "^5.10.7", + "@mui/base": "5.0.0-alpha.100", + "@mui/core-downloads-tracker": "^5.10.8", + "@mui/system": "^5.10.8", "@mui/types": "^7.2.0", "@mui/utils": "^5.10.6", "@types/react-transition-group": "^4.4.5", @@ -19700,9 +19700,9 @@ } }, "@mui/styled-engine": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.7.tgz", - "integrity": "sha512-CCrtW+vvCKEm6pOE/QcutQ+ORC/iE6D1ghscN4l7LE2JXPvTXO/z0yu8Wxug1JEDlWm4r1Qa0PzJe1P9bjKzNA==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.10.8.tgz", + "integrity": "sha512-w+y8WI18EJV6zM/q41ug19cE70JTeO6sWFsQ7tgePQFpy6ToCVPh0YLrtqxUZXSoMStW5FMw0t9fHTFAqPbngw==", "requires": { "@babel/runtime": "^7.19.0", "@emotion/cache": "^11.10.3", @@ -19711,13 +19711,13 @@ } }, "@mui/system": { - "version": "5.10.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.7.tgz", - "integrity": "sha512-kwyhjjKGsgtBRFl6vSqidDZcNKU5S1juTgm4Xi2fyWxaEbIQb9Sh9y0iVP2bNCJzgDr0alLaENOZOEaDWHISAQ==", + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.10.8.tgz", + "integrity": "sha512-hRQ354zcrYP/KHqK8FheICSvE9raQaUgQaV+A3oD4JETaFUCVI9Ytt+RcQYgTqx02xlCXIjl8LK1rPjTneySqw==", "requires": { "@babel/runtime": "^7.19.0", "@mui/private-theming": "^5.10.6", - "@mui/styled-engine": "^5.10.7", + "@mui/styled-engine": "^5.10.8", "@mui/types": "^7.2.0", "@mui/utils": "^5.10.6", "clsx": "^1.2.1", @@ -20233,9 +20233,9 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==" }, "@types/node": { - "version": "18.7.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz", - "integrity": "sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==" + "version": "18.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.2.tgz", + "integrity": "sha512-cRMwIgdDN43GO4xMWAfJAecYn8wV4JbsOGHNfNUIDiuYkUYAR5ec4Rj7IO2SAhFPEfpPtLtUTbbny/TCT7aDwA==" }, "@types/parse-json": { "version": "4.0.0", diff --git a/interface/package.json b/interface/package.json index 075122eca..1b97bef90 100644 --- a/interface/package.json +++ b/interface/package.json @@ -8,10 +8,10 @@ "@emotion/styled": "^11.10.4", "@msgpack/msgpack": "^2.8.0", "@mui/icons-material": "^5.10.6", - "@mui/material": "^5.10.7", + "@mui/material": "^5.10.8", "@table-library/react-table-library": "4.0.18", "@types/lodash": "^4.14.186", - "@types/node": "^18.7.23", + "@types/node": "^18.8.2", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", "@types/react-router-dom": "^5.3.3", diff --git a/interface/src/framework/mqtt/MqttStatusForm.tsx b/interface/src/framework/mqtt/MqttStatusForm.tsx index a889ec0fa..825f76731 100644 --- a/interface/src/framework/mqtt/MqttStatusForm.tsx +++ b/interface/src/framework/mqtt/MqttStatusForm.tsx @@ -5,6 +5,7 @@ import DeviceHubIcon from '@mui/icons-material/DeviceHub'; import RefreshIcon from '@mui/icons-material/Refresh'; import ReportIcon from '@mui/icons-material/Report'; import SpeakerNotesOffIcon from '@mui/icons-material/SpeakerNotesOff'; +import AutoAwesomeMotionIcon from '@mui/icons-material/AutoAwesomeMotion'; import { ButtonRow, FormLoader, SectionContent } from '../../components'; import { MqttStatus, MqttDisconnectReason } from '../../types'; @@ -31,6 +32,12 @@ export const mqttPublishHighlight = ({ mqtt_fails }: MqttStatus, theme: Theme) = return theme.palette.error.main; }; +export const mqttQueueHighlight = ({ mqtt_queued }: MqttStatus, theme: Theme) => { + if (mqtt_queued <= 1) return theme.palette.success.main; + + return theme.palette.warning.main; +}; + const MqttStatusForm: FC = () => { const { loadData, data, errorMessage } = useRest({ read: MqttApi.readMqttStatus }); @@ -38,14 +45,14 @@ const MqttStatusForm: FC = () => { const theme = useTheme(); - const mqttStatus = ({ enabled, connected }: MqttStatus) => { + const mqttStatus = ({ enabled, connected, connect_count }: MqttStatus) => { if (!enabled) { return LL.NOT_ENABLED(); } if (connected) { - return LL.CONNECTED(); + return LL.CONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : ''); } - return LL.DISCONNECTED(); + return LL.DISCONNECTED() + (connect_count > 1 ? ' (' + connect_count + ')' : ''); }; const disconnectReason = ({ disconnect_reason }: MqttStatus) => { @@ -77,36 +84,44 @@ const MqttStatusForm: FC = () => { } const renderConnectionStatus = () => { - if (data.connected) { - return ( - <> - - - # - - - - - - - - - - - - - - ); - } return ( <> + {!data.connected && ( + <> + + + + + + + + + + + )} - - + # + + + + + + + + - + + + + + + + + + + diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx index c60c4eed9..6bfe28887 100644 --- a/interface/src/project/DashboardData.tsx +++ b/interface/src/project/DashboardData.tsx @@ -508,7 +508,7 @@ const DashboardData: FC = () => { { } function formatName(de: DeviceEntity) { - if (de.n === undefined || de.n === de.id) { - return de.id; - } - - if (de.n[0] === '!') { - return LL.COMMAND() + ': ' + de.n.slice(1); + if (de.n === undefined) { + return ( + <> + ( + + {de.id} + + ) + + ); } return ( <> - {de.cn !== undefined && de.cn !== '' ? de.cn : de.n} + {de.n[0] === '!' ? LL.COMMAND() + ': ' + de.n.slice(1) : de.cn !== undefined && de.cn !== '' ? de.cn : de.n}  ( {de.id} @@ -324,7 +328,7 @@ const SettingsCustomization: FC = () => { }; const editEntity = (de: DeviceEntity) => { - if (de.n && de.n[0] === '!') { + if (de.n === undefined || (de.n && de.n[0] === '!')) { return; } diff --git a/interface/src/types/mqtt.ts b/interface/src/types/mqtt.ts index 1e2b50a00..0e8a10eec 100644 --- a/interface/src/types/mqtt.ts +++ b/interface/src/types/mqtt.ts @@ -15,6 +15,8 @@ export interface MqttStatus { client_id: string; disconnect_reason: MqttDisconnectReason; mqtt_fails: number; + mqtt_queued: number; + connect_count: number; } export interface MqttSettings { diff --git a/lib/framework/MqttStatus.cpp b/lib/framework/MqttStatus.cpp index dc75cc9fc..c5ff2a05c 100644 --- a/lib/framework/MqttStatus.cpp +++ b/lib/framework/MqttStatus.cpp @@ -20,7 +20,9 @@ void MqttStatus::mqttStatus(AsyncWebServerRequest * request) { root["client_id"] = _mqttSettingsService->getClientId(); root["disconnect_reason"] = (uint8_t)_mqttSettingsService->getDisconnectReason(); - root["mqtt_fails"] = emsesp::Mqtt::publish_fails(); // proddy added + root["mqtt_queued"] = emsesp::Mqtt::publish_queued(); // mdvp added + root["mqtt_fails"] = emsesp::Mqtt::publish_fails(); // proddy added + root["connect_count"] = emsesp::Mqtt::connect_count(); // mdvp added response->setLength(); request->send(response); diff --git a/mock-api/server.js b/mock-api/server.js index 75d799ea0..33d218ec9 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -240,6 +240,8 @@ const mqtt_status = { client_id: 'ems-esp', disconnect_reason: 0, mqtt_fails: 0, + mqtt_queued: 1, + connect_count: 2, } // SYSTEM diff --git a/scripts/rename_fw.py b/scripts/rename_fw.py index 371aeab45..07a944567 100644 --- a/scripts/rename_fw.py +++ b/scripts/rename_fw.py @@ -19,7 +19,9 @@ def bin_copy(source, target, env): app_version = bag.get('app_version') platform = "ESP32" + chip_target = env.get('PIOENV').upper() + # this breaks the CI so removed # flash_size = env["PIOENV"].split('_')[1] # print(env.Dump()) @@ -31,14 +33,12 @@ def bin_copy(source, target, env): # alternatively take platform from the pio target # platform = str(target[0]).split(os.path.sep)[2] - print("app version: "+app_version) - print("platform: "+platform) - # print("flash size: "+flash_size) + print("app version: " + app_version) + print("platform: " + platform) + print("chip_target: " + chip_target) # convert . to _ so Windows doesn't complain - variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + platform - - # variant = "EMS-ESP-" + app_version.replace(".", "_") + "-" + platform + "_" + flash_size + variant = "EMS-ESP-" + chip_target + "-" + app_version.replace(".", "_") # check if output directories exist and create if necessary if not os.path.isdir(OUTPUT_DIR): diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 2d6708042..091df787e 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -522,7 +522,7 @@ void Thermostat::process_RC10Set(std::shared_ptr telegram) { if (hc == nullptr) { return; } - has_update(telegram, ibaClockOffset_, 0); + has_update(telegram, ibaCalIntTemperature_, 0); has_update(telegram, backlight_, 1); has_update(telegram, wwMode_, 2); has_update(telegram, hc->nighttemp, 3); @@ -1102,6 +1102,7 @@ void Thermostat::process_RC300OutdoorTemp(std::shared_ptr telegr // 0x240 RC300 parameter void Thermostat::process_RC300Settings(std::shared_ptr telegram) { + has_update(telegram, ibaCalIntTemperature_, 7); has_update(telegram, ibaDamping_, 8); has_enumupdate(telegram, ibaBuildingType_, 9, 1); // 1=light, 2=medium, 3=heavy has_update(telegram, ibaMinExtTemperature_, 10); @@ -1557,6 +1558,8 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) { write_command(EMS_TYPE_RC30Settings, 1, t, EMS_TYPE_RC30Settings); } else if (model() == EMS_DEVICE_FLAG_RC100H) { write_command(0x273, 0, t, 0x273); + } else if (model() == EMS_DEVICE_FLAG_RC100 || model() == EMS_DEVICE_FLAG_RC300) { + write_command(0x240, 7, t, 0x240); } else { write_command(EMS_TYPE_IBASettings, 2, t, EMS_TYPE_IBASettings); } @@ -1564,10 +1567,10 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) { return true; } -// 0xA5 - Set the display settings +// 0xA5 - Set the display settings, RC30_N bool Thermostat::set_display(const char * value, const int8_t id) { - int ds = 0; - if (!Helpers::value2number(value, ds)) { + uint8_t ds; + if (!Helpers::value2enum(value, ds, FL_(enum_ibaMainDisplay))) { return false; } @@ -3382,6 +3385,13 @@ void Thermostat::register_device_values() { FL_(dateTime), DeviceValueUOM::NONE, MAKE_CF_CB(set_datetime)); + register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, + &ibaCalIntTemperature_, + DeviceValueType::INT, + DeviceValueNumOp::DV_NUMOP_DIV10, + FL_(ibaCalIntTemperature), + DeviceValueUOM::DEGREES_R, + MAKE_CF_CB(set_calinttemp)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &floordrystatus_, DeviceValueType::ENUM, @@ -3506,12 +3516,6 @@ void Thermostat::register_device_values() { FL_(ibaLanguage), DeviceValueUOM::NONE, MAKE_CF_CB(set_language)); - register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, - &ibaMainDisplay_, - DeviceValueType::ENUM, - FL_(enum_ibaMainDisplay), - FL_(ibaMainDisplay), - DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &backlight_, DeviceValueType::BOOL, FL_(backlight), DeviceValueUOM::NONE, MAKE_CF_CB(set_backlight)); register_device_value( DeviceValueTAG::TAG_DEVICE_DATA, &brightness_, DeviceValueType::INT, FL_(brightness), DeviceValueUOM::NONE, MAKE_CF_CB(set_brightness), -15, 15); @@ -3599,13 +3603,15 @@ void Thermostat::register_device_values() { DeviceValueType::ENUM, FL_(enum_ibaMainDisplay), FL_(ibaMainDisplay), - DeviceValueUOM::NONE); + DeviceValueUOM::NONE, + MAKE_CF_CB(set_display)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaLanguage_, DeviceValueType::ENUM, FL_(enum_ibaLanguage), FL_(ibaLanguage), DeviceValueUOM::NONE); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaClockOffset_, DeviceValueType::INT, FL_(ibaClockOffset), - DeviceValueUOM::SECONDS); // offset (in sec) to clock, 0xff=-1s, 0x02=2s + DeviceValueUOM::SECONDS, + MAKE_CF_CB(set_clockoffset)); // offset (in sec) to clock, 0xff=-1s, 0x02=2s register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &ibaCalIntTemperature_, DeviceValueType::INT, @@ -3950,7 +3956,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrselTemp, DeviceValueType::SHORT, seltemp_divider, FL_(selRoomTemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_temp), 0, 30); } register_device_value(tag, &hc->roomTemp, DeviceValueType::SHORT, roomtemp_divider, FL_(roomTemp), DeviceValueUOM::DEGREES); - register_device_value(tag, &hc->climate, DeviceValueType::ENUM, FL_(enum_climate), FL_(climate), DeviceValueUOM::NONE); + register_device_value(tag, &hc->climate, DeviceValueType::ENUM, FL_(enum_climate), FL_(climate), DeviceValueUOM::NONE); // min, max set in ha function switch (model) { case EMS_DEVICE_FLAG_RC10: @@ -4135,9 +4141,16 @@ void Thermostat::register_device_values_hc(std::shared_ptrmode, DeviceValueType::ENUM, FL_(enum_mode3), FL_(mode), DeviceValueUOM::NONE, MAKE_CF_CB(set_mode)); register_device_value(tag, &hc->modetype, DeviceValueType::ENUM, FL_(enum_modetype3), FL_(modetype), DeviceValueUOM::NONE); register_device_value( - tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp)); - register_device_value( - tag, &hc->nighttemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(nighttemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_nighttemp)); + tag, &hc->daytemp, DeviceValueType::UINT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(daytemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_daytemp), 5, 30); + register_device_value(tag, + &hc->nighttemp, + DeviceValueType::UINT, + DeviceValueNumOp::DV_NUMOP_DIV2, + FL_(nighttemp), + DeviceValueUOM::DEGREES, + MAKE_CF_CB(set_nighttemp), + 5, + 30); register_device_value(tag, &hc->designtemp, DeviceValueType::UINT, FL_(designtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_designtemp), 30, 90); register_device_value(tag, &hc->offsettemp, @@ -4154,7 +4167,9 @@ void Thermostat::register_device_values_hc(std::shared_ptrtargetflowtemp, DeviceValueType::UINT, FL_(targetflowtemp), DeviceValueUOM::DEGREES); register_device_value(tag, &hc->summertemp, DeviceValueType::UINT, FL_(summertemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_summertemp), 9, 25); register_device_value(tag, &hc->summermode, DeviceValueType::ENUM, FL_(enum_summer), FL_(summermode), DeviceValueUOM::NONE); @@ -4183,7 +4198,9 @@ void Thermostat::register_device_values_hc(std::shared_ptrnoreducetemp, DeviceValueType::INT, FL_(noreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_noreducetemp), -30, 10); register_device_value(tag, &hc->reducetemp, DeviceValueType::INT, FL_(reducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_reducetemp), -20, 10); register_device_value(tag, &hc->vacreducetemp, DeviceValueType::INT, FL_(vacreducetemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_vacreducetemp), -20, 10); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index ce475d3e2..fdf302c56 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -850,7 +850,8 @@ void EMSdevice::generate_values_web(JsonObject & output) { obj["s"] = Helpers::render_value(s, (float)(-1) * dv.numeric_operator, 0); } - int16_t dv_set_min, dv_set_max; + int16_t dv_set_min; + uint16_t 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); @@ -980,6 +981,20 @@ void EMSdevice::generate_values_web_customization(JsonArray & output) { } } +void EMSdevice::set_climate_minmax(uint8_t tag, int16_t min, uint16_t max) { + for (auto & dv : devicevalues_) { + if (dv.tag == tag && dv.short_name == FL_(climate[0])) { + if (dv.min != min || dv.max != max) { + dv.min = min; + dv.max = max; + dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); + Mqtt::publish_ha_climate_config(dv.tag, false, true); // delete topic (remove = true) + } + return; + } + } +} + // set mask per device entity based on the id which is prefixed with the 2 char hex mask value // returns true if the entity has a mask set (not 0 the default) void EMSdevice::setCustomEntity(const std::string & entity_id) { @@ -1002,7 +1017,7 @@ void EMSdevice::setCustomEntity(const std::string & entity_id) { uint8_t new_mask = Helpers::hextoint(entity_id.substr(0, 2).c_str()); // first character contains mask flags // if it's a new mask, reconfigure HA - if (Mqtt::ha_enabled() && ((current_mask ^ new_mask) & (DeviceValueState::DV_READONLY >> 4))) { + if (Mqtt::ha_enabled() && (has_custom_name || ((current_mask ^ new_mask) & (DeviceValueState::DV_READONLY >> 4)))) { // remove ha config on change of dv_readonly flag dv.remove_state(DeviceValueState::DV_HA_CONFIG_CREATED); Mqtt::publish_ha_sensor_config(dv, "", "", true); // delete topic (remove = true) @@ -1018,9 +1033,16 @@ void EMSdevice::setCustomEntity(const std::string & entity_id) { dv.custom_fullname = ""; } + auto min = dv.min; + auto max = dv.max; + // set the min / max dv.set_custom_minmax(); + if (Mqtt::ha_enabled() && dv.short_name == FL_(seltemp)[0] && (min != dv.min || max != dv.max)) { + set_climate_minmax(dv.tag, dv.min, dv.max); + } + return; } } @@ -1187,11 +1209,14 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8 break; } - // set the min and max - int16_t dv_set_min, dv_set_max; - if (dv.get_min_max(dv_set_min, dv_set_max)) { - json["min"] = dv_set_min; - json["max"] = dv_set_max; + // set the min and max only for commands + if (dv.has_cmd) { + int16_t dv_set_min; + uint16_t dv_set_max; + if (dv.get_min_max(dv_set_min, dv_set_max)) { + json["min"] = dv_set_min; + json["max"] = dv_set_max; + } } // add uom if it's not a " " (single space) @@ -1469,12 +1494,12 @@ void EMSdevice::mqtt_ha_entity_config_create() { if (*(int8_t *)(dv.value_p) == 1 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) { dv.remove_state(DeviceValueState::DV_HA_CLIMATE_NO_RT); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); - Mqtt::publish_ha_climate_config(dv.tag, true); + Mqtt::publish_ha_climate_config(dv.tag, true, false, dv.min, dv.max); } else if (*(int8_t *)(dv.value_p) == 0 && (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) || !dv.has_state(DeviceValueState::DV_HA_CLIMATE_NO_RT))) { dv.add_state(DeviceValueState::DV_HA_CLIMATE_NO_RT); dv.add_state(DeviceValueState::DV_HA_CONFIG_CREATED); - Mqtt::publish_ha_climate_config(dv.tag, false); + Mqtt::publish_ha_climate_config(dv.tag, false, false, dv.min, dv.max); } } if (!dv.has_state(DeviceValueState::DV_HA_CONFIG_CREATED) && (dv.type != DeviceValueType::CMD) && dv.has_state(DeviceValueState::DV_ACTIVE) diff --git a/src/emsdevice.h b/src/emsdevice.h index 8a841e14a..d4ea9ad0d 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -187,6 +187,7 @@ class EMSdevice { void list_device_entries(JsonObject & output) const; void add_handlers_ignored(const uint16_t handler); + void set_climate_minmax(uint8_t tag, int16_t min, uint16_t max); void setCustomEntity(const std::string & entity_id); void getCustomEntities(std::vector & entity_ids); diff --git a/src/emsdevicevalue.cpp b/src/emsdevicevalue.cpp index 97b7f6b7a..87452232c 100644 --- a/src/emsdevicevalue.cpp +++ b/src/emsdevicevalue.cpp @@ -270,7 +270,7 @@ bool DeviceValue::hasValue() const { // converts to signed int, which means rounding to an whole integer // returns false if there is no min/max needed // Types BOOL, ENUM, STRING and CMD are not used -bool DeviceValue::get_min_max(int16_t & dv_set_min, int16_t & dv_set_max) { +bool DeviceValue::get_min_max(int16_t & dv_set_min, uint16_t & dv_set_max) { uint8_t fahrenheit = !EMSESP::system_.fahrenheit() ? 0 : (uom == DeviceValueUOM::DEGREES) ? 2 : (uom == DeviceValueUOM::DEGREES_R) ? 1 : 0; // if we have individual limits set already, just do the conversion diff --git a/src/emsdevicevalue.h b/src/emsdevicevalue.h index a36795e46..bdb003450 100644 --- a/src/emsdevicevalue.h +++ b/src/emsdevicevalue.h @@ -176,7 +176,7 @@ class DeviceValue { uint8_t state); bool hasValue() const; - bool get_min_max(int16_t & dv_set_min, int16_t & dv_set_max); + bool get_min_max(int16_t & dv_set_min, uint16_t & dv_set_max); void set_custom_minmax(); bool get_custom_min(int16_t & val); diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 1e44808ab..fac98d316 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -1340,6 +1340,7 @@ void EMSESP::scheduled_fetch_values() { last_fetch_ = uuid::get_uptime(); no = 1; } + if (txservice_.tx_queue_empty()) { uint8_t i = 0; for (const auto & emsdevice : emsdevices) { diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 885961db8..be3286ff3 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -915,7 +915,7 @@ void Mqtt::publish_ha_sensor_config(DeviceValue & dv, const std::string & model, // calculate the min and max int16_t dv_set_min; - int16_t dv_set_max; + uint16_t dv_set_max; (void)dv.get_min_max(dv_set_min, dv_set_max); // determine if we're creating the command topics which we use special HA configs @@ -1241,7 +1241,7 @@ void Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdevice publish_ha(topic, doc.as()); } -void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove) { +void Mqtt::publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp, const bool remove, const int16_t min, const uint16_t max) { uint8_t hc_num = tag - DeviceValueTAG::TAG_HC1 + 1; char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; @@ -1313,9 +1313,9 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove doc["curr_temp_t"] = topic_t; doc["curr_temp_tpl"] = currtemp_s; } - - doc["min_temp"] = Helpers::render_value(min_s, (uint32_t)5, 0, EMSESP::system_.fahrenheit() ? 2 : 0); - doc["max_temp"] = Helpers::render_value(max_s, (uint32_t)30, 0, EMSESP::system_.fahrenheit() ? 2 : 0); + + doc["min_temp"] = Helpers::render_value(min_s, min, 0, EMSESP::system_.fahrenheit() ? 2 : 0); + doc["max_temp"] = Helpers::render_value(max_s, max, 0, EMSESP::system_.fahrenheit() ? 2 : 0); doc["temp_step"] = "0.5"; // the HA climate component only responds to auto, heat and off diff --git a/src/mqtt.h b/src/mqtt.h index 1fef21aef..b709c3f9b 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -107,7 +107,7 @@ class Mqtt { const JsonObject & dev_json); static void publish_system_ha_sensor_config(uint8_t type, const char * name, const char * entity, const uint8_t uom); - static void publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove = false); + static void publish_ha_climate_config(const uint8_t tag, const bool has_roomtemp, const bool remove = false, const int16_t min = 5, const uint16_t max = 30); static void show_topic_handlers(uuid::console::Shell & shell, const uint8_t device_type); static void show_mqtt(uuid::console::Shell & shell); @@ -166,6 +166,14 @@ class Mqtt { return mqtt_publish_fails_; } + static uint32_t publish_queued() { + return mqtt_messages_.size(); + } + + static uint8_t connect_count() { + return connectcount_; + } + static void reset_mqtt(); static bool is_nested() { @@ -177,7 +185,7 @@ class Mqtt { } static bool publish_single() { - return publish_single_; + return mqtt_enabled_ && publish_single_; } static bool publish_single2cmd() { @@ -189,7 +197,7 @@ class Mqtt { } static bool ha_enabled() { - return ha_enabled_; + return mqtt_enabled_ && ha_enabled_; } static void ha_enabled(bool ha_enabled) { diff --git a/src/telegram.cpp b/src/telegram.cpp index c23baf6bf..121097fe6 100644 --- a/src/telegram.cpp +++ b/src/telegram.cpp @@ -432,8 +432,13 @@ void TxService::add(const uint8_t operation, LOG_DEBUG("[DEBUG] New Tx [#%d] telegram, length %d", tx_telegram_id_, message_length); #endif - // if the queue is full, make room but removing the last one + // if the queue is full, make room by removing the last one if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { + if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) { + telegram_write_fail_count_++; + } else { + telegram_read_fail_count_++; + } tx_telegrams_.pop_front(); } @@ -505,8 +510,13 @@ void TxService::add(uint8_t operation, const uint8_t * data, const uint8_t lengt auto telegram = std::make_shared(operation, src, dest, type_id, offset, message_data, message_length); // operation is TX_WRITE or TX_READ - // if the queue is full, make room but removing the last one + // if the queue is full, make room by removing the last one if (tx_telegrams_.size() >= MAX_TX_TELEGRAMS) { + if (tx_telegrams_.front().telegram_->operation == Telegram::Operation::TX_WRITE) { + telegram_write_fail_count_++; + } else { + telegram_read_fail_count_++; + } tx_telegrams_.pop_front(); }