diff --git a/interface/package.json b/interface/package.json index 51078e8e3..bcc223484 100644 --- a/interface/package.json +++ b/interface/package.json @@ -29,7 +29,7 @@ "@types/imagemin": "^8.0.3", "@types/lodash-es": "^4.17.10", "@types/node": "^20.8.10", - "@types/react": "^18.2.33", + "@types/react": "^18.2.34", "@types/react-dom": "^18.2.14", "@types/react-router-dom": "^5.3.3", "alova": "^2.13.1", @@ -61,7 +61,7 @@ "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-autofix": "^1.1.0", "eslint-plugin-import": "^2.29.0", - "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-prettier": "alpha", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index d2c340b93..09c8cc959 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -323,7 +323,14 @@ const de: Translation = { WRITEABLE: 'Schreibbar', SHOWING: 'Anzeigen von', SEARCH: 'Suche', - CERT: 'TLS Zertifikat (Freilassen um TLS zu deaktivieren)' + CERT: 'TLS Zertifikat (Freilassen um TLS zu deaktivieren)', + ON: 'An', + OFF: 'Aus', + POLARITY: 'Polarität', + ACTIVEHIGH: 'Aktiv Positiv', + ACTIVELOW: 'Aktiv Negativ', + UNCHANGED: 'Unverändert', + ALWAYS: 'Immer' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 10567ebb6..76b2db4dc 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -323,7 +323,14 @@ const en: Translation = { WRITEABLE: 'Writeable', SHOWING: 'Showing', SEARCH: 'Search', - CERT: 'TLS root certificate (leave blank to disable TLS)' + CERT: 'TLS root certificate (leave blank to disable TLS)', + ON: 'On', + OFF: 'Off', + POLARITY: 'Polarity', + ACTIVEHIGH: 'Active High', + ACTIVELOW: 'Active Low', + UNCHANGED: 'Unchanged', + ALWAYS: 'Always' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 097efa8c2..f556dc261 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -323,7 +323,14 @@ const fr: Translation = { WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate SEARCH: 'Search', // TODO translate - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index 71acefced..c303bcc00 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -325,7 +325,14 @@ const it: Translation = { WRITEABLE: 'Scrivibile', SHOWING: 'Visualizza', SEARCH: 'Ricerca', - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 1400870f7..b8c6eef7d 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -323,7 +323,14 @@ const nl: Translation = { WRITEABLE: 'Beschrijfbare', SHOWING: 'Tonen', SEARCH: 'Zoek', - CERT: 'TLS rootcertificaat (laat leeg om TLS uit te schakelen)' + CERT: 'TLS rootcertificaat (laat leeg om TLS uit te schakelen)', + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 698714e3c..f660aa2d9 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -323,7 +323,14 @@ const no: Translation = { WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate SEARCH: 'Search', // TODO translate - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 4404b7f53..63df4129d 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -323,7 +323,14 @@ const pl: BaseTranslation = { WRITEABLE: 'zapisywalna', SHOWING: 'Wyświetlane', SEARCH: 'Szukaj', - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default pl; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index f486955de..c1d2f0239 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -323,7 +323,14 @@ const sv: Translation = { WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate SEARCH: 'Search', // TODO translate - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index f018b91ba..682c4648b 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -323,7 +323,14 @@ const tr: Translation = { WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate SEARCH: 'Search', // TODO translate - CERT: 'TLS root certificate (leave blank to disable TLS)' // TODO translate + CERT: 'TLS root certificate (leave blank to disable TLS)', // TODO translate + ON: 'On', // TODO translate + OFF: 'Off', // TODO translate + POLARITY: 'Polarity', // TODO translate + ACTIVEHIGH: 'Active High', // TODO translate + ACTIVELOW: 'Active Low', // TODO translate + UNCHANGED: 'Unchanged', // TODO translate + ALWAYS: 'Always' // TODO translate }; export default tr; diff --git a/interface/src/project/DashboardSensors.tsx b/interface/src/project/DashboardSensors.tsx index 380587a9f..9fde6feae 100644 --- a/interface/src/project/DashboardSensors.tsx +++ b/interface/src/project/DashboardSensors.tsx @@ -16,7 +16,7 @@ import DashboardSensorsAnalogDialog from './DashboardSensorsAnalogDialog'; import DashboardSensorsTemperatureDialog from './DashboardSensorsTemperatureDialog'; import * as EMSESP from './api'; -import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames } from './types'; +import { DeviceValueUOM, DeviceValueUOM_s, AnalogTypeNames, AnalogType } from './types'; import { temperatureSensorItemValidation, analogSensorItemValidation } from './validators'; import type { TemperatureSensor, AnalogSensor } from './types'; import type { FC } from 'react'; @@ -38,7 +38,8 @@ const DashboardSensors: FC = () => { initialData: { ts: [], as: [], - analog_enabled: false + analog_enabled: false, + platform: 'ESP32' } }); @@ -391,7 +392,11 @@ const DashboardSensors: FC = () => { {a.g} {a.n} {AnalogTypeNames[a.t]} - {a.t ? formatValue(a.v, a.u) : ''} + {a.t === AnalogType.DIGITAL_OUT || a.t === AnalogType.DIGITAL_IN ? ( + {a.v ? LL.ON() : LL.OFF()} + ) : ( + {a.t ? formatValue(a.v, a.u) : ''} + )} ))} @@ -402,18 +407,22 @@ const DashboardSensors: FC = () => { return ( - - {LL.TEMP_SENSORS()} - - - {selectedTemperatureSensor && ( - + {sensorData.ts.length > 0 && ( + <> + + {LL.TEMP_SENSORS()} + + + {selectedTemperatureSensor && ( + + )} + )} {sensorData?.analog_enabled === true && ( @@ -429,7 +438,7 @@ const DashboardSensors: FC = () => { onSave={onAnalogDialogSave} creating={creating} selectedItem={selectedAnalogSensor} - validator={analogSensorItemValidation(sensorData.as, creating)} + validator={analogSensorItemValidation(sensorData.as, creating, sensorData.platform)} /> )} @@ -442,14 +451,16 @@ const DashboardSensors: FC = () => { {LL.REFRESH()} - + {sensorData?.analog_enabled === true && ( + + )} diff --git a/interface/src/project/DashboardSensorsAnalogDialog.tsx b/interface/src/project/DashboardSensorsAnalogDialog.tsx index 485dca37e..f66f700a3 100644 --- a/interface/src/project/DashboardSensorsAnalogDialog.tsx +++ b/interface/src/project/DashboardSensorsAnalogDialog.tsx @@ -89,7 +89,6 @@ const DashboardSensorsAnalogDialog = ({ fieldErrors={fieldErrors} name="g" label="GPIO" - disabled={!creating} value={numberValue(editItem.g)} type="number" variant="outlined" @@ -124,90 +123,125 @@ const DashboardSensorsAnalogDialog = ({ {editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && ( - <> - - - {DeviceValueUOM_s.map((val, i) => ( - - {val} - - ))} - - - {editItem.t === AnalogType.ADC && ( - - mV - }} - /> - - )} - {editItem.t === AnalogType.COUNTER && ( - - - - )} - - - - + + + {DeviceValueUOM_s.map((val, i) => ( + + {val} + + ))} + + )} - {editItem.t === AnalogType.DIGITAL_OUT && (editItem.g === 25 || editItem.g === 26) && ( + {editItem.t === AnalogType.ADC && ( mV + }} /> )} - {editItem.t === AnalogType.DIGITAL_OUT && editItem.g !== 25 && editItem.g !== 26 && ( + {editItem.t === AnalogType.COUNTER && ( )} - {editItem.t >= AnalogType.PWM_0 && ( + {editItem.t >= AnalogType.COUNTER && editItem.t <= AnalogType.RATE && ( + + + + )} + {editItem.t === AnalogType.DIGITAL_OUT && (editItem.g === 25 || editItem.g === 26) && ( + + + + )} + {editItem.t === AnalogType.DIGITAL_OUT && editItem.g !== 25 && editItem.g !== 26 && ( + <> + + + {LL.OFF()} + {LL.ON()} + + + + + {LL.ACTIVEHIGH()} + {LL.ACTIVELOW()} + + + + + {LL.UNCHANGED()} + + {LL.ALWAYS()} {LL.OFF()} + + + {LL.ALWAYS()} {LL.ON()} + + + + + )} + {(editItem.t === AnalogType.PWM_0 || editItem.t === AnalogType.PWM_1 || editItem.t === AnalogType.PWM_2) && ( <> ({ } }); -export const analogSensorItemValidation = (sensors: AnalogSensor[], creating: boolean) => +export const analogSensorItemValidation = (sensors: AnalogSensor[], creating: boolean, platform: string) => new Schema({ n: [{ required: true, message: 'Name is required' }], g: [ { required: true, message: 'GPIO is required' }, - GPIO_VALIDATOR, + platform === 'ESP32-S3' ? GPIO_VALIDATORS3 : platform === 'ESP32-C3' ? GPIO_VALIDATORC3 : GPIO_VALIDATOR, ...(creating ? [isGPIOUniqueValidator(sensors)] : []) ] }); diff --git a/interface/yarn.lock b/interface/yarn.lock index eb1bf057d..cc0410c85 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -267,7 +267,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.7": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.6, @babel/runtime@npm:^7.8.7": version: 7.23.2 resolution: "@babel/runtime@npm:7.23.2" dependencies: @@ -1359,7 +1359,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^18.2.33": +"@types/react@npm:*": version: 18.2.33 resolution: "@types/react@npm:18.2.33" dependencies: @@ -1370,6 +1370,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.2.34": + version: 18.2.34 + resolution: "@types/react@npm:18.2.34" + dependencies: + "@types/prop-types": "npm:*" + "@types/scheduler": "npm:*" + csstype: "npm:^3.0.2" + checksum: 6d16f86b384e829edc3710b1dd9ec4eb1d6b26bc079c5cf605bd0cbf77ae6224f15c76949afadb7f53df4544cfe4025c1111fbe36732cd7f660a320fbc2e5866 + languageName: node + linkType: hard + "@types/responselike@npm:^1.0.0": version: 1.0.2 resolution: "@types/responselike@npm:1.0.2" @@ -1547,7 +1558,7 @@ __metadata: "@types/imagemin": "npm:^8.0.3" "@types/lodash-es": "npm:^4.17.10" "@types/node": "npm:^20.8.10" - "@types/react": "npm:^18.2.33" + "@types/react": "npm:^18.2.34" "@types/react-dom": "npm:^18.2.14" "@types/react-router-dom": "npm:^5.3.3" "@typescript-eslint/eslint-plugin": "npm:^6.9.1" @@ -1562,7 +1573,7 @@ __metadata: eslint-import-resolver-typescript: "npm:^3.6.1" eslint-plugin-autofix: "npm:^1.1.0" eslint-plugin-import: "npm:^2.29.0" - eslint-plugin-jsx-a11y: "npm:^6.7.1" + eslint-plugin-jsx-a11y: "npm:^6.8.0" eslint-plugin-prettier: "npm:alpha" eslint-plugin-react: "npm:^7.33.2" eslint-plugin-react-hooks: "npm:^4.6.0" @@ -1754,7 +1765,7 @@ __metadata: languageName: node linkType: hard -"aria-query@npm:^5.1.3": +"aria-query@npm:^5.3.0": version: 5.3.0 resolution: "aria-query@npm:5.3.0" dependencies: @@ -1865,10 +1876,10 @@ __metadata: languageName: node linkType: hard -"ast-types-flow@npm:^0.0.7": - version: 0.0.7 - resolution: "ast-types-flow@npm:0.0.7" - checksum: 663b90e99b56ee2d7f736a6b6fff8b3c5404f28fa1860bb8d83ee5a9bff9e687520d0d6d9db6edff5a34fd4d3c0c11a3beb1cf75e43c9a880cca04371cc99808 +"ast-types-flow@npm:^0.0.8": + version: 0.0.8 + resolution: "ast-types-flow@npm:0.0.8" + checksum: 85a1c24af4707871c27cfe456bd2ff7fcbe678f3d1c878ac968c9557735a171a17bdcc8c8f903ceab3fc3c49d5b3da2194e6ab0a6be7fec0e133fa028f21ba1b languageName: node linkType: hard @@ -1902,14 +1913,14 @@ __metadata: languageName: node linkType: hard -"axe-core@npm:^4.6.2": - version: 4.8.2 - resolution: "axe-core@npm:4.8.2" - checksum: 3e8dbf264a57767713daa77fe04bbabd71a956b08b99c2eb0ec61b75852f21190653f557d2da623dea9e0a7555460deaac71d9f6a9125c0b52576f8581bfbe52 +"axe-core@npm:=4.7.0": + version: 4.7.0 + resolution: "axe-core@npm:4.7.0" + checksum: 615c0f7722c3c9fcf353dbd70b00e2ceae234d4c17cbc839dd85c01d16797c4e4da45f8d27c6118e9e6b033fb06efd196106e13651a1b2f3a10e0f11c7b2f660 languageName: node linkType: hard -"axobject-query@npm:^3.1.1": +"axobject-query@npm:^3.2.1": version: 3.2.1 resolution: "axobject-query@npm:3.2.1" dependencies: @@ -3034,7 +3045,7 @@ __metadata: languageName: node linkType: hard -"es-iterator-helpers@npm:^1.0.12": +"es-iterator-helpers@npm:^1.0.12, es-iterator-helpers@npm:^1.0.15": version: 1.0.15 resolution: "es-iterator-helpers@npm:1.0.15" dependencies: @@ -3539,29 +3550,29 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-jsx-a11y@npm:^6.7.1": - version: 6.7.1 - resolution: "eslint-plugin-jsx-a11y@npm:6.7.1" +"eslint-plugin-jsx-a11y@npm:^6.8.0": + version: 6.8.0 + resolution: "eslint-plugin-jsx-a11y@npm:6.8.0" dependencies: - "@babel/runtime": "npm:^7.20.7" - aria-query: "npm:^5.1.3" - array-includes: "npm:^3.1.6" - array.prototype.flatmap: "npm:^1.3.1" - ast-types-flow: "npm:^0.0.7" - axe-core: "npm:^4.6.2" - axobject-query: "npm:^3.1.1" + "@babel/runtime": "npm:^7.23.2" + aria-query: "npm:^5.3.0" + array-includes: "npm:^3.1.7" + array.prototype.flatmap: "npm:^1.3.2" + ast-types-flow: "npm:^0.0.8" + axe-core: "npm:=4.7.0" + axobject-query: "npm:^3.2.1" damerau-levenshtein: "npm:^1.0.8" emoji-regex: "npm:^9.2.2" - has: "npm:^1.0.3" - jsx-ast-utils: "npm:^3.3.3" - language-tags: "npm:=1.0.5" + es-iterator-helpers: "npm:^1.0.15" + hasown: "npm:^2.0.0" + jsx-ast-utils: "npm:^3.3.5" + language-tags: "npm:^1.0.9" minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.6" - object.fromentries: "npm:^2.0.6" - semver: "npm:^6.3.0" + object.entries: "npm:^1.1.7" + object.fromentries: "npm:^2.0.7" peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: b7eb451304dc27c9552649a716be1de3b5d577f39e53f6da6a2dac084b84b349b0224be3020439f99c2b3bf417a13c5591326f1ce6af8d74f1cb5d5d95c4222b + checksum: 7a8e4498531a43d988ce2f12502a3f5ce96eacfec13f956cf927f24bb041b724fb7fc0f0306ea19d143bfc79e138bf25e25acca0822847206ac6bf5ce095e846 languageName: node linkType: hard @@ -4625,13 +4636,6 @@ __metadata: languageName: node linkType: hard -"has@npm:^1.0.3": - version: 1.0.4 - resolution: "has@npm:1.0.4" - checksum: c245f332fe78c7b6b8753857240ac12b3286f995f656a33c77e0f5baab7d0157e6ddb1c34940ffd2bffc51f75ede50cd8b29ff65c13e336376aca8cf3df58043 - languageName: node - linkType: hard - "hasown@npm:^2.0.0": version: 2.0.0 resolution: "hasown@npm:2.0.0" @@ -5493,7 +5497,7 @@ __metadata: languageName: node linkType: hard -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": version: 3.3.5 resolution: "jsx-ast-utils@npm:3.3.5" dependencies: @@ -5544,19 +5548,19 @@ __metadata: languageName: node linkType: hard -"language-subtag-registry@npm:~0.3.2": +"language-subtag-registry@npm:^0.3.20": version: 0.3.22 resolution: "language-subtag-registry@npm:0.3.22" checksum: 5591f4abd775d1ab5945355a5ba894327d2d94c900607bdb69aac1bc5bb921dbeeeb5f616df95e8c0ae875501d19c1cfa0e852ece822121e95048deb34f2b4d2 languageName: node linkType: hard -"language-tags@npm:=1.0.5": - version: 1.0.5 - resolution: "language-tags@npm:1.0.5" +"language-tags@npm:^1.0.9": + version: 1.0.9 + resolution: "language-tags@npm:1.0.9" dependencies: - language-subtag-registry: "npm:~0.3.2" - checksum: 2161292ddae73ff2f5a15fd2d753b21096b81324337dff4ad78d702c63210d5beb18892cd53a3455ee6e88065807c8e285e82c40503678951d2071d101a473b4 + language-subtag-registry: "npm:^0.3.20" + checksum: d3a7c14b694e67f519153d6df6cb200681648d38d623c3bfa9d6a66a5ec5493628acb88e9df5aceef3cf1902ab263a205e7d59ee4cf1d6bb67e707b83538bd6d languageName: node linkType: hard @@ -6196,7 +6200,7 @@ __metadata: languageName: node linkType: hard -"object.entries@npm:^1.1.5, object.entries@npm:^1.1.6": +"object.entries@npm:^1.1.5, object.entries@npm:^1.1.6, object.entries@npm:^1.1.7": version: 1.1.7 resolution: "object.entries@npm:1.1.7" dependencies: diff --git a/lib/espMqttClient/src/MqttClient.cpp b/lib/espMqttClient/src/MqttClient.cpp index 18de7ec74..51d67426d 100644 --- a/lib/espMqttClient/src/MqttClient.cpp +++ b/lib/espMqttClient/src/MqttClient.cpp @@ -14,12 +14,8 @@ using espMqttClientTypes::DisconnectReason; using espMqttClientTypes::Error; MqttClient::MqttClient(espMqttClientTypes::UseInternalTask useInternalTask, uint8_t priority, uint8_t core) -#if defined(ARDUINO_ARCH_ESP32) : _useInternalTask(useInternalTask) , _transport(nullptr) -#else - : _transport(nullptr) -#endif , _onConnectCallback(nullptr) , _onDisconnectCallback(nullptr) , _onSubscribeCallback(nullptr) @@ -153,8 +149,8 @@ uint16_t MqttClient::publish(const char * topic, uint8_t qos, bool retain, const #endif return 0; } - uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; EMC_SEMAPHORE_TAKE(); + uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; if (!_addPacket(packetId, topic, payload, length, qos, retain)) { emc_log_e("Could not create PUBLISH packet"); _onError(packetId, Error::OUT_OF_MEMORY); @@ -177,8 +173,8 @@ uint16_t MqttClient::publish(const char * topic, uint8_t qos, bool retain, espMq #endif return 0; } - uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; EMC_SEMAPHORE_TAKE(); + uint16_t packetId = (qos > 0) ? _getNextPacketId() : 1; if (!_addPacket(packetId, topic, callback, length, qos, retain)) { emc_log_e("Could not create PUBLISH packet"); _onError(packetId, Error::OUT_OF_MEMORY); @@ -320,12 +316,9 @@ void MqttClient::_loop(MqttClient * c) { #endif uint16_t MqttClient::_getNextPacketId() { - uint16_t packetId = 0; - EMC_SEMAPHORE_TAKE(); - // cppcheck-suppress knownConditionTrueFalse - packetId = (++_packetId == 0) ? ++_packetId : _packetId; - EMC_SEMAPHORE_GIVE(); - return packetId; + ++_packetId; + if (_packetId == 0) ++_packetId; + return _packetId; } void MqttClient::_checkOutbox() { @@ -340,10 +333,9 @@ int MqttClient::_sendPacket() { EMC_SEMAPHORE_TAKE(); OutgoingPacket * packet = _outbox.getCurrent(); - size_t wantToWrite = 0; size_t written = 0; - if (packet && (wantToWrite == written)) { - wantToWrite = packet->packet.available(_bytesSent); + if (packet) { + size_t wantToWrite = packet->packet.available(_bytesSent); if (wantToWrite == 0) { EMC_SEMAPHORE_GIVE(); return 0; diff --git a/lib/espMqttClient/src/Transport/ClientPosix.cpp b/lib/espMqttClient/src/Transport/ClientPosix.cpp index edccad065..82f16b449 100644 --- a/lib/espMqttClient/src/Transport/ClientPosix.cpp +++ b/lib/espMqttClient/src/Transport/ClientPosix.cpp @@ -40,8 +40,7 @@ bool ClientPosix::connect(IPAddress ip, uint16_t port) { _host.sin_addr.s_addr = htonl(uint32_t(ip)); _host.sin_port = htons(port); // modified by proddy for EMS-ESP compiling standalone - int ret = ::connect(_sockfd, (struct sockaddr *)&_host, sizeof(_host)); - + int ret = ::connect(_sockfd, reinterpret_cast(&_host), sizeof(_host)); if (ret < 0) { emc_log_e("Error connecting: %d - (%d) %s", ret, errno, strerror(errno)); return false; diff --git a/lib/espMqttClient/src/Transport/ClientPosix.h b/lib/espMqttClient/src/Transport/ClientPosix.h index a2f9c9fae..af0dd4bff 100644 --- a/lib/espMqttClient/src/Transport/ClientPosix.h +++ b/lib/espMqttClient/src/Transport/ClientPosix.h @@ -43,7 +43,7 @@ class ClientPosix : public Transport { protected: int _sockfd; - struct sockaddr_in _host; + sockaddr_in _host; }; } // namespace espMqttClientInternals diff --git a/platformio.ini b/platformio.ini index eafde0a7f..455e78998 100644 --- a/platformio.ini +++ b/platformio.ini @@ -127,7 +127,9 @@ extends = espressi32_base_tasmota board = lolin_c3_mini board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv -build_flags = ${common.build_flags} +build_flags = + ${common.build_flags} + -DEMSESP_DEFAULT_BOARD_PROFILE = "C3MINI" ; lolin C3 mini v1 needs special wifi init. ; https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi @@ -139,13 +141,16 @@ board_build.partitions = esp32_partition_4M.csv build_flags = ${common.build_flags} -DBOARD_C3_MINI_V1 + -DEMSESP_DEFAULT_BOARD_PROFILE = "C3MINI" [env:lolin_s2_mini] extends = espressi32_base_tasmota board = lolin_s2_mini board_upload.flash_size = 4MB board_build.partitions = esp32_partition_4M.csv -build_flags = ${common.build_flags} +build_flags = + ${common.build_flags} + -DEMSESP_DEFAULT_BOARD_PROFILE = "S2MINI" [env:lolin_s3] extends = espressi32_base @@ -158,6 +163,7 @@ board_upload.wait_for_upload_port = false build_flags = ${common.build_flags} -O2 + -DEMSESP_DEFAULT_BOARD_PROFILE = "S32S3" ; to build and run: pio run -e standalone -t exec [env:standalone] diff --git a/src/analogsensor.cpp b/src/analogsensor.cpp index 8c42be43c..e9c29782e 100644 --- a/src/analogsensor.cpp +++ b/src/analogsensor.cpp @@ -57,7 +57,9 @@ void AnalogSensor::start() { [&](const char * value, const int8_t id, JsonObject & output) { return command_commands(value, id, output); }, FL_(commands_cmd)); - Mqtt::subscribe(EMSdevice::DeviceType::ANALOGSENSOR, "analogsensor/#", nullptr); // use empty function callback + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + snprintf(topic, sizeof(topic), "%s/#", F_(analogsensor)); + Mqtt::subscribe(EMSdevice::DeviceType::ANALOGSENSOR, topic, nullptr); // use empty function callback } // load settings from the customization file, sorts them and initializes the GPIOs @@ -142,12 +144,12 @@ void AnalogSensor::reload() { for (auto & sensor : sensors_) { sensor.ha_registered = false; // force HA configs to be re-created if (sensor.type() == AnalogType::ADC) { - LOG_DEBUG("Adding analog ADC sensor on GPIO %02d", sensor.gpio()); + LOG_DEBUG("ADC Sensor on GPIO %02d", sensor.gpio()); // analogSetPinAttenuation does not work with analogReadMilliVolts sensor.analog_ = 0; // initialize sensor.last_reading_ = 0; } else if (sensor.type() == AnalogType::COUNTER) { - LOG_DEBUG("Adding analog I/O Counter sensor on GPIO %02d", sensor.gpio()); + LOG_DEBUG("I/O Counter on GPIO %02d", sensor.gpio()); pinMode(sensor.gpio(), INPUT_PULLUP); #if CONFIG_IDF_TARGET_ESP32 if (sensor.gpio() == 25 || sensor.gpio() == 26) { @@ -165,7 +167,7 @@ void AnalogSensor::reload() { } publish_sensor(sensor); } else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { - LOG_DEBUG("Adding analog Timer/Rate sensor on GPIO %02d", sensor.gpio()); + LOG_DEBUG("Timer/Rate on GPIO %02d", sensor.gpio()); pinMode(sensor.gpio(), INPUT_PULLUP); sensor.polltime_ = uuid::get_uptime(); sensor.last_polltime_ = uuid::get_uptime(); @@ -174,7 +176,7 @@ void AnalogSensor::reload() { sensor.set_value(0); publish_sensor(sensor); } else if (sensor.type() == AnalogType::DIGITAL_IN) { - LOG_DEBUG("Adding analog Read sensor on GPIO %02d", sensor.gpio()); + LOG_DEBUG("Digital Read on GPIO %02d", sensor.gpio()); pinMode(sensor.gpio(), INPUT_PULLUP); sensor.set_value(digitalRead(sensor.gpio())); // initial value sensor.set_uom(0); // no uom, just for safe measures @@ -182,7 +184,7 @@ void AnalogSensor::reload() { sensor.poll_ = digitalRead(sensor.gpio()); publish_sensor(sensor); } else if (sensor.type() == AnalogType::DIGITAL_OUT) { - LOG_DEBUG("Adding analog Write sensor on GPIO %02d", sensor.gpio()); + LOG_DEBUG("Digital Write on GPIO %02d", sensor.gpio()); pinMode(sensor.gpio(), OUTPUT); #if CONFIG_IDF_TARGET_ESP32 if (sensor.gpio() == 25 || sensor.gpio() == 26) { @@ -206,13 +208,12 @@ void AnalogSensor::reload() { } else #endif { - digitalWrite(sensor.gpio(), sensor.offset() > 0 ? 1 : 0); - sensor.set_value(digitalRead(sensor.gpio())); + digitalWrite(sensor.gpio(), sensor.offset() * sensor.factor() > 0 ? 1 : 0); + sensor.set_value(sensor.offset()); } - sensor.set_uom(0); // no uom, just for safe measures publish_sensor(sensor); - } else if (sensor.type() >= AnalogType::PWM_0) { - LOG_DEBUG("Adding PWM output sensor on GPIO %02d", sensor.gpio()); + } else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) { + LOG_DEBUG("PWM output on GPIO %02d", sensor.gpio()); #if ESP_IDF_VERSION_MAJOR >= 5 ledcAttach(sensor.gpio(), sensor.factor(), 13); #else @@ -239,10 +240,10 @@ void AnalogSensor::reload() { // measure input sensors and moving average adc void AnalogSensor::measure() { - static uint32_t measure_last_ = 0; + static uint32_t measure_last_ = uuid::get_uptime() - MEASURE_ANALOG_INTERVAL; // measure interval 500ms for adc sensors - if (!measure_last_ || (uuid::get_uptime() - measure_last_) >= MEASURE_ANALOG_INTERVAL) { + if ((uuid::get_uptime() - measure_last_) >= MEASURE_ANALOG_INTERVAL) { measure_last_ = uuid::get_uptime(); // go through the list of adc sensors for (auto & sensor : sensors_) { @@ -434,15 +435,15 @@ void AnalogSensor::remove_ha_topic(const int8_t type, const uint8_t gpio) const #else if (type == AnalogType::DIGITAL_OUT) { #endif - snprintf(topic, sizeof(topic), "switch/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio); + snprintf(topic, sizeof(topic), "switch/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), gpio); } else if (type == AnalogType::DIGITAL_OUT) { // DAC - snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio); + snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), gpio); } else if (type >= AnalogType::PWM_0) { - snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio); + snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), gpio); } else if (type == AnalogType::DIGITAL_IN) { - snprintf(topic, sizeof(topic), "binary_sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio); + snprintf(topic, sizeof(topic), "binary_sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), gpio); } else { - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), gpio); + snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), gpio); } Mqtt::queue_remove_topic(topic); } @@ -514,7 +515,7 @@ void AnalogSensor::publish_values(const bool force) { StaticJsonDocument config; char stat_t[50]; - snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::basename().c_str()); // use basename + snprintf(stat_t, sizeof(stat_t), "%s/%s_data", Mqtt::basename().c_str(), F_(analogsensor)); // use base path config["stat_t"] = stat_t; char val_obj[50]; @@ -534,9 +535,9 @@ void AnalogSensor::publish_values(const bool force) { char uniq_s[70]; if (Mqtt::entity_format() == Mqtt::entityFormat::MULTI_SHORT) { - snprintf(uniq_s, sizeof(uniq_s), "%s_analogsensor_%02d", Mqtt::basename().c_str(), sensor.gpio()); + snprintf(uniq_s, sizeof(uniq_s), "%s_%s_%02d", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); } else { - snprintf(uniq_s, sizeof(uniq_s), "analogsensor_%02d", sensor.gpio()); + snprintf(uniq_s, sizeof(uniq_s), "%s_%02d", F_(analogsensor), sensor.gpio()); } config["obj_id"] = uniq_s; @@ -559,8 +560,8 @@ void AnalogSensor::publish_values(const bool force) { #else if (sensor.type() == AnalogType::DIGITAL_OUT) { #endif - snprintf(topic, sizeof(topic), "switch/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); - snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str()); + snprintf(topic, sizeof(topic), "switch/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); + snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::basename().c_str(), F_(analogsensor), sensor.name().c_str()); config["cmd_t"] = command_topic; if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { config["pl_on"] = true; @@ -574,30 +575,30 @@ void AnalogSensor::publish_values(const bool force) { config["pl_off"] = Helpers::render_boolean(result, false); } } else if (sensor.type() == AnalogType::DIGITAL_OUT) { // DAC - snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); - snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str()); + snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); + snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::basename().c_str(), F_(analogsensor), sensor.name().c_str()); config["cmd_t"] = command_topic; config["min"] = 0; config["max"] = 255; config["mode"] = "box"; // auto, slider or box config["step"] = 1; - } else if (sensor.type() >= AnalogType::PWM_0) { - snprintf(topic, sizeof(topic), "number/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); - snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str()); + } else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) { + snprintf(topic, sizeof(topic), "number/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); + snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::basename().c_str(), F_(analogsensor), sensor.name().c_str()); config["cmd_t"] = command_topic; config["min"] = 0; config["max"] = 100; config["mode"] = "box"; // auto, slider or box config["step"] = 0.1; } else if (sensor.type() == AnalogType::COUNTER) { - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); - snprintf(command_topic, sizeof(command_topic), "%s/analogsensor/%s", Mqtt::basename().c_str(), sensor.name().c_str()); + snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); + snprintf(command_topic, sizeof(command_topic), "%s/%s/%s", Mqtt::basename().c_str(), F_(analogsensor), sensor.name().c_str()); config["cmd_t"] = command_topic; config["stat_cla"] = "total_increasing"; // config["mode"] = "box"; // auto, slider or box // config["step"] = sensor.factor(); } else if (sensor.type() == AnalogType::DIGITAL_IN) { - snprintf(topic, sizeof(topic), "binary_sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); + snprintf(topic, sizeof(topic), "binary_sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) { config["pl_on"] = true; config["pl_off"] = false; @@ -610,7 +611,7 @@ void AnalogSensor::publish_values(const bool force) { config["pl_off"] = Helpers::render_boolean(result, false); } } else { - snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%02d/config", Mqtt::basename().c_str(), sensor.gpio()); + snprintf(topic, sizeof(topic), "sensor/%s/%s_%02d/config", Mqtt::basename().c_str(), F_(analogsensor), sensor.gpio()); config["stat_cla"] = "measurement"; } @@ -626,7 +627,9 @@ void AnalogSensor::publish_values(const bool force) { } } - Mqtt::queue_publish("analogsensor_data", doc.as()); + char topic[Mqtt::MQTT_TOPIC_MAX_SIZE]; + snprintf(topic, sizeof(topic), "%s_data", F_(analogsensor)); + Mqtt::queue_publish(topic, doc.as()); } // called from emsesp.cpp, similar to the emsdevice->get_value_info @@ -657,7 +660,7 @@ bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const i output["offset"] = sensor.offset(); output["factor"] = sensor.factor(); output["value"] = sensor.value(); - output["writeable"] = sensor.type() == AnalogType::COUNTER || sensor.type() >= AnalogType::DIGITAL_OUT; + output["writeable"] = sensor.type() == AnalogType::COUNTER || (sensor.type() >= AnalogType::DIGITAL_OUT && sensor.type() <= AnalogType::PWM_2); // min/max for writeable analogs if (sensor.type() == AnalogType::COUNTER) { output["min"] = 0; @@ -665,7 +668,7 @@ bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const i } else if (sensor.type() == AnalogType::DIGITAL_OUT) { output["min"] = 0; output["max"] = sensor.gpio() == 25 || sensor.gpio() == 26 ? 255 : 1; - } else if (sensor.type() >= AnalogType::PWM_0) { + } else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) { output["min"] = 0; output["max"] = 100; } @@ -702,6 +705,7 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject JsonObject dataSensor = output.createNestedObject(sensor.name()); dataSensor["gpio"] = sensor.gpio(); dataSensor["type"] = F_(number); + dataSensor["value"] = sensor.value(); dataSensor["analog"] = FL_(list_sensortype)[sensor.type()]; if (sensor.type() == AnalogType::ADC) { dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); @@ -713,11 +717,10 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject dataSensor["factor"] = sensor.factor(); } else if (sensor.type() == AnalogType::TIMER || sensor.type() == AnalogType::RATE) { dataSensor["factor"] = sensor.factor(); - } else if (sensor.type() >= AnalogType::PWM_0) { + } else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) { dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); dataSensor["frequency"] = sensor.factor(); } - dataSensor["value"] = sensor.value(); } else if (id == 0) { // output values command output[sensor.name()] = sensor.value(); } else { // if someone wants gpio numbers @@ -763,6 +766,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { } for (auto & sensor : sensors_) { if (sensor.gpio() == gpio) { + double oldoffset = sensor.offset(); if (sensor.type() == AnalogType::COUNTER) { if (val < 0 || value[0] == '+') { // sign corrects values sensor.set_offset(sensor.value() + val); @@ -771,11 +775,11 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { sensor.set_offset(val); sensor.set_value(val); } - publish_sensor(sensor); - return true; + if (oldoffset != sensor.offset() && sensor.offset() != EMSESP::nvs_.getDouble(sensor.name().c_str())) { + EMSESP::nvs_.putDouble(sensor.name().c_str(), sensor.value()); + } } else if (sensor.type() == AnalogType::ADC) { sensor.set_offset(val); - return true; } else if (sensor.type() == AnalogType::DIGITAL_OUT) { uint8_t v = val; #if CONFIG_IDF_TARGET_ESP32 @@ -784,8 +788,6 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { sensor.set_value(v); pinMode(sensor.gpio(), OUTPUT); dacWrite(sensor.gpio(), sensor.offset()); - publish_sensor(sensor); - return true; } else #elif CONFIG_IDF_TARGET_ESP32S2 if ((sensor.gpio() == 23 || sensor.gpio() == 24) && v <= 255) { @@ -801,11 +803,9 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { sensor.set_offset(v); sensor.set_value(v); pinMode(sensor.gpio(), OUTPUT); - digitalWrite(sensor.gpio(), sensor.offset() > 0 ? 1 : 0); - publish_sensor(sensor); - return true; + digitalWrite(sensor.gpio(), sensor.offset() * sensor.factor() > 0 ? 1 : 0); } - } else if (sensor.type() >= AnalogType::PWM_0) { + } else if (sensor.type() >= AnalogType::PWM_0 && sensor.type() <= AnalogType::PWM_2) { if (val > 100) { val = 100; } else if (val < 0) { @@ -819,9 +819,28 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) { uint8_t channel = sensor.type() - AnalogType::PWM_0; ledcWrite(channel, (uint32_t)(val * 8191 / 100)); #endif + } else { + return false; + } + if (oldoffset != sensor.offset()) { + EMSESP::webCustomizationService.update( + [&](WebCustomization & settings) { + for (auto & AnalogCustomization : settings.analogCustomizations) { + if (AnalogCustomization.gpio == sensor.gpio() && AnalogCustomization.type == sensor.type()) { + AnalogCustomization.offset = sensor.offset(); + } + } + if (sensor.type() == AnalogType::COUNTER || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.uom() > 0)) { + return StateUpdateResult::UNCHANGED; // temporary change + } else { + return StateUpdateResult::CHANGED; // persist the change + } + }, + "local"); publish_sensor(sensor); - return true; + changed_ = true; } + return true; } } return false; diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index f36bcf4b0..330eb6cef 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -1269,8 +1269,10 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr telegram has_update(telegram, heatblock_, 23); // see #1317 has_update(telegram, headertemp_, 25); // see #1317 //has_update(telegram, temperatur_, 27); // unknown temperature - has_update(telegram, exhaustTemp_, 31); - + telegram->read_value(exhaustTemp1_ , 31); + if (Helpers::hasValue(exhaustTemp1_)) { + has_update(exhaustTemp_, exhaustTemp1_); + } // read 3 char service code / installation status as appears on the display if ((telegram->message_length > 3) && (telegram->offset == 0)) { char serviceCode[4] = {0}; @@ -1338,7 +1340,10 @@ void Boiler::process_UBAMonitorSlowPlus(std::shared_ptr telegram has_bitupdate(telegram, heatingPump_, 2, 5); has_bitupdate(telegram, wwCirc_, 2, 7); // temperature measurements at offset 4 unknown, see https://github.com/emsesp/EMS-ESP/issues/620 - // exhaustTemp was offset 6, now in e4. See #1147, #1150, #1326 + // exhaust is in E4/31, but not always published, but this goes to zero if burner stops + if (!Helpers::hasValue(exhaustTemp1_)) { + has_update(telegram, exhaustTemp_, 6); + } has_update(telegram, burnStarts_, 10, 3); // force to 3 bytes has_update(telegram, burnWorkMin_, 13, 3); // force to 3 bytes has_update(telegram, burn2WorkMin_, 16, 3); // force to 3 bytes diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 5215e3f00..b48d00ccf 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -113,7 +113,8 @@ class Boiler : public EMSdevice { uint16_t switchTemp_; // Switch temperature uint8_t sysPress_; // System pressure uint16_t boilTemp_; // Boiler temperature - uint16_t exhaustTemp_; // Exhaust temperature + uint16_t exhaustTemp_; // Exhaust temperature published + uint16_t exhaustTemp1_; // read from E4 uint8_t burnGas_; // Gas on/off uint8_t burnGas2_; // Gas stage 2 on/off uint16_t flameCurr_; // Flame current in micro amps diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 798795cbb..f7f5dfa32 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -83,27 +83,34 @@ Thermostat::Thermostat(uint8_t device_type, uint8_t device_id, uint8_t product_i // RC20 } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC20) { - monitor_typeids = {0x91}; - set_typeids = {0xA8}; - curve_typeids = {0x90}; - timer_typeids = {0x8F}; - for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor)); - register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set)); - register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp)); - register_telegram_type(timer_typeids[i], "RC20Timer", false, MAKE_PF_CB(process_RC20Timer)); + if (device_id == 0x17) { // master + monitor_typeids = {0x91}; + set_typeids = {0xA8}; + curve_typeids = {0x90}; + timer_typeids = {0x8F}; + for (uint8_t i = 0; i < monitor_typeids.size(); i++) { + register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor)); + register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set)); + register_telegram_type(curve_typeids[i], "RC20Temp", false, MAKE_PF_CB(process_RC20Temp)); + register_telegram_type(timer_typeids[i], "RC20Timer", false, MAKE_PF_CB(process_RC20Timer)); + } + } else { + // remote thermostat uses only 0xAF + register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote)); } - // remote thermostat uses only 0xAF - register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote)); // RC20 newer } else if ((model == EMSdevice::EMS_DEVICE_FLAG_RC20_N) || (model == EMSdevice::EMS_DEVICE_FLAG_RC25)) { - monitor_typeids = {0xAE}; - set_typeids = {0xAD}; - for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2)); - register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2)); + if (device_id == 0x17) { // master + monitor_typeids = {0xAE}; + set_typeids = {0xAD}; + for (uint8_t i = 0; i < monitor_typeids.size(); i++) { + register_telegram_type(monitor_typeids[i], "RC20Monitor", false, MAKE_PF_CB(process_RC20Monitor_2)); + register_telegram_type(set_typeids[i], "RC20Set", false, MAKE_PF_CB(process_RC20Set_2)); + } + } else { + // remote thermostat uses only 0xAF + register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote)); } - register_telegram_type(0xAF, "RC20Remote", false, MAKE_PF_CB(process_RC20Remote)); // RC30 } else if (model == EMSdevice::EMS_DEVICE_FLAG_RC30) { monitor_typeids = {0x41}; @@ -237,15 +244,23 @@ std::shared_ptr Thermostat::heating_circuit(std::sha // look through the Monitor and Set arrays to see if there is a match uint8_t hc_num = 0; bool toggle_ = false; - // search monitor message types - for (uint8_t i = 0; i < monitor_typeids.size(); i++) { - if (monitor_typeids[i] == telegram->type_id) { - hc_num = i + 1; - toggle_ = true; - break; - } + + // search device-id types for remote thermostats first, they have only a single typeid for all hcs + if (telegram->src >= 0x18 && telegram->src <= 0x1F) { + hc_num = telegram->src - 0x17; + toggle_ = true; } + // not found, search monitor message types + if (hc_num == 0) { + for (uint8_t i = 0; i < monitor_typeids.size(); i++) { + if (monitor_typeids[i] == telegram->type_id) { + hc_num = i + 1; + toggle_ = true; + break; + } + } + } // not found, search status message/set types if (hc_num == 0) { for (uint8_t i = 0; i < set_typeids.size(); i++) { @@ -335,12 +350,6 @@ std::shared_ptr Thermostat::heating_circuit(std::sha } } - // not found, search device-id types for remote thermostats - if (hc_num == 0 && telegram->src >= 0x18 && telegram->src <= 0x1F) { - hc_num = telegram->src - 0x17; - toggle_ = true; - } - // not found, search device-id types for remote thermostats if (hc_num == 0 && telegram->dest >= 0x20 && telegram->dest <= 0x27) { hc_num = telegram->dest - 0x20; @@ -4223,13 +4232,8 @@ void Thermostat::register_device_values_hc(std::shared_ptrremoteseltemp, - DeviceValueType::INT, - DeviceValueNumOp::DV_NUMOP_DIV2, - FL_(remoteseltemp), - DeviceValueUOM::DEGREES); - // a command is only accepted from the remote device, not from ems-esp. + register_device_value(tag, &hc->remoteseltemp, DeviceValueType::INT, DeviceValueNumOp::DV_NUMOP_DIV2, FL_(remoteseltemp), DeviceValueUOM::DEGREES); + // a command is only accepted from the remote device, not from ems-esp. register_device_value(tag, &hc->fastHeatup, DeviceValueType::UINT, FL_(fastheatup), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_fastheatup)); register_device_value(tag, &hc->switchonoptimization, @@ -4258,14 +4262,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrremotehum, - DeviceValueType::UINT, - FL_(remotehum), - DeviceValueUOM::PERCENT, - MAKE_CF_CB(set_remotehum), - -1, - 101); + register_device_value(tag, &hc->remotehum, DeviceValueType::UINT, FL_(remotehum), DeviceValueUOM::PERCENT, MAKE_CF_CB(set_remotehum), -1, 101); break; case EMS_DEVICE_FLAG_CRF: diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 2e48ecfaa..af78b4648 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -1595,7 +1595,11 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c } } } - + // do not overwrite + if (json.containsKey(name)) { + EMSESP::logger().debug("double json key: %s", name); + continue; + } // handle Booleans if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) { // see how to render the value depending on the setting diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 1f4b7e223..0f50df108 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -601,10 +601,10 @@ void EMSESP::publish_other_values() { publish_device_values(EMSdevice::DeviceType::HEATSOURCE); publish_device_values(EMSdevice::DeviceType::VENTILATION); publish_device_values(EMSdevice::DeviceType::EXTENSION); + publish_device_values(EMSdevice::DeviceType::ALERT); // other devices without values yet // publish_device_values(EMSdevice::DeviceType::GATEWAY); // publish_device_values(EMSdevice::DeviceType::CONNECT); - // publish_device_values(EMSdevice::DeviceType::ALERT); // publish_device_values(EMSdevice::DeviceType::GENERIC); webCustomEntityService.publish(); } diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 52331824f..d700f4f32 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -881,7 +881,6 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev break; case DeviceValueType::STRING: snprintf(topic, sizeof(topic), "text/%s", config_topic); // e.g. set_datetime, set_holiday, set_wwswitchtime - set_ha_classes = true; break; default: // plain old sensor @@ -1130,7 +1129,7 @@ bool Mqtt::publish_ha_sensor_config(uint8_t type, // EMSdev // add category "diagnostic" for system entities // config for writeable entities, like switches. diagnostic for read only sensors. - doc["ent_cat"] = (has_cmd) ? "config" : "diagnostic"; + doc["ent_cat"] = (has_cmd && !set_ha_classes) ? "config" : "diagnostic"; // add the dev json object to the end doc["dev"] = dev_json; diff --git a/src/system.cpp b/src/system.cpp index dda114816..b193deed2 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1442,7 +1442,7 @@ bool System::load_board_profile(std::vector & data, const std::string & } else if (board_profile == "E32") { data = {2, 4, 5, 17, 33, PHY_type::PHY_TYPE_LAN8720, 16, 1, 0}; // BBQKees Gateway E32 } else if (board_profile == "E32V2") { - data = {2, 14, 4, 5, 12, PHY_type::PHY_TYPE_LAN8720, 15, 0, 1}; // BBQKees Gateway E32 V2 + data = {2, 14, 4, 5, 34, PHY_type::PHY_TYPE_LAN8720, 15, 0, 1}; // BBQKees Gateway E32 V2 } else if (board_profile == "MH-ET") { data = {2, 18, 23, 5, 0, PHY_type::PHY_TYPE_NONE, 0, 0, 0}; // MH-ET Live D1 Mini } else if (board_profile == "NODEMCU") { diff --git a/src/version.h b/src/version.h index 334317288..6aabb9bbe 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.6.3-dev.5a" +#define EMSESP_APP_VERSION "3.6.3-dev.5b" diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 6f1e9f711..ab5fe1603 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -22,6 +22,8 @@ namespace emsesp { using namespace std::placeholders; // for `_1` etc +bool WebCustomization::_start = true; + WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager) : _httpEndpoint(WebCustomization::read, WebCustomization::update, @@ -132,10 +134,13 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization & sensor.factor = analogJson["factor"]; sensor.uom = analogJson["uom"]; sensor.type = analogJson["type"]; + if (_start && sensor.type == EMSESP::analogsensor_.AnalogType::DIGITAL_OUT && sensor.uom > DeviceValue::DeviceValueUOM::NONE) { + sensor.offset = sensor.uom - 1; + } customizations.analogCustomizations.push_back(sensor); // add to list } } - + _start = false; // load array of entities id's with masks, building up the object class customizations.entityCustomizations.clear(); if (root["masked_entities"].is()) { @@ -203,7 +208,7 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request) { size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE; auto * response = new MsgpackAsyncJsonResponse(true, buffer); - while (!response->getSize()) { + while (!response) { delete response; buffer -= 1024; response = new MsgpackAsyncJsonResponse(true, buffer); @@ -259,7 +264,7 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req // emsesp::EMSESP::logger().info(id.as()); } // add deleted entities from file - EMSESP::webCustomizationService.read([&](WebCustomization & settings) { + read([&](WebCustomization & settings) { for (EntityCustomization entityCustomization : settings.entityCustomizations) { if (entityCustomization.device_id == device_id) { for (std::string entity_id : entityCustomization.entity_ids) { @@ -288,7 +293,7 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req emsdevice->getCustomizationEntities(entity_ids); // Save the list to the customization file - EMSESP::webCustomizationService.update( + update( [&](WebCustomization & settings) { // see if we already have a mask list for this device, if so remove it for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) { diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index ecb4b6a50..5044c0005 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -73,6 +73,9 @@ class WebCustomization { std::list entityCustomizations; // for a list of entities that have a special mask set static void read(WebCustomization & customizations, JsonObject & root); static StateUpdateResult update(JsonObject & root, WebCustomization & customizations); + + private: + static bool _start; }; class WebCustomizationService : public StatefulService { diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 77185d233..989753a65 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -93,7 +93,8 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { } // add any custom entities - if (EMSESP::webCustomEntityService.count_entities()) { + uint8_t customEntities = EMSESP::webCustomEntityService.count_entities(); + if (customEntities) { JsonObject obj = devices.createNestedObject(); obj["id"] = 99; // the last unique id obj["tn"] = Helpers::translated_word(FL_(custom_device)); // translated device type name @@ -103,7 +104,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { obj["d"] = 0; // deviceid obj["p"] = 0; // productid obj["v"] = 0; // version - obj["e"] = EMSESP::webCustomEntityService.count_entities(); // number of custom entities + obj["e"] = customEntities; // number of custom entities } root["connected"] = EMSESP::bus_status() != 2; @@ -163,7 +164,8 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { } } - root["analog_enabled"] = EMSESP::analogsensor_.analog_enabled(); + root["analog_enabled"] = EMSESP::analog_enabled(); + root["platform"] = EMSESP_PLATFORM; response->setLength(); request->send(response); @@ -180,7 +182,7 @@ void WebDataService::device_data(AsyncWebServerRequest * request) { auto * response = new MsgpackAsyncJsonResponse(false, buffer); // check size - while (!response->getSize()) { + while (!response) { delete response; buffer -= 1024; response = new MsgpackAsyncJsonResponse(false, buffer); diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index f1ec4d410..793f05f8f 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -87,6 +87,11 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) // load default GPIO configuration based on board profile std::vector data; // // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode + settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; + if ((String)EMSESP_DEFAULT_BOARD_PROFILE != "default" && EMSESP::nvs_.getString("boot") == "") { + EMSESP::nvs_.putString("boot", (const char *)EMSESP_DEFAULT_BOARD_PROFILE); + } + /* #if CONFIG_IDF_TARGET_ESP32C3 settings.board_profile = root["board_profile"] | "C3MINI"; #elif CONFIG_IDF_TARGET_ESP32S2 @@ -97,12 +102,12 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) #elif CONFIG_IDF_TARGET_ESP32 settings.board_profile = root["board_profile"] | EMSESP_DEFAULT_BOARD_PROFILE; #endif - +*/ if (!System::load_board_profile(data, settings.board_profile.c_str())) { // unknown, check for NVS or scan for ethernet, use default E32/E32V2/S32 -#if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE) settings.board_profile = EMSESP::nvs_.getString("boot"); if (!System::load_board_profile(data, settings.board_profile.c_str())) { +#if CONFIG_IDF_TARGET_ESP32 && !defined(EMSESP_STANDALONE) if (settings.board_profile == "") { // empty: new test if (ETH.begin((eth_phy_type_t)1, 16, 23, 18, ETH_PHY_LAN8720, ETH_CLOCK_GPIO0_IN)) { EMSESP::nvs_.putString("boot", "E32"); @@ -119,11 +124,11 @@ StateUpdateResult WebSettings::update(JsonObject & root, WebSettings & settings) EMSESP::nvs_.putString("boot", "S32"); } ESP.restart(); - } #else - settings.board_profile = "S32"; - System::load_board_profile(data, settings.board_profile.c_str()); + settings.board_profile = "S32"; + System::load_board_profile(data, settings.board_profile.c_str()); #endif + } EMSESP::logger().info("No board profile found. Re-setting to %s", settings.board_profile.c_str()); } else { EMSESP::logger().info("Loading board profile %s", settings.board_profile.c_str());