diff --git a/.github/workflows/sonar_check.yml b/.github/workflows/sonar_check.yml
index c0ea0e1bb..b638df864 100644
--- a/.github/workflows/sonar_check.yml
+++ b/.github/workflows/sonar_check.yml
@@ -9,9 +9,10 @@ jobs:
build:
name: Build
runs-on: ubuntu-latest
+ if: github.repository_owner == 'emsesp'
+ # if: github.repository == 'emsesp/EMS-ESP32'
env:
# https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
- # SONAR_SCANNER_VERSION: 4.6.1.2450
SONAR_SCANNER_VERSION: 4.7.0.2747
SONAR_SERVER_URL: "https://sonarcloud.io"
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 080b6687e..9b0eedbde 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+# Changelog
+
+## [3.4.1] May 29 2022
+
+### Fixed
+
+- Fix memory leak in api [#524](https://github.com/emsesp/EMS-ESP32/issues/524)
+
+### Changed
+
+- Controller data in web-ui only for IVT [#522](https://github.com/emsesp/EMS-ESP32/issues/522)
+- Rename hidden `climate` to a more explaining name [#523](https://github.com/emsesp/EMS-ESP32/issues/523)
+- Minor changes to the Customizations web page [#527](https://github.com/emsesp/EMS-ESP32/pull/527)
+
# [3.4.0] May 23 2022
## Added
diff --git a/interface/package-lock.json b/interface/package-lock.json
index 65851482f..ec5446a98 100644
--- a/interface/package-lock.json
+++ b/interface/package-lock.json
@@ -13,9 +13,9 @@
"@msgpack/msgpack": "^2.7.2",
"@mui/icons-material": "^5.8.0",
"@mui/material": "^5.8.1",
- "@table-library/react-table-library": "^3.1.2",
+ "@table-library/react-table-library": "^3.1.4",
"@types/lodash": "^4.14.182",
- "@types/node": "^17.0.35",
+ "@types/node": "^17.0.36",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@types/react-router-dom": "^5.3.3",
@@ -34,7 +34,7 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"sockette": "^2.0.6",
- "typescript": "^4.6.4"
+ "typescript": "^4.7.2"
},
"devDependencies": {
"nodemon": "^2.0.16",
@@ -3689,16 +3689,15 @@
}
},
"node_modules/@table-library/react-table-library": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-3.1.2.tgz",
- "integrity": "sha512-zfjIvcEP114KFh5WyZzbPQHtaxiSr0LHHgm+A8El6YG/SQ7D+i88RUdwiBu3uuKXTY7OV+5v/GESEiioZo150w==",
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-3.1.4.tgz",
+ "integrity": "sha512-6JgQJLWgkMkdVzB/gGU/7BuMRGhQkkbg150YXiq+2U2ICyV773JPW5oxE5QaQJZUsDGlcS1FuaK/UFJVLZWs4A==",
"dependencies": {
"clsx": "1.1.1",
"react-virtualized-auto-sizer": "1.0.6",
- "react-window": "1.8.6"
+ "react-window": "1.8.7"
},
"peerDependencies": {
- "@emotion/react": ">= 11",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
}
@@ -3715,22 +3714,6 @@
"react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0"
}
},
- "node_modules/@table-library/react-table-library/node_modules/react-window": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.6.tgz",
- "integrity": "sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==",
- "dependencies": {
- "@babel/runtime": "^7.0.0",
- "memoize-one": ">=3.1.1 <6"
- },
- "engines": {
- "node": ">8.0.0"
- },
- "peerDependencies": {
- "react": "^15.0.0 || ^16.0.0 || ^17.0.0",
- "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0"
- }
- },
"node_modules/@tootallnate/once": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -3930,9 +3913,9 @@
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"node_modules/@types/node": {
- "version": "17.0.35",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
- "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
+ "version": "17.0.36",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz",
+ "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA=="
},
"node_modules/@types/parse-json": {
"version": "4.0.0",
@@ -15026,6 +15009,22 @@
"react-dom": ">=16.6.0"
}
},
+ "node_modules/react-window": {
+ "version": "1.8.7",
+ "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz",
+ "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==",
+ "dependencies": {
+ "@babel/runtime": "^7.0.0",
+ "memoize-one": ">=3.1.1 <6"
+ },
+ "engines": {
+ "node": ">8.0.0"
+ },
+ "peerDependencies": {
+ "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -16806,9 +16805,9 @@
}
},
"node_modules/typescript": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
- "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==",
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz",
+ "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -20452,13 +20451,13 @@
}
},
"@table-library/react-table-library": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-3.1.2.tgz",
- "integrity": "sha512-zfjIvcEP114KFh5WyZzbPQHtaxiSr0LHHgm+A8El6YG/SQ7D+i88RUdwiBu3uuKXTY7OV+5v/GESEiioZo150w==",
+ "version": "3.1.4",
+ "resolved": "https://registry.npmjs.org/@table-library/react-table-library/-/react-table-library-3.1.4.tgz",
+ "integrity": "sha512-6JgQJLWgkMkdVzB/gGU/7BuMRGhQkkbg150YXiq+2U2ICyV773JPW5oxE5QaQJZUsDGlcS1FuaK/UFJVLZWs4A==",
"requires": {
"clsx": "1.1.1",
"react-virtualized-auto-sizer": "1.0.6",
- "react-window": "1.8.6"
+ "react-window": "1.8.7"
},
"dependencies": {
"react-virtualized-auto-sizer": {
@@ -20466,15 +20465,6 @@
"resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz",
"integrity": "sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ==",
"requires": {}
- },
- "react-window": {
- "version": "1.8.6",
- "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.6.tgz",
- "integrity": "sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg==",
- "requires": {
- "@babel/runtime": "^7.0.0",
- "memoize-one": ">=3.1.1 <6"
- }
}
}
},
@@ -20671,9 +20661,9 @@
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"@types/node": {
- "version": "17.0.35",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz",
- "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg=="
+ "version": "17.0.36",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz",
+ "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA=="
},
"@types/parse-json": {
"version": "4.0.0",
@@ -28628,6 +28618,15 @@
"prop-types": "^15.6.2"
}
},
+ "react-window": {
+ "version": "1.8.7",
+ "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz",
+ "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==",
+ "requires": {
+ "@babel/runtime": "^7.0.0",
+ "memoize-one": ">=3.1.1 <6"
+ }
+ },
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -29974,9 +29973,9 @@
}
},
"typescript": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz",
- "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg=="
+ "version": "4.7.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz",
+ "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A=="
},
"unbox-primitive": {
"version": "1.0.2",
diff --git a/interface/package.json b/interface/package.json
index 2ad65f12b..bfee5c32d 100644
--- a/interface/package.json
+++ b/interface/package.json
@@ -9,9 +9,9 @@
"@msgpack/msgpack": "^2.7.2",
"@mui/icons-material": "^5.8.0",
"@mui/material": "^5.8.1",
- "@table-library/react-table-library": "^3.1.2",
+ "@table-library/react-table-library": "^3.1.4",
"@types/lodash": "^4.14.182",
- "@types/node": "^17.0.35",
+ "@types/node": "^17.0.36",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@types/react-router-dom": "^5.3.3",
@@ -30,7 +30,7 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"sockette": "^2.0.6",
- "typescript": "^4.6.4"
+ "typescript": "^4.7.2"
},
"scripts": {
"start": "react-app-rewired start",
diff --git a/interface/src/index.tsx b/interface/src/index.tsx
index e0f77e141..e5473f9d6 100644
--- a/interface/src/index.tsx
+++ b/interface/src/index.tsx
@@ -1,15 +1,15 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
-ReactDOM.render(
-
+const root = createRoot(document.getElementById('root') as HTMLElement);
+
+root.render(
+
- ,
- document.getElementById('root')
+
);
diff --git a/interface/src/project/DashboardData.tsx b/interface/src/project/DashboardData.tsx
index 5b4bd827d..5d8ae278c 100644
--- a/interface/src/project/DashboardData.tsx
+++ b/interface/src/project/DashboardData.tsx
@@ -384,7 +384,10 @@ const DashboardData: FC = () => {
const handleDownloadCsv = () => {
const columns = [
{ accessor: (dv: any) => dv.id.slice(2), name: 'Entity' },
- { accessor: (dv: any) => (typeof dv.v === 'number') ? new Intl.NumberFormat().format(dv.v) : dv.v, name: 'Value' },
+ {
+ accessor: (dv: any) => (typeof dv.v === 'number' ? new Intl.NumberFormat().format(dv.v) : dv.v),
+ name: 'Value'
+ },
{ accessor: (dv: any) => DeviceValueUOM_s[dv.u], name: 'UoM' }
];
downloadAsCsv(
@@ -449,7 +452,7 @@ const DashboardData: FC = () => {
}
};
- const isCmdOnly = (dv: DeviceValue) => dv.v === undefined && dv.c;
+ const isCmdOnly = (dv: DeviceValue) => dv.v === '' && dv.c;
function formatValue(value: any, uom: number) {
if (value === undefined) {
diff --git a/interface/src/project/OptionIcon.tsx b/interface/src/project/OptionIcon.tsx
new file mode 100644
index 000000000..71be44969
--- /dev/null
+++ b/interface/src/project/OptionIcon.tsx
@@ -0,0 +1,39 @@
+import { FC } from 'react';
+import { SvgIconProps } from '@mui/material';
+
+import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
+import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
+
+import StarIcon from '@mui/icons-material/Star';
+import StarOutlineIcon from '@mui/icons-material/StarOutline';
+
+import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
+import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined';
+
+import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
+import InsertCommentOutlinedIcon from '@mui/icons-material/InsertCommentOutlined';
+
+type OptionType = 'readonly' | 'web_exclude' | 'api_mqtt_exclude' | 'favorite';
+
+const OPTION_ICONS: { [type in OptionType]: [React.ComponentType, React.ComponentType] } = {
+ readonly: [EditOffOutlinedIcon, EditOutlinedIcon],
+ web_exclude: [VisibilityOffOutlinedIcon, VisibilityOutlinedIcon],
+ api_mqtt_exclude: [CommentsDisabledOutlinedIcon, InsertCommentOutlinedIcon],
+ favorite: [StarIcon, StarOutlineIcon]
+};
+
+interface OptionIconProps {
+ type: OptionType;
+ isSet: boolean;
+}
+
+const OptionIcon: FC = ({ type, isSet }) => {
+ const Icon = OPTION_ICONS[type][isSet ? 0 : 1];
+ return isSet ? (
+
+ ) : (
+
+ );
+};
+
+export default OptionIcon;
diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx
index a5cac3aae..f1527a6dc 100644
--- a/interface/src/project/SettingsCustomization.tsx
+++ b/interface/src/project/SettingsCustomization.tsx
@@ -25,10 +25,12 @@ import { useSnackbar } from 'notistack';
import SaveIcon from '@mui/icons-material/Save';
import CancelIcon from '@mui/icons-material/Cancel';
-import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
-import StarIcon from '@mui/icons-material/Star';
-import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
-import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
+
+// import EditOffOutlinedIcon from '@mui/icons-material/EditOffOutlined';
+// import StarIcon from '@mui/icons-material/Star';
+// import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined';
+// import CommentsDisabledOutlinedIcon from '@mui/icons-material/CommentsDisabledOutlined';
+
import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore';
import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined';
import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
@@ -36,6 +38,8 @@ import UnfoldMoreOutlinedIcon from '@mui/icons-material/UnfoldMoreOutlined';
import SearchIcon from '@mui/icons-material/Search';
import FilterListIcon from '@mui/icons-material/FilterList';
+import OptionIcon from './OptionIcon';
+
import { ButtonRow, FormLoader, ValidatedTextField, SectionContent } from '../components';
import * as EMSESP from './api';
@@ -47,7 +51,7 @@ import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types';
const SettingsCustomization: FC = () => {
const { enqueueSnackbar } = useSnackbar();
- const [deviceEntities, setDeviceEntities] = useState([{ id: '', v: 0, s: '', m: 0, w: false }]);
+ const [deviceEntities, setDeviceEntities] = useState([{ id: '', v: 0, n: '', m: 0, w: false }]);
const [devices, setDevices] = useState();
const [errorMessage, setErrorMessage] = useState();
const [selectedDevice, setSelectedDevice] = useState(0);
@@ -199,6 +203,15 @@ const SettingsCustomization: FC = () => {
return value;
}
+ function formatName(de: DeviceEntity) {
+ if (de.n === undefined || de.n === de.id) {
+ return de.id;
+ } else if (de.n === '') {
+ return 'Command: ' + de.id;
+ }
+ return de.n + ' (' + de.id + ')';
+ }
+
const getMaskNumber = (newMask: string[]) => {
var new_mask = 0;
for (let entry of newMask) {
@@ -272,7 +285,7 @@ const SettingsCustomization: FC = () => {
if (deviceEntities && selectedDevice) {
const masked_entities = deviceEntities
.filter((de) => de.m !== de.om)
- .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.s);
+ .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id);
if (masked_entities.length > 60) {
enqueueSnackbar('Selected entities exceeded limit of 60. Please Save in batches', { variant: 'warning' });
@@ -303,8 +316,18 @@ const SettingsCustomization: FC = () => {
return (
<>
-
- Select a device and customize each of its entities using the options.
+
+ Select a device and customize each of its entities using the options:
+
+
+ =mark as a favorite
+
+ =disable write action
+
+ =exclude from MQTT and API outputs
+
+ =hide from Web Dashboard
+
{
}}
/>
-
- :
-
+
+
+ :
+
+
{
}}
>
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
+
-
- :
-
-
-
+
-
+
@@ -458,29 +475,44 @@ const SettingsCustomization: FC = () => {
value={getMaskString(de.m)}
onChange={(event, mask) => {
de.m = getMaskNumber(mask);
+ if (de.n === '' && de.m & DeviceEntityMask.DV_READONLY) {
+ de.m = de.m | DeviceEntityMask.DV_WEB_EXCLUDE;
+ }
if (de.m & DeviceEntityMask.DV_WEB_EXCLUDE) {
de.m = de.m & ~DeviceEntityMask.DV_FAVORITE;
}
setMasks(['']);
}}
>
-
-
+
+
-
+
-
-
+
+
-
-
+
+
- |
- {de.id} ({de.s})
- |
+ {formatName(de)} |
{formatValue(de.v)} |
))}
diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts
index 9c1cfecef..c0f115a16 100644
--- a/interface/src/project/types.ts
+++ b/interface/src/project/types.ts
@@ -132,9 +132,9 @@ export interface DeviceData {
}
export interface DeviceEntity {
- id: string; // name
- v: any; // value, in any format
- s: string; // shortname
+ id: string; // shortname
+ v?: any; // value, in any format, optional
+ n?: string; // fullname, optional
m: number; // mask
om?: number; // original mask before edits
w: boolean; // writeable
diff --git a/mock-api/package-lock.json b/mock-api/package-lock.json
index e7dd05f0a..5620b6cf0 100644
--- a/mock-api/package-lock.json
+++ b/mock-api/package-lock.json
@@ -14,7 +14,7 @@
"express": "^4.18.1",
"express-sse": "^0.5.3",
"nodemon": "^2.0.16",
- "ws": "^8.6.0"
+ "ws": "^8.7.0"
}
},
"node_modules/@msgpack/msgpack": {
@@ -1811,9 +1811,9 @@
}
},
"node_modules/ws": {
- "version": "8.6.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz",
- "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==",
+ "version": "8.7.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz",
+ "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==",
"engines": {
"node": ">=10.0.0"
},
@@ -3169,9 +3169,9 @@
}
},
"ws": {
- "version": "8.6.0",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz",
- "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==",
+ "version": "8.7.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz",
+ "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==",
"requires": {}
},
"xdg-basedir": {
diff --git a/mock-api/package.json b/mock-api/package.json
index bdc44b1c3..b41cb5039 100644
--- a/mock-api/package.json
+++ b/mock-api/package.json
@@ -16,6 +16,6 @@
"express": "^4.18.1",
"express-sse": "^0.5.3",
"nodemon": "^2.0.16",
- "ws": "^8.6.0"
+ "ws": "^8.7.0"
}
}
diff --git a/mock-api/server.js b/mock-api/server.js
index d6bc9fefc..0802ddcce 100644
--- a/mock-api/server.js
+++ b/mock-api/server.js
@@ -337,6 +337,7 @@ settings = {
pbutton_gpio: 0,
board_profile: 'S32',
bool_format: 1,
+ bool_dashboard: 1,
enum_format: 1,
}
@@ -473,7 +474,7 @@ const emsesp_devicedata_1 = {
const emsesp_devicedata_2 = {
label: 'Boiler: Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i',
data: [
- { v: 0, u: 0, id: '08reset', c: 'reset', l: ['-', 'maintenance', 'error'] },
+ { v: '', u: 0, id: '08reset', c: 'reset', l: ['-', 'maintenance', 'error'] },
{ v: 'false', u: 0, id: '08heating active' },
{ v: 'false', u: 0, id: '04tapwater active' },
{ v: 5, u: 1, id: '04selected flow temperature', c: 'selflowtemp' },
@@ -575,145 +576,161 @@ const emsesp_devicedata_4 = {
],
}
+// CUSTOMIZATION
+
const emsesp_deviceentities_1 = [
{
v: '(0)',
- id: 'error code',
- s: 'errorcode',
+ n: 'error code',
+ id: 'errorcode',
m: 0,
w: false,
},
{
v: '14:54:39 06/06/2021',
- id: 'date/time',
- s: 'datetime',
+ n: 'date/time',
+ id: 'datetime',
+ m: 0,
+ w: false,
+ },
+ {
+ v: 'test data',
+ n: 'test',
+ id: 'test',
+ m: 0,
+ w: false,
+ },
+ {
+ v: 'roomTemp',
+ id: 'hc1/HA climate config creation',
m: 0,
w: false,
},
{
v: 18.2,
- id: 'hc1 selected room temperature',
- s: 'hc1/seltemp',
+ n: 'hc1 selected room temperature',
+ id: 'hc1/seltemp',
m: 0,
w: true,
},
{
v: 22.6,
- id: 'hc1 current room temperature',
- s: 'hc1/curtemp',
+ n: 'hc1 current room temperature',
+ id: 'hc1/curtemp',
m: 0,
w: false,
},
{
v: 'auto',
- id: 'hc1 mode',
- s: 'hc1/mode',
+ n: 'hc1 mode',
+ id: 'hc1/mode',
m: 0,
w: true,
},
]
const emsesp_deviceentities_2 = [
- { v: false, id: 'heating active', s: 'heatingactive', m: 0, w: false },
- { v: false, id: 'tapwater active', s: 'tapwateractive', m: 0, w: false },
- { v: 5, id: 'selected flow temperature', s: 'selflowtemp', m: 0, w: true },
- { v: 0, id: 'burner selected max power', s: 'selburnpow', m: 0, w: true },
- { v: 0, id: 'heating pump modulation', s: 'heatingpumpmod', m: 0, w: false },
- { id: 'heating pump 2 modulation', s: 'heatingpump2mod', m: 0, w: false },
- { id: 'outside temperature', s: 'outdoortemp', m: 0, w: false },
- { v: 53, id: 'current flow temperature', s: 'curflowtemp', m: 0, w: false },
- { v: 51.8, id: 'return temperature', s: 'rettemp', m: 0, w: false },
- { id: 'mixing switch temperature', s: 'switchtemp', m: 0, w: false },
- { v: 1.3, id: 'system pressure', s: 'syspress', m: 0, w: false },
- { v: 54.6, id: 'actual boiler temperature', s: 'boiltemp', m: 0, w: false },
- { id: 'exhaust temperature', s: 'exhausttemp', m: 0, w: false },
- { v: false, id: 'gas', s: 'burngas', m: 0, w: false },
- { v: false, id: 'gas stage 2', s: 'burngas2', m: 0, w: false },
- { v: 0, id: 'flame current', s: 'flamecurr', m: 0, w: false },
- { v: false, id: 'heating pump', s: 'heatingpump', m: 0, w: false },
- { v: false, id: 'fan', s: 'fanwork', m: 0, w: false },
- { v: false, id: 'ignition', s: 'ignwork', m: 0, w: false },
- { v: false, id: 'oil preheating', s: 'oilpreheat', m: 0, w: false },
- { v: true, id: 'heating activated', s: 'heatingactivated', m: 0, w: false },
- { v: 80, id: 'heating temperature', s: 'heatingtemp', m: 0, w: false },
- { v: 70, id: 'burner pump max power', s: 'pumpmodmax', m: 0, w: false },
- { v: 30, id: 'burner pump min power', s: 'pumpmodmin', m: 0, w: false },
- { v: 1, id: 'pump delay', s: 'pumpdelay', m: 0, w: false },
- { v: 10, id: 'burner min period', s: 'burnminperiod', m: 0, w: false },
- { v: 0, id: 'burner min power', s: 'burnminpower', m: 0, w: false },
- { v: 50, id: 'burner max power', s: 'burnmaxpower', m: 0, w: false },
- { v: -6, id: 'hysteresis on temperature', s: 'boilhyston', m: 0, w: false },
- { v: 6, id: 'hysteresis off temperature', s: 'boilhystoff', m: 0, w: false },
- { v: 0, id: 'set flow temperature', s: 'setflowtemp', m: 0, w: true },
- { v: 0, id: 'burner set power', s: 'setburnpow', m: 0, w: false },
- { v: 0, id: 'burner current power', s: 'curburnpow', m: 0, w: false },
- { v: 326323, id: 'burner starts', s: 'burnstarts', m: 0, w: false },
- { v: 553437, id: 'total burner operating time', s: 'burnworkmin', m: 0, w: false },
- { v: 451286, id: 'total heat operating time', s: 'heatworkmin', m: 0, w: false },
- { v: 4672175, id: 'total UBA operating time', s: 'ubauptime', m: 0, w: false },
- { v: '1C(210) 06.06.2020 12:07 (0 min)', id: 'last error code', s: 'lastcode', m: 0, w: false },
- { v: '0H', id: 'service code', s: 'servicecode', m: 0, w: false },
- { v: 203, id: 'service code number', s: 'servicecodenumber', m: 0, w: false },
- { v: 'H00', id: 'maintenance message', s: 'maintenancemessage', m: 0, w: false },
- { v: 'manual', id: 'maintenance scheduled', s: 'maintenance', m: 0, w: false },
- { v: 6000, id: 'time to next maintenance', s: 'maintenancetime', m: 0, w: false },
- { v: '01.01.2012', id: 'next maintenance date', s: 'maintenancedate', m: 0, w: false },
- { v: true, id: 'dhw turn on/off', s: 'wwtapactivated', m: 0, w: false },
- { v: 62, id: 'dhw set temperature', s: 'wwsettemp', m: 0, w: false },
- { v: 60, id: 'dhw selected temperature', s: 'wwseltemp', m: 0, w: true },
- { id: 'dhw selected lower temperature', s: 'wwseltemplow', m: 2 },
- { id: 'dhw selected temperature for off', s: 'wwseltempoff', m: 2 },
- { id: 'dhw single charge temperature', s: 'wwseltempsingle', m: 2 },
- { v: 'flow', id: 'dhw type', s: 'wwtype', m: 0, w: false },
- { v: 'hot', id: 'dhw comfort', s: 'wwcomfort', m: 0, w: false },
- { v: 40, id: 'dhw flow temperature offset', s: 'wwflowtempoffset', m: 0, w: false },
- { v: 100, id: 'dhw max power', s: 'wwmaxpower', m: 0, w: false },
- { v: false, id: 'dhw circulation pump available', s: 'wwcircpump', m: 0, w: false },
- { v: '3-way valve', id: 'dhw charging type', s: 'wwchargetype', m: 0, w: false },
- { v: -5, id: 'dhw hysteresis on temperature', s: 'wwhyston', m: 0, w: false },
- { v: 0, id: 'dhw hysteresis off temperature', s: 'wwhystoff', m: 0, w: false },
- { v: 70, id: 'dhw disinfection temperature', s: 'wwdisinfectiontemp', m: 0, w: false },
- { v: 'off', id: 'dhw circulation pump mode', s: 'wwcircmode', m: 0, w: false },
- { v: false, id: 'dhw circulation active', s: 'wwcirc', m: 0, w: false },
- { v: 46.4, id: 'dhw current intern temperature', s: 'wwcurtemp', m: 0, w: false },
- { id: 'dhw current extern temperature', s: 'wwcurtemp2', m: 2 },
- { v: 0, id: 'dhw current tap water flow', s: 'wwcurflow', m: 0, w: false },
- { v: 46.3, id: 'dhw storage intern temperature', s: 'wwstoragetemp1', m: 0, w: false },
- { id: 'dhw storage extern temperature', s: 'wwstoragetemp2', m: 2 },
- { v: true, id: 'dhw activated', s: 'wwactivated', m: 0, w: false },
- { v: false, id: 'dhw one time charging', s: 'wwonetime', m: 0, w: false },
- { v: false, id: 'dhw disinfecting', s: 'wwdisinfecting', m: 0, w: false },
- { v: false, id: 'dhw charging', s: 'wwcharging', m: 0, w: false },
- { v: false, id: 'dhw recharging', s: 'wwrecharging', m: 0, w: false },
- { v: true, id: 'dhw temperature ok', s: 'wwtempok', m: 0, w: false },
- { v: false, id: 'dhw active', s: 'wwactive', m: 0, w: false },
- { v: true, id: 'dhw 3way valve active', s: 'ww3wayvalve', m: 0, w: false },
- { v: 0, id: 'dhw set pump power', s: 'wwsetpumppower', m: 0, w: true },
- { id: 'dhw mixer temperature', s: 'wwmixertemp', m: 2 },
- { id: 'dhw cylinder middle temperature (TS3)', s: 'wwcylmiddletemp', m: 2 },
- { v: 288768, id: 'dhw starts', s: 'wwstarts', m: 0, w: false },
- { v: 102151, id: 'dhw active time', s: 'wwworkm', m: 0, w: false },
+ { u: 0, n: '', id: 'reset', m: 8, w: false },
+ { v: false, n: 'heating active', id: 'heatingactive', m: 8, w: false },
+ { v: false, n: 'tapwater active', id: 'tapwateractive', m: 4, w: false },
+ { v: 5, n: 'selected flow temperature', id: 'selflowtemp', m: 4, w: true },
+ { v: 0, n: 'burner selected max power', id: 'selburnpow', m: 14, w: true },
+ { v: 0, n: 'heating pump modulation', id: 'heatingpumpmod', m: 0, w: false },
+ { n: 'heating pump 2 modulation', id: 'heatingpump2mod', m: 0, w: false },
+ { n: 'outside temperature', id: 'outdoortemp', m: 0, w: false },
+ { v: 53, n: 'current flow temperature', id: 'curflowtemp', m: 0, w: false },
+ { v: 51.8, n: 'return temperature', id: 'rettemp', m: 0, w: false },
+ { n: 'mixing switch temperature', id: 'switchtemp', m: 0, w: false },
+ { v: 1.3, n: 'system pressure', id: 'syspress', m: 0, w: false },
+ { v: 54.6, n: 'actual boiler temperature', id: 'boiltemp', m: 0, w: false },
+ { n: 'exhaust temperature', id: 'exhausttemp', m: 0, w: false },
+ { v: false, n: 'gas', id: 'burngas', m: 0, w: false },
+ { v: false, n: 'gas stage 2', id: 'burngas2', m: 0, w: false },
+ { v: 0, n: 'flame current', id: 'flamecurr', m: 0, w: false },
+ { v: false, n: 'heating pump', id: 'heatingpump', m: 0, w: false },
+ { v: false, n: 'fan', id: 'fanwork', m: 0, w: false },
+ { v: false, n: 'ignition', id: 'ignwork', m: 0, w: false },
+ { v: false, n: 'oil preheating', id: 'oilpreheat', m: 0, w: false },
+ { v: true, n: 'heating activated', id: 'heatingactivated', m: 0, w: false },
+ { v: 80, n: 'heating temperature', id: 'heatingtemp', m: 0, w: false },
+ { v: 70, n: 'burner pump max power', id: 'pumpmodmax', m: 0, w: false },
+ { v: 30, n: 'burner pump min power', id: 'pumpmodmin', m: 0, w: false },
+ { v: 1, n: 'pump delay', id: 'pumpdelay', m: 0, w: false },
+ { v: 10, n: 'burner min period', id: 'burnminperiod', m: 0, w: false },
+ { v: 0, n: 'burner min power', id: 'burnminpower', m: 0, w: false },
+ { v: 50, n: 'burner max power', id: 'burnmaxpower', m: 0, w: false },
+ { v: -6, n: 'hysteresis on temperature', id: 'boilhyston', m: 0, w: false },
+ { v: 6, n: 'hysteresis off temperature', id: 'boilhystoff', m: 0, w: false },
+ { v: 0, n: 'set flow temperature', id: 'setflowtemp', m: 0, w: true },
+ { v: 0, n: 'burner set power', id: 'setburnpow', m: 0, w: false },
+ { v: 0, n: 'burner current power', id: 'curburnpow', m: 0, w: false },
+ { v: 326323, n: 'burner starts', id: 'burnstarts', m: 0, w: false },
+ { v: 553437, n: 'total burner operating time', id: 'burnworkmin', m: 0, w: false },
+ { v: 451286, n: 'total heat operating time', id: 'heatworkmin', m: 0, w: false },
+ { v: 4672175, n: 'total UBA operating time', id: 'ubauptime', m: 0, w: false },
+ { v: '1C(210) 06.06.2020 12:07 (0 min)', n: 'last error code', id: 'lastcode', m: 0, w: false },
+ { v: '0H', n: 'service code', id: 'servicecode', m: 0, w: false },
+ { v: 203, n: 'service code number', id: 'servicecodenumber', m: 0, w: false },
+ { v: 'H00', n: 'maintenance message', id: 'maintenancemessage', m: 0, w: false },
+ { v: 'manual', n: 'maintenance scheduled', id: 'maintenance', m: 0, w: false },
+ { v: 6000, n: 'time to next maintenance', id: 'maintenancetime', m: 0, w: false },
+ { v: '01.01.2012', n: 'next maintenance date', id: 'maintenancedate', m: 0, w: false },
+ { v: true, n: 'dhw turn on/off', id: 'wwtapactivated', m: 0, w: false },
+ { v: 62, n: 'dhw set temperature', id: 'wwsettemp', m: 0, w: false },
+ { v: 60, n: 'dhw selected temperature', id: 'wwseltemp', m: 0, w: true },
+ { n: 'dhw selected lower temperature', id: 'wwseltemplow', m: 2 },
+ { n: 'dhw selected temperature for off', id: 'wwseltempoff', m: 2 },
+ { n: 'dhw single charge temperature', id: 'wwseltempsingle', m: 2 },
+ { v: 'flow', n: 'dhw type', id: 'wwtype', m: 0, w: false },
+ { v: 'hot', n: 'dhw comfort', id: 'wwcomfort', m: 0, w: false },
+ { v: 40, n: 'dhw flow temperature offset', id: 'wwflowtempoffset', m: 0, w: false },
+ { v: 100, n: 'dhw max power', id: 'wwmaxpower', m: 0, w: false },
+ { v: false, n: 'dhw circulation pump available', id: 'wwcircpump', m: 0, w: false },
+ { v: '3-way valve', n: 'dhw charging type', id: 'wwchargetype', m: 0, w: false },
+ { v: -5, n: 'dhw hysteresis on temperature', id: 'wwhyston', m: 0, w: false },
+ { v: 0, n: 'dhw hysteresis off temperature', id: 'wwhystoff', m: 0, w: false },
+ { v: 70, n: 'dhw disinfection temperature', id: 'wwdisinfectiontemp', m: 0, w: false },
+ { v: 'off', n: 'dhw circulation pump mode', id: 'wwcircmode', m: 0, w: false },
+ { v: false, n: 'dhw circulation active', id: 'wwcirc', m: 0, w: false },
+ { v: 46.4, n: 'dhw current intern temperature', id: 'wwcurtemp', m: 0, w: false },
+ { n: 'dhw current extern temperature', id: 'wwcurtemp2', m: 2 },
+ { v: 0, n: 'dhw current tap water flow', id: 'wwcurflow', m: 0, w: false },
+ { v: 46.3, n: 'dhw storage intern temperature', id: 'wwstoragetemp1', m: 0, w: false },
+ { n: 'dhw storage extern temperature', id: 'wwstoragetemp2', m: 2 },
+ { v: true, n: 'dhw activated', id: 'wwactivated', m: 0, w: false },
+ { v: false, n: 'dhw one time charging', id: 'wwonetime', m: 0, w: false },
+ { v: false, n: 'dhw disinfecting', id: 'wwdisinfecting', m: 0, w: false },
+ { v: false, n: 'dhw charging', id: 'wwcharging', m: 0, w: false },
+ { v: false, n: 'dhw recharging', id: 'wwrecharging', m: 0, w: false },
+ { v: true, n: 'dhw temperature ok', id: 'wwtempok', m: 0, w: false },
+ { v: false, n: 'dhw active', id: 'wwactive', m: 0, w: false },
+ { v: true, n: 'dhw 3way valve active', id: 'ww3wayvalve', m: 0, w: false },
+ { v: 0, n: 'dhw set pump power', id: 'wwsetpumppower', m: 0, w: true },
+ { n: 'dhw mixer temperature', id: 'wwmixertemp', m: 2 },
+ { n: 'dhw cylinder middle temperature (TS3)', id: 'wwcylmiddletemp', m: 2 },
+ { v: 288768, n: 'dhw starts', id: 'wwstarts', m: 0, w: false },
+ { v: 102151, n: 'dhw active time', id: 'wwworkm', m: 0, w: false },
]
const emsesp_deviceentities_4 = [
{
v: 16,
- id: 'hc2 selected room temperature',
- s: 'hc2/seltemp',
+ n: 'hc2 selected room temperature',
+ id: 'hc2/seltemp',
m: 8,
w: true,
},
{
v: 18.5,
- id: 'hc2 current room temperature',
- s: 'hc2/curtemp',
+ n: 'hc2 current room temperature',
+ id: 'hc2/curtemp',
m: 2,
w: false,
},
{
v: 'off',
- id: 'hc2 mode',
- s: 'hc2/mode',
+ n: 'hc2 mode',
+ id: 'hc2/mode',
m: 2,
w: true,
},
@@ -912,13 +929,13 @@ rest_server.post(EMSESP_DEVICEENTITIES_ENDPOINT, (req, res) => {
})
function updateMask(entity, de, dd) {
- const name = entity.slice(2)
+ const shortname = entity.slice(2)
const new_mask = parseInt(entity.slice(0, 2), 16)
- objIndex = de.findIndex((obj) => obj.s == name)
+ objIndex = de.findIndex((obj) => obj.id == shortname)
if (objIndex !== -1) {
de[objIndex].m = new_mask
- const fullname = de[objIndex].id
+ const fullname = de[objIndex].n
objIndex = dd.data.findIndex((obj) => obj.id.slice(2) == fullname)
if (objIndex !== -1) {
// see if the mask has changed
@@ -930,7 +947,7 @@ function updateMask(entity, de, dd) {
}
}
} else {
- console.log("can't locate record for id " + id)
+ console.log("can't locate record for name " + shortname)
}
}
diff --git a/pio_local.ini_example b/pio_local.ini_example
index 9d7c4cd8d..9c2db40f8 100644
--- a/pio_local.ini_example
+++ b/pio_local.ini_example
@@ -32,5 +32,5 @@ build_type = debug
monitor_filters = esp32_exception_decoder
debug_tool = esp-prog
debug_init_break = tbreak setup
-build_flags = ${factory_settings.build_flags} ${common.debug_flags} -DONEWIRE_CRC16=0 -DNO_GLOBAL_ARDUINOOTA -DARDUINOJSON_ENABLE_STD_STRING=1 -DESP32=1 -DARDUINO_ARCH_ESP32=1
+build_flags = ${factory_settings.build_flags} -DONEWIRE_CRC16=0 -DNO_GLOBAL_ARDUINOOTA -DARDUINOJSON_ENABLE_STD_STRING=1 -DESP32=1 -DARDUINO_ARCH_ESP32=1
extra_scripts = pre:scripts/build_interface.py
diff --git a/src/device_library.h b/src/device_library.h
index 21fd47917..acbbc514c 100644
--- a/src/device_library.h
+++ b/src/device_library.h
@@ -68,7 +68,7 @@
{224, DeviceType::CONTROLLER, F("9000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{229, DeviceType::CONTROLLER, F("8700i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
{230, DeviceType::CONTROLLER, F("BC Base"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
-{240, DeviceType::CONTROLLER, F("Rego 3000"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
+{240, DeviceType::CONTROLLER, F("Rego 3000"), DeviceFlags::EMS_DEVICE_FLAG_IVT}, // 0x09
{241, DeviceType::CONTROLLER, F("Condens 5000i"), DeviceFlags::EMS_DEVICE_FLAG_NONE}, // 0x09
// Thermostat - not currently supporting write operations, like the Easy/100 types - 0x18
diff --git a/src/devices/controller.cpp b/src/devices/controller.cpp
index f7b0b952f..e8e7af228 100644
--- a/src/devices/controller.cpp
+++ b/src/devices/controller.cpp
@@ -25,8 +25,10 @@ REGISTER_FACTORY(Controller, EMSdevice::DeviceType::CONTROLLER);
Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_id, const char * version, const std::string & name, uint8_t flags, uint8_t brand)
: EMSdevice(device_type, device_id, product_id, version, name, flags, brand) {
// IVT broadcasts Thermostat time from controller (0x09) if display is off.
- register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime));
- register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
+ if ((flags & 0x0F) == EMS_DEVICE_FLAG_IVT) {
+ register_telegram_type(0x06, F("RCTime"), false, MAKE_PF_CB(process_dateTime));
+ register_device_value(DeviceValueTAG::TAG_NONE, &dateTime_, DeviceValueType::STRING, nullptr, FL_(dateTime), DeviceValueUOM::NONE);
+ }
}
// process_dateTime - type 0x06 - date and time from a thermostat - 14 bytes long, IVT only
@@ -35,7 +37,7 @@ void Controller::process_dateTime(std::shared_ptr telegram) {
return;
}
char newdatetime[sizeof(dateTime_)];
- // publich as dd.mm.yyyy hh:mmF
+ // publish as dd.mm.yyyy hh:mmF
snprintf(newdatetime,
sizeof(dateTime_),
"%02d.%02d.%04d %02d:%02d",
@@ -47,5 +49,4 @@ void Controller::process_dateTime(std::shared_ptr telegram) {
has_update(dateTime_, newdatetime, sizeof(dateTime_));
}
-
} // namespace emsesp
\ No newline at end of file
diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp
index 29d2759a2..92561391a 100644
--- a/src/emsdevice.cpp
+++ b/src/emsdevice.cpp
@@ -716,11 +716,9 @@ void EMSdevice::generate_values_web(JsonObject & output) {
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. This is the id used for the table sorting
+ // add name, prefixing the tag if it exists. This is the id used in the WebUI table and must be unique
if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
obj["id"] = mask + read_flash_string(dv.full_name);
- } else if (dv.tag < DeviceValueTAG::TAG_HC1) {
- obj["id"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name);
} else {
obj["id"] = mask + tag_to_string(dv.tag) + " " + read_flash_string(dv.full_name);
}
@@ -775,7 +773,7 @@ void EMSdevice::generate_values_web(JsonObject & output) {
// as generate_values_web() but stripped down to only show all entities and their state
// this is used only for WebCustomizationService::device_entities()
-void EMSdevice::generate_values_web_all(JsonArray & output) {
+void EMSdevice::generate_values_web_customization(JsonArray & output) {
for (const auto & dv : devicevalues_) {
// also show commands and entities that have an empty full name
JsonObject obj = output.createNestedObject();
@@ -831,29 +829,29 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
obj["v"] = (divider > 0) ? time_value / divider : time_value * factor; // sometimes we need to divide by 60
}
}
- } else {
- // must always have v for sorting to work in web
- obj["v"] = "";
}
- // add name, prefixing the tag if it exists as the id (key for table sorting)
- if (dv.full_name) {
- if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
- obj["id"] = dv.full_name;
- } else {
- char name[50];
- snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str());
- obj["id"] = name;
+ // id holds the shortname and must always have a value for the WebUI table to work
+ if (dv.tag >= DeviceValueTAG::TAG_HC1) {
+ obj["id"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
+ } else {
+ obj["id"] = read_flash_string(dv.short_name);
+ }
+
+ // n is the fullname, and can be optional
+ // don't add the fullname if its a command
+ if (dv.type != DeviceValueType::CMD) {
+ if (dv.full_name) {
+ if ((dv.tag == DeviceValueTAG::TAG_NONE) || tag_to_string(dv.tag).empty()) {
+ obj["n"] = dv.full_name;
+ } else {
+ char name[50];
+ snprintf(name, sizeof(name), "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str());
+ obj["n"] = name;
+ }
}
} else {
- obj["id"] = "";
- }
-
- // shortname
- if (dv.tag >= DeviceValueTAG::TAG_HC1) {
- obj["s"] = tag_to_string(dv.tag) + "/" + read_flash_string(dv.short_name);
- } else {
- obj["s"] = dv.short_name;
+ obj["n"] = "";
}
obj["m"] = dv.state >> 4; // send back the mask state. We're only interested in the high nibble
diff --git a/src/emsdevice.h b/src/emsdevice.h
index 3da12a4e3..603e353c8 100644
--- a/src/emsdevice.h
+++ b/src/emsdevice.h
@@ -200,7 +200,7 @@ class EMSdevice {
enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT, CONSOLE };
bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target);
void generate_values_web(JsonObject & output);
- void generate_values_web_all(JsonArray & output);
+ void generate_values_web_customization(JsonArray & output);
void register_device_value(uint8_t tag,
void * value_p,
@@ -315,6 +315,9 @@ class EMSdevice {
// device flags: The lower 4 bits hold the unique identifier, the upper 4 bits are used for specific flags
static constexpr uint8_t EMS_DEVICE_FLAG_NONE = 0;
+ // Controller
+ static constexpr uint8_t EMS_DEVICE_FLAG_IVT = 1;
+
// Boiler
static constexpr uint8_t EMS_DEVICE_FLAG_EMS = 1;
static constexpr uint8_t EMS_DEVICE_FLAG_EMSPLUS = 2;
diff --git a/src/locale_EN.h b/src/locale_EN.h
index 5ddf6dc1e..72ea00698 100644
--- a/src/locale_EN.h
+++ b/src/locale_EN.h
@@ -616,7 +616,7 @@ MAKE_PSTR_LIST(wwDailyHeating, F("wwdailyheating"), F("daily heating"))
MAKE_PSTR_LIST(wwDailyHeatTime, F("wwdailyheattime"), F("daily heating time"))
MAKE_PSTR_LIST(wwWhenModeOff, F("wwwhenmodeoff"), F("when thermostat mode off"))
// thermostat hc
-MAKE_PSTR_LIST(climate, F("climate"))
+MAKE_PSTR_LIST(climate, F("HA climate config creation")) // no full-name, hidden, only for creation
MAKE_PSTR_LIST(selRoomTemp, F("seltemp"), F("selected room temperature"))
MAKE_PSTR_LIST(roomTemp, F("currtemp"), F("current room temperature"))
MAKE_PSTR_LIST(mode, F("mode"), F("mode"))
diff --git a/src/test/test.cpp b/src/test/test.cpp
index 3d320bb47..2b77622f1 100644
--- a/src/test/test.cpp
+++ b/src/test/test.cpp
@@ -418,7 +418,7 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// emsdevice->generate_values_web(root);
JsonArray output = doc.to();
- emsdevice->generate_values_web_all(output);
+ emsdevice->generate_values_web_customization(output);
Serial.print(COLOR_BRIGHT_MAGENTA);
serializeJson(doc, Serial);
diff --git a/src/version.h b/src/version.h
index f1435b3b3..4b5f64b27 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1 +1 @@
-#define EMSESP_APP_VERSION "3.4.0"
+#define EMSESP_APP_VERSION "3.4.1"
diff --git a/src/web/WebAPIService.cpp b/src/web/WebAPIService.cpp
index 5ab041987..407e33fb2 100644
--- a/src/web/WebAPIService.cpp
+++ b/src/web/WebAPIService.cpp
@@ -132,6 +132,7 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
JsonVariant data = output["api_data"];
request->send(200, "text/plain; charset=utf-8", data.as());
api_count_++;
+ delete response;
return;
}
diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp
index 2634030fd..9c9f16f20 100644
--- a/src/web/WebCustomizationService.cpp
+++ b/src/web/WebCustomizationService.cpp
@@ -196,7 +196,7 @@ void WebCustomizationService::device_entities(AsyncWebServerRequest * request, J
if (emsdevice->unique_id() == json["id"]) {
#ifndef EMSESP_STANDALONE
JsonArray output = response->getRoot();
- emsdevice->generate_values_web_all(output);
+ emsdevice->generate_values_web_customization(output);
#endif
response->setLength();
request->send(response);