From d12879b07b532d047401f350d5b7004a487a39a2 Mon Sep 17 00:00:00 2001 From: Proddy Date: Sun, 24 Jul 2022 13:39:52 +0200 Subject: [PATCH] link to device entity details from customization page --- .../src/project/SettingsCustomization.tsx | 62 ++++++++----------- interface/src/project/types.ts | 5 +- mock-api/server.js | 5 +- src/web/WebCustomizationService.cpp | 13 ++-- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/interface/src/project/SettingsCustomization.tsx b/interface/src/project/SettingsCustomization.tsx index 3e74419e7..cdaeec26d 100644 --- a/interface/src/project/SettingsCustomization.tsx +++ b/interface/src/project/SettingsCustomization.tsx @@ -13,7 +13,8 @@ import { ToggleButtonGroup, Tooltip, Grid, - TextField + TextField, + Link } from '@mui/material'; import { Table } from '@table-library/react-table-library/table'; @@ -26,11 +27,6 @@ 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 SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'; import KeyboardArrowUpOutlinedIcon from '@mui/icons-material/KeyboardArrowUpOutlined'; import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined'; @@ -48,13 +44,15 @@ import { extractErrorMessage } from '../utils'; import { DeviceShort, Devices, DeviceEntity, DeviceEntityMask } from './types'; +export const APIURL = window.location.origin + '/api/'; + const SettingsCustomization: FC = () => { const { enqueueSnackbar } = useSnackbar(); 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); + const [selectedDevice, setSelectedDevice] = useState(-1); const [confirmReset, setConfirmReset] = useState(false); const [selectedFilters, setSelectedFilters] = useState(0); const [search, setSearch] = useState(''); @@ -94,7 +92,6 @@ const SettingsCustomization: FC = () => { Row: ` background-color: #1e1e1e; position: relative; - cursor: pointer; .td { border-top: 1px solid #565656; @@ -107,11 +104,6 @@ const SettingsCustomization: FC = () => { font-weight: normal; } - &:hover .td { - border-top: 1px solid #177ac9; - border-bottom: 1px solid #177ac9; - } - &:nth-of-type(odd) .td { background-color: #303030; } @@ -194,7 +186,15 @@ const SettingsCustomization: FC = () => { } else if (de.n === '') { return 'Command: ' + de.id; } - return de.n + ' (' + de.id + ')'; + return ( + <> + {de.n} ( + + {de.id} + + ) + + ); } const getMaskNumber = (newMask: string[]) => { @@ -239,20 +239,12 @@ const SettingsCustomization: FC = () => { ); }; - function compareDevices(a: DeviceShort, b: DeviceShort) { - if (a.s < b.s) { - return -1; - } - if (a.s > b.s) { - return 1; - } - return 0; - } - const changeSelectedDevice = (event: React.ChangeEvent) => { - const selected_device = parseInt(event.target.value, 10); - setSelectedDevice(selected_device); - fetchDeviceEntities(selected_device); + if (devices) { + const selected_device = parseInt(event.target.value, 10); + setSelectedDevice(selected_device); + fetchDeviceEntities(devices?.devices[selected_device].i); + } }; const resetCustomization = async () => { @@ -267,7 +259,7 @@ const SettingsCustomization: FC = () => { }; const saveCustomization = async () => { - if (deviceEntities && selectedDevice) { + if (devices && deviceEntities && selectedDevice !== -1) { const masked_entities = deviceEntities .filter((de) => de.m !== de.om) .map((new_de) => new_de.m.toString(16).padStart(2, '0') + new_de.id); @@ -279,7 +271,7 @@ const SettingsCustomization: FC = () => { try { const response = await EMSESP.writeMaskedEntities({ - id: selectedDevice, + id: devices?.devices[selectedDevice].i, entity_ids: masked_entities }); if (response.status === 200) { @@ -305,13 +297,13 @@ const SettingsCustomization: FC = () => { Select a device and customize each of its entities using the options: - =mark as a favorite   + =mark as favorite   =disable write action   - =exclude from MQTT and API outputs   + =exclude from MQTT and API   - =hide from Web Dashboard + =hide from Dashboard { margin="normal" select > - + Select a device... - {devices.devices.sort(compareDevices).map((device: DeviceShort, index) => ( - + {devices.devices.map((device: DeviceShort, index) => ( + {device.s} ))} diff --git a/interface/src/project/types.ts b/interface/src/project/types.ts index a3bd4b53c..0d5a1834b 100644 --- a/interface/src/project/types.ts +++ b/interface/src/project/types.ts @@ -104,9 +104,10 @@ export interface CoreData { export interface DeviceShort { i: number; // id - d: number; // deviceid - p: number; // productid + d?: number; // deviceid + p?: number; // productid s: string; // shortname + t?: string; // device type name } export interface Devices { diff --git a/mock-api/server.js b/mock-api/server.js index 96fdb18a3..1e6ebef3a 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -347,18 +347,21 @@ const emsesp_devices = { d: 23, p: 77, s: 'Thermostat (RC20/Moduline 300)', + t: 'thermostat1', }, { i: 2, d: 8, p: 123, s: 'Boiler (Nefit GBx72/Trendline/Cerapur/Greenstar Si/27i)', + t: 'boiler', }, { i: 4, d: 16, p: 165, s: 'Thermostat (RC100/Moduline 1000/1010)', + t: 'thermostat2', }, ], } @@ -1224,8 +1227,8 @@ rest_server.get(GET_CUSTOMIZATIONS_ENDPOINT, (req, res) => { // start server const expressServer = rest_server.listen(port, () => + console.log(`EMS-ESP REST API server running on http://localhost:${port}/api`), ) -console.log(`EMS-ESP Rest API listening to http://localhost:${port}/api`) // start websocket server const websocketServer = new WebSocket.Server({ diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 1b37c830e..36dfb2e16 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -165,22 +165,23 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) { auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN); JsonObject root = response->getRoot(); + // list is already sorted by device type + // controller is ignored since it doesn't have any associated entities JsonArray devices = root.createNestedArray("devices"); for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice->has_entities()) { JsonObject obj = devices.createNestedObject(); - obj["i"] = emsdevice->unique_id(); // a unique id + obj["i"] = emsdevice->unique_id(); // its unique id + obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; // shortname - /* + // device type name. We may have one than one (e.g. multiple thermostats) so postfix name with index uint8_t device_index = EMSESP::device_index(emsdevice->device_type(), emsdevice->unique_id()); if (device_index) { char s[10]; - obj["s"] = emsdevice->device_type_name() + Helpers::smallitoa(s, device_index) + " (" + emsdevice->name() + ")"; // shortname - we prefix the count to make it unique + obj["t"] = Helpers::toLower(emsdevice->device_type_name()) + Helpers::smallitoa(s, device_index); } else { - obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; + obj["t"] = Helpers::toLower(emsdevice->device_type_name()); } - */ - obj["s"] = emsdevice->device_type_name() + " (" + emsdevice->name() + ")"; } }