diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index 9fa642937..97047f74f 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -21,10 +21,11 @@ - Added scripts for OTA (scripts/upload.py and upload_cli.py) [#1738](https://github.com/emsesp/EMS-ESP32/issues/1738) - timeout for remote thermostat emulation [#1680](https://github.com/emsesp/EMS-ESP32/discussions/1680), [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774) - CR120 thermostat as own model() [#1779](https://github.com/emsesp/EMS-ESP32/discussions/1779) -- Modules - external linkable module library [#1778](https://github.com/emsesp/EMS-ESP32/issues/1778) -- Scheduler onChange and Conditions [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806) +- modules - external linkable module library [#1778](https://github.com/emsesp/EMS-ESP32/issues/1778) +- scheduler onChange and Conditions [#1806](https://github.com/emsesp/EMS-ESP32/issues/1806) - make remote control timeout editable [#1774](https://github.com/emsesp/EMS-ESP32/issues/1774) - added extra pump characteristics (mode and pressure for EMS+) by @SLTKA [#1802](https://github.com/emsesp/EMS-ESP32/pull/1802) +- allow device name to be customized [#1174](https://github.com/emsesp/EMS-ESP32/issues/1174) ## Fixed diff --git a/interface/package.json b/interface/package.json index 62c205e82..e2fc7d328 100644 --- a/interface/package.json +++ b/interface/package.json @@ -47,7 +47,7 @@ "react-router-dom": "^6.24.0", "react-toastify": "^10.0.5", "typesafe-i18n": "^5.26.2", - "typescript": "^5.5.2" + "typescript": "^5.5.3" }, "devDependencies": { "@babel/core": "^7.24.7", @@ -59,12 +59,12 @@ "concurrently": "^8.2.2", "eslint": "^9.6.0", "eslint-config-prettier": "^9.1.0", - "preact": "^10.22.0", + "preact": "^10.22.1", "prettier": "^3.3.2", "rollup-plugin-visualizer": "^5.12.0", "terser": "^5.31.1", - "typescript-eslint": "^7.14.1", - "vite": "^5.3.2", + "typescript-eslint": "^7.15.0", + "vite": "^5.3.3", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^4.3.2" }, diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index b04338932..9627a017d 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -331,7 +331,8 @@ const de: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index d996e5c06..3846441bf 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -331,7 +331,8 @@ const en: Translation = { MODULES: 'Modules', MODULES_UPDATED: 'Modules updated', MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', - MODULES_NONE: 'No external modules detected' + MODULES_NONE: 'No external modules detected', + RENAME: 'Rename' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 0e1d46f37..fb4e0de39 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -331,7 +331,8 @@ const fr: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index eae77f1a2..124e76a04 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -331,7 +331,8 @@ const it: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 6b2c1a00d..02d2e5ea5 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -331,7 +331,8 @@ const nl: Translation = { MODULES: 'Module', MODULES_UPDATED: 'Modules geüpdatet', MODULES_DESCRIPTION: 'Klik op de module om EMS-ESP library modules te activeren of te deactiveren', - MODULES_NONE: 'Geen externe modules gedetecteerd' + MODULES_NONE: 'Geen externe modules gedetecteerd', + RENAME: 'Hernoemen' }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 025cb91a8..2d053ebe7 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -331,7 +331,8 @@ const no: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 6896051fe..b367ebce9 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -331,7 +331,8 @@ const pl: BaseTranslation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default pl; diff --git a/interface/src/i18n/sk/index.ts b/interface/src/i18n/sk/index.ts index 43ae4ac38..cd83f5893 100644 --- a/interface/src/i18n/sk/index.ts +++ b/interface/src/i18n/sk/index.ts @@ -331,7 +331,7 @@ const sk: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; - export default sk; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index ca9952708..6977ee6c7 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -331,7 +331,8 @@ const sv: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 44ab06c5d..9b95cf8d8 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -331,7 +331,8 @@ const tr: Translation = { MODULES: 'Module', // TODO translate MODULES_UPDATED: 'Modules updated', // TODO translate MODULES_DESCRIPTION: 'Click on the Module to activate or de-activate EMS-ESP library modules', // TODO translate - MODULES_NONE: 'No external modules detected' // TODO translate + MODULES_NONE: 'No external modules detected', // TODO translate + RENAME: 'Rename' // TODO translate }; export default tr; diff --git a/interface/src/project/Customization.tsx b/interface/src/project/Customization.tsx index 9293cad7c..be34f04bf 100644 --- a/interface/src/project/Customization.tsx +++ b/interface/src/project/Customization.tsx @@ -4,7 +4,9 @@ import { useBlocker, useLocation } from 'react-router-dom'; import { toast } from 'react-toastify'; import CancelIcon from '@mui/icons-material/Cancel'; +import EditIcon from '@mui/icons-material/Edit'; import PowerSettingsNewIcon from '@mui/icons-material/PowerSettingsNew'; +import SaveIcon from '@mui/icons-material/Save'; import SearchIcon from '@mui/icons-material/Search'; import SettingsBackupRestoreIcon from '@mui/icons-material/SettingsBackupRestore'; import WarningIcon from '@mui/icons-material/Warning'; @@ -71,21 +73,31 @@ const Customization: FC = () => { const [search, setSearch] = useState(''); const [selectedDeviceEntity, setSelectedDeviceEntity] = useState(); const [dialogOpen, setDialogOpen] = useState(false); + const [rename, setRename] = useState(false); useLayoutTitle(LL.CUSTOMIZATIONS()); // fetch devices first - const { data: devices } = useRequest(EMSESP.readDevices); + const { data: devices, send: fetchDevices } = useRequest(EMSESP.readDevices); const [selectedDevice, setSelectedDevice] = useState( Number(useLocation().state) || -1 ); + const [selectedDeviceTypeNameURL, setSelectedDeviceTypeNameURL] = + useState(''); // needed for API URL const [selectedDeviceName, setSelectedDeviceName] = useState(''); const { send: resetCustomizations } = useRequest(EMSESP.resetCustomizations(), { immediate: false }); + const { send: writeDeviceName } = useRequest( + (data: { id: number; name: string }) => EMSESP.writeDeviceName(data), + { + immediate: false + } + ); + const { send: writeCustomizationEntities } = useRequest( (data: { id: number; entity_ids: string[] }) => EMSESP.writeCustomizationEntities(data), @@ -223,9 +235,10 @@ const Customization: FC = () => { const id = devices.devices.findIndex((d) => d.i === selectedDevice); if (id === -1) { setSelectedDevice(-1); - setSelectedDeviceName(''); + setSelectedDeviceTypeNameURL(''); } else { - setSelectedDeviceName(devices.devices[id].tn || ''); + setSelectedDeviceTypeNameURL(devices.devices[id].url || ''); + setSelectedDeviceName(devices.devices[id].s); setNumChanges(0); setRestartNeeded(false); } @@ -388,31 +401,87 @@ const Customization: FC = () => { } }; + const renameDevice = async () => { + await writeDeviceName({ id: selectedDevice, name: selectedDeviceName }) + .then(() => { + toast.success(LL.UPDATED_OF(LL.NAME(1))); + }) + .catch(() => { + toast.error(LL.UPDATE_OF(LL.NAME(1)) + ' ' + LL.FAILED(1)); + }) + .finally(async () => { + setRename(false); + await fetchDevices(); + }); + }; + const renderDeviceList = () => ( <> {LL.CUSTOMIZATIONS_HELP_1()}. - setSelectedDevice(parseInt(e.target.value))} - margin="normal" - select - > - - {LL.SELECT_DEVICE()}... - - {devices.devices.map((device: DeviceShort) => ( - - {device.s} - - ))} - + + {rename ? ( + setSelectedDeviceName(e.target.value)} + margin="normal" + /> + ) : ( + setSelectedDevice(parseInt(e.target.value))} + margin="normal" + style={{ minWidth: '50%' }} + select + > + + {LL.SELECT_DEVICE()}... + + {devices.devices.map((device: DeviceShort) => ( + + {device.s} ({device.tn}) + + ))} + + )} + {selectedDevice !== -1 && + (rename ? ( + + + + + ) : ( + + ))} + ); @@ -545,7 +614,7 @@ const Customization: FC = () => { {formatName(de, false)} ( {de.id} @@ -600,7 +669,7 @@ const Customization: FC = () => { const renderContent = () => ( <> {devices && renderDeviceList()} - {selectedDevice !== -1 && renderDeviceData()} + {selectedDevice !== -1 && !rename && renderDeviceData()} {restartNeeded && (