From 68036f6467b7012621247fa8a6eb013038d1dd8e Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:01:29 +0200 Subject: [PATCH 01/17] 3.7.0-dev.37 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 2c0569424..68f176080 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define EMSESP_APP_VERSION "3.7.0-dev.36" +#define EMSESP_APP_VERSION "3.7.0-dev.37" From 003d78be9f8acaf9425bbeead0035b5d160509ee Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:01:43 +0200 Subject: [PATCH 02/17] update dictionary --- cspell.json | 2 +- project-words.txt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cspell.json b/cspell.json index f617c827b..b5dc0b7ad 100644 --- a/cspell.json +++ b/cspell.json @@ -9,5 +9,5 @@ } ], "dictionaries": ["project-words"], - "ignorePaths": ["node_modules", "**/venv/**", "lib/eModbus", "lib/ESPAsyncWebServer", "lib/espMqttClient", "analyse.html", "dist", "**/*.csv", "locale_translations.h", "TZ.tsx", "**/*.txt","build/**", "**/i18n/**", "/project-words.txt"] + "ignorePaths": ["node_modules", "WWWData.h", "**/venv/**", "lib/eModbus", "lib/ESPAsyncWebServer", "lib/espMqttClient", "analyse.html", "dist", "**/*.csv", "locale_translations.h", "TZ.tsx", "**/*.txt","build/**", "**/i18n/**", "/project-words.txt"] } \ No newline at end of file diff --git a/project-words.txt b/project-words.txt index c941c8e0c..d1ea72cb8 100644 --- a/project-words.txt +++ b/project-words.txt @@ -464,7 +464,7 @@ GPOC Greenstar Grokhotkov haclimate -hardwarestatus +systemstatus Harwerth headersize headertemp @@ -1344,4 +1344,5 @@ zuluftgebläse zulufttemp zyxwvutsrqponmlkjihgfedcba Omea -Bolv \ No newline at end of file +Bolv +hardwarestatus \ No newline at end of file From dd1ed08f7c20f361d9ff885fd4a8e5a04697e007 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:01:59 +0200 Subject: [PATCH 03/17] remove .txt and .csv --- interface/src/components/upload/DragNdrop.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/components/upload/DragNdrop.tsx b/interface/src/components/upload/DragNdrop.tsx index a659bd106..d9d06c585 100644 --- a/interface/src/components/upload/DragNdrop.tsx +++ b/interface/src/components/upload/DragNdrop.tsx @@ -16,7 +16,7 @@ const DragNdrop = ({ onFileSelected }) => { const { LL } = useI18nContext(); const checkFileExtension = (file: File) => { - const validExtensions = ['.json', '.txt', '.csv', '.bin', '.md5']; + const validExtensions = ['.json', '.bin', '.md5']; const fileName = file.name; const fileExtension = fileName.substring(fileName.lastIndexOf('.')); if (validExtensions.includes(fileExtension)) { From 63a3152b916de7e4aa918e45b46d25158cb3fff5 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:02:19 +0200 Subject: [PATCH 04/17] remove unused useRequest --- interface/src/app/status/SystemLog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/app/status/SystemLog.tsx b/interface/src/app/status/SystemLog.tsx index 13c0235c6..7aaeea32c 100644 --- a/interface/src/app/status/SystemLog.tsx +++ b/interface/src/app/status/SystemLog.tsx @@ -8,7 +8,7 @@ import Grid from '@mui/material/Grid2'; import { fetchLogES, readLogSettings, updateLogSettings } from 'api/system'; -import { useRequest, useSSE } from 'alova/client'; +import { useSSE } from 'alova/client'; import { BlockFormControlLabel, BlockNavigation, From 191edffe3c52425a0344bc4d3c65cefc051d69a6 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:03:11 +0200 Subject: [PATCH 05/17] optimize endpoints, so re-use where possible --- interface/src/api/app.ts | 10 +- interface/src/api/system.ts | 8 +- interface/src/app/main/Customizations.tsx | 24 +- interface/src/app/main/types.ts | 15 +- .../src/app/settings/ApplicationSettings.tsx | 4 +- interface/src/app/settings/DownloadUpload.tsx | 93 ++----- interface/src/app/status/HardwareStatus.tsx | 2 +- interface/src/app/status/RestartMonitor.tsx | 6 +- interface/src/app/status/Status.tsx | 8 +- interface/src/types/system.ts | 29 +-- mock-api/rest_server.ts | 240 +++++++----------- src/system.cpp | 2 - src/web/WebCustomEntityService.cpp | 16 -- src/web/WebCustomEntityService.h | 1 - src/web/WebCustomizationService.cpp | 43 ---- src/web/WebCustomizationService.h | 4 - src/web/WebDataService.cpp | 1 + src/web/WebSchedulerService.cpp | 16 -- src/web/WebSchedulerService.h | 3 - src/web/WebSettingsService.cpp | 24 -- src/web/WebSettingsService.h | 2 - src/web/WebStatusService.cpp | 63 +++-- src/web/WebStatusService.h | 6 +- 23 files changed, 192 insertions(+), 428 deletions(-) diff --git a/interface/src/api/app.ts b/interface/src/api/app.ts index 886c00236..1863a6893 100644 --- a/interface/src/api/app.ts +++ b/interface/src/api/app.ts @@ -6,7 +6,6 @@ import type { CoreData, DeviceData, DeviceEntity, - Devices, Entities, EntityItem, ModuleItem, @@ -53,11 +52,9 @@ export const readActivity = () => alovaInstance.Get('/rest/activity'); // API export const API = (apiCall: APIcall) => alovaInstance.Post('/api', apiCall); -// UploadFileForm -export const getSettings = () => alovaInstance.Get('/rest/getSettings'); -export const getCustomizations = () => alovaInstance.Get('/rest/getCustomizations'); -export const getEntities = () => alovaInstance.Get('/rest/getEntities'); -export const getSchedule = () => alovaInstance.Get('/rest/getSchedule'); +// DownloadUpload +export const exportData = (type: string) => + alovaInstance.Get('/rest/exportData', { params: { type } }); // SettingsCustomization export const readDeviceEntities = (id: number) => @@ -75,7 +72,6 @@ export const readDeviceEntities = (id: number) => })); } }); -export const readDevices = () => alovaInstance.Get('/rest/devices'); export const resetCustomizations = () => alovaInstance.Post('/rest/resetCustomizations'); export const writeCustomizationEntities = (data: { diff --git a/interface/src/api/system.ts b/interface/src/api/system.ts index 6585a0b85..b1d4298e0 100644 --- a/interface/src/api/system.ts +++ b/interface/src/api/system.ts @@ -1,12 +1,8 @@ -import type { HardwareStatus, LogSettings, SystemStatus } from 'types'; +import type { LogSettings, SystemStatus } from 'types'; import { alovaInstance, alovaInstanceGH } from './endpoints'; -// hardwareStatus - also used to ping in Restart monitor for pinging -export const readHardwareStatus = () => - alovaInstance.Get('/rest/hardwareStatus'); - -// SystemStatus +// systemStatus - also used to ping in Restart monitor for pinging export const readSystemStatus = () => alovaInstance.Get('/rest/systemStatus'); diff --git a/interface/src/app/main/Customizations.tsx b/interface/src/app/main/Customizations.tsx index 4fcbe15c6..24b105ec6 100644 --- a/interface/src/app/main/Customizations.tsx +++ b/interface/src/app/main/Customizations.tsx @@ -50,8 +50,8 @@ import { useI18nContext } from 'i18n/i18n-react'; import { API, + readCoreData, readDeviceEntities, - readDevices, resetCustomizations, writeCustomizationEntities, writeDeviceName @@ -60,7 +60,7 @@ import SettingsCustomizationsDialog from './CustomizationsDialog'; import EntityMaskToggle from './EntityMaskToggle'; import OptionIcon from './OptionIcon'; import { DeviceEntityMask } from './types'; -import type { APIcall, DeviceEntity, DeviceShort } from './types'; +import type { APIcall, Device, DeviceEntity } from './types'; export const APIURL = window.location.origin + '/api/'; @@ -81,8 +81,8 @@ const Customizations = () => { useLayoutTitle(LL.CUSTOMIZATIONS()); - // fetch devices first - const { data: devices, send: fetchDevices } = useRequest(readDevices); + // fetch devices first from coreData + const { data: devices, send: fetchCoreData } = useRequest(readCoreData); const { send: sendAPI } = useRequest((data: APIcall) => API(data), { immediate: false @@ -242,13 +242,13 @@ const Customizations = () => { useEffect(() => { if (devices && selectedDevice !== -1) { void sendDeviceEntities(selectedDevice); - const id = devices.devices.findIndex((d) => d.i === selectedDevice); - if (id === -1) { + const index = devices.devices.findIndex((d) => d.id === selectedDevice); + if (index === -1) { setSelectedDevice(-1); setSelectedDeviceTypeNameURL(''); } else { - setSelectedDeviceTypeNameURL(devices.devices[id].url || ''); - setSelectedDeviceName(devices.devices[id].s); + setSelectedDeviceTypeNameURL(devices.devices[index].url || ''); + setSelectedDeviceName(devices.devices[index].n); setNumChanges(0); setRestartNeeded(false); } @@ -414,7 +414,7 @@ const Customizations = () => { }) .finally(async () => { setRename(false); - await fetchDevices(); + await fetchCoreData(); }); }; @@ -449,9 +449,9 @@ const Customizations = () => { {LL.SELECT_DEVICE()}... - {devices.devices.map((device: DeviceShort) => ( - - {device.s} ({device.tn}) + {devices.devices.map((device: Device) => ( + + {device.n} ({device.tn}) ))} diff --git a/interface/src/app/main/types.ts b/interface/src/app/main/types.ts index 093b55a9d..8aa183705 100644 --- a/interface/src/app/main/types.ts +++ b/interface/src/app/main/types.ts @@ -71,6 +71,7 @@ export interface Device { p: number; // productid v: string; // version e: number; // entities + url?: string; // lowercase type name used in API URL } export interface TemperatureSensor { @@ -113,20 +114,6 @@ export interface CoreData { devices: Device[]; } -export interface DeviceShort { - i: number; // id - d?: number; // deviceid - p?: number; // productid - s: string; // shortname - t?: number; // device type id - tn?: string; // device type internal name (translated) - url?: string; // lowercase type name used in API URL -} - -export interface Devices { - devices: DeviceShort[]; -} - export interface DeviceValue { id: string; // index, contains mask+name v: unknown; // value, Number or String diff --git a/interface/src/app/settings/ApplicationSettings.tsx b/interface/src/app/settings/ApplicationSettings.tsx index 9daf45b74..946f295fd 100644 --- a/interface/src/app/settings/ApplicationSettings.tsx +++ b/interface/src/app/settings/ApplicationSettings.tsx @@ -16,7 +16,7 @@ import { } from '@mui/material'; import Grid from '@mui/material/Grid2'; -import { readHardwareStatus } from 'api/system'; +import { readSystemStatus } from 'api/system'; import { useRequest } from 'alova/client'; import RestartMonitor from 'app/status/RestartMonitor'; @@ -49,7 +49,7 @@ export function boardProfileSelectItems() { } const ApplicationSettings = () => { - const { data: hardwareData } = useRequest(readHardwareStatus); + const { data: hardwareData } = useRequest(readSystemStatus); const { loadData, diff --git a/interface/src/app/settings/DownloadUpload.tsx b/interface/src/app/settings/DownloadUpload.tsx index 11dc3f45a..c222c4901 100644 --- a/interface/src/app/settings/DownloadUpload.tsx +++ b/interface/src/app/settings/DownloadUpload.tsx @@ -18,13 +18,7 @@ import { import Grid from '@mui/material/Grid2'; import * as SystemApi from 'api/system'; -import { - API, - getCustomizations, - getEntities, - getSchedule, - getSettings -} from 'api/app'; +import { API, exportData } from 'api/app'; import { checkUpgrade, getDevVersion, @@ -52,48 +46,26 @@ const DownloadUpload = () => { const [useDev, setUseDev] = useState(false); const [upgradeAvailable, setUpgradeAvailable] = useState(false); - const { send: sendSettings } = useRequest(getSettings(), { - immediate: false - }).onSuccess((event) => { - saveFile(event.data, 'settings.json'); - }); - - const { send: sendCustomizations } = useRequest(getCustomizations(), { - immediate: false - }).onSuccess((event) => { - saveFile(event.data, 'customizations.json'); - }); - - const { send: sendEntities } = useRequest(getEntities(), { - immediate: false - }).onSuccess((event) => { - saveFile(event.data, 'custom_entities.json'); - }); - - const { send: sendSchedule } = useRequest(getSchedule(), { + const { send: sendExportData } = useRequest((type: string) => exportData(type), { immediate: false - }).onSuccess((event) => { - saveFile(event.data, 'schedule.json'); - }); + }) + .onSuccess((event) => { + saveFile(event.data, event.args[0]); + toast.info(LL.DOWNLOAD_SUCCESSFUL()); + }) + .onError((error) => { + toast.error(error.message); + }); const { send: sendAPI } = useRequest((data: APIcall) => API(data), { immediate: false }); - const { send: sendAPIandSave } = useRequest((data: APIcall) => API(data), { - immediate: false - }).onSuccess((event) => { - saveFile( - event.data, - String(event.args[0].device) + '_' + String(event.args[0].cmd) + '.txt' - ); - }); - const { data: data, send: loadData, error - } = useRequest(SystemApi.readHardwareStatus); + } = useRequest(SystemApi.readSystemStatus); const { send: sendUploadURL } = useRequest( (data: { url: string }) => uploadURL(data), @@ -123,6 +95,8 @@ const DownloadUpload = () => { // immediate: false, // initialData: '3.6.5' }); + + // called immediately to get the latest version, on page load, then check for upgrade const { data: latestDevVersion } = useRequest(getDevVersion, { // uncomment next 2 lines for testing, uses https://github.com/emsesp/EMS-ESP32/releases/download/latest/EMS-ESP-3_7_0-dev_31-ESP32-16MB+.bin // immediate: false, @@ -175,40 +149,9 @@ const DownloadUpload = () => { type: 'text/plain' }) ); - anchor.download = 'emsesp_' + filename; + anchor.download = 'emsesp_' + filename + '.json'; anchor.click(); URL.revokeObjectURL(anchor.href); - toast.info(LL.DOWNLOAD_SUCCESSFUL()); - }; - - const downloadSettings = async () => { - await sendSettings().catch((error: Error) => { - toast.error(error.message); - }); - }; - - const downloadCustomizations = async () => { - await sendCustomizations().catch((error: Error) => { - toast.error(error.message); - }); - }; - - const downloadEntities = async () => { - await sendEntities().catch((error: Error) => { - toast.error(error.message); - }); - }; - - const downloadSchedule = async () => { - await sendSchedule().catch((error: Error) => { - toast.error(error.message); - }); - }; - - const callAPIandSave = async (device: string, cmd: string) => { - await sendAPIandSave({ device, cmd, id: 0 }).catch((error: Error) => { - toast.error(error.message); - }); }; useLayoutTitle(LL.DOWNLOAD_UPLOAD()); @@ -301,7 +244,7 @@ const DownloadUpload = () => { startIcon={} variant="outlined" color="primary" - onClick={downloadSettings} + onClick={() => sendExportData('settings')} > {LL.DOWNLOAD(1)} {LL.SETTINGS_OF(LL.APPLICATION())} @@ -311,7 +254,7 @@ const DownloadUpload = () => { startIcon={} variant="outlined" color="primary" - onClick={downloadCustomizations} + onClick={() => sendExportData('customizations')} > {LL.DOWNLOAD(1)} {LL.CUSTOMIZATIONS()} @@ -320,7 +263,7 @@ const DownloadUpload = () => { startIcon={} variant="outlined" color="primary" - onClick={downloadEntities} + onClick={() => sendExportData('entities')} > {LL.DOWNLOAD(1)} {LL.CUSTOM_ENTITIES(0)} @@ -329,7 +272,7 @@ const DownloadUpload = () => { startIcon={} variant="outlined" color="primary" - onClick={downloadSchedule} + onClick={() => sendExportData('schedule')} > {LL.DOWNLOAD(1)} {LL.SCHEDULE(0)} diff --git a/interface/src/app/status/HardwareStatus.tsx b/interface/src/app/status/HardwareStatus.tsx index 16e3204c1..7637861cd 100644 --- a/interface/src/app/status/HardwareStatus.tsx +++ b/interface/src/app/status/HardwareStatus.tsx @@ -36,7 +36,7 @@ const HardwareStatus = () => { data: data, send: loadData, error - } = useAutoRequest(SystemApi.readHardwareStatus, { pollingTime: 2000 }); + } = useAutoRequest(SystemApi.readSystemStatus, { pollingTime: 2000 }); const content = () => { if (!data) { diff --git a/interface/src/app/status/RestartMonitor.tsx b/interface/src/app/status/RestartMonitor.tsx index 9e813eebe..855d597c9 100644 --- a/interface/src/app/status/RestartMonitor.tsx +++ b/interface/src/app/status/RestartMonitor.tsx @@ -8,7 +8,7 @@ import { Typography } from '@mui/material'; -import { readHardwareStatus } from 'api/system'; +import { readSystemStatus } from 'api/system'; import { dialogStyle } from 'CustomTheme'; import { useAutoRequest } from 'alova/client'; @@ -22,7 +22,7 @@ const RestartMonitor = () => { let count = 0; - const { data } = useAutoRequest(readHardwareStatus, { + const { data } = useAutoRequest(readSystemStatus, { pollingTime: 1000, force: true, initialData: { status: 'Getting ready...' }, @@ -38,7 +38,7 @@ const RestartMonitor = () => { document.location.href = '/'; } }) - .onError((error, _method) => { + .onError((error) => { setErrorMessage(error.message); }); diff --git a/interface/src/app/status/Status.tsx b/interface/src/app/status/Status.tsx index 6f274dd96..51241c04d 100644 --- a/interface/src/app/status/Status.tsx +++ b/interface/src/app/status/Status.tsx @@ -29,8 +29,8 @@ import { useTheme } from '@mui/material'; -import * as SystemApi from 'api/system'; import { API } from 'api/app'; +import { readSystemStatus } from 'api/system'; import { dialogStyle } from 'CustomTheme'; import { useAutoRequest, useRequest } from 'alova/client'; @@ -63,7 +63,7 @@ const SystemStatus = () => { data: data, send: loadData, error - } = useAutoRequest(SystemApi.readSystemStatus, { + } = useAutoRequest(readSystemStatus, { initialData: [], pollingTime: 5000, async middleware(_, next) { @@ -101,7 +101,7 @@ const SystemStatus = () => { const busStatus = () => { if (data) { - switch (data.status) { + switch (data.bus_status) { case busConnectionStatus.BUS_STATUS_CONNECTED: return ( 'EMS ' + @@ -120,7 +120,7 @@ const SystemStatus = () => { }; const busStatusHighlight = () => { - switch (data.status) { + switch (data.bus_status) { case busConnectionStatus.BUS_STATUS_TX_ERRORS: return theme.palette.warning.main; case busConnectionStatus.BUS_STATUS_CONNECTED: diff --git a/interface/src/types/system.ts b/interface/src/types/system.ts index 768813dda..ca9d34555 100644 --- a/interface/src/types/system.ts +++ b/interface/src/types/system.ts @@ -2,8 +2,19 @@ import type { busConnectionStatus } from 'app/main/types'; import type { NetworkConnectionStatus } from './network'; -export interface HardwareStatus { +export interface SystemStatus { emsesp_version: string; + bus_status: busConnectionStatus; + uptime: number; + bus_uptime: number; + num_devices: number; + num_sensors: number; + num_analogs: number; + ntp_status: number; + mqtt_status: boolean; + ap_status: boolean; + network_status: NetworkConnectionStatus; + wifi_rssi: number; build_flags: string; esp_platform: string; max_alloc_heap: number; @@ -32,22 +43,6 @@ export interface HardwareStatus { status: string; } -export interface SystemStatus { - emsesp_version: string; - status: busConnectionStatus; - uptime: number; - bus_uptime: number; - num_devices: number; - num_sensors: number; - num_analogs: number; - free_heap: number; - ntp_status: number; - mqtt_status: boolean; - ap_status: boolean; - network_status: NetworkConnectionStatus; - wifi_rssi: number; -} - export enum LogLevel { ERROR = 3, WARNING = 4, diff --git a/mock-api/rest_server.ts b/mock-api/rest_server.ts index 13ebe958a..5b3b2476d 100644 --- a/mock-api/rest_server.ts +++ b/mock-api/rest_server.ts @@ -307,11 +307,10 @@ const mqtt_status = { }; // STATUS -const SYSTEM_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'systemStatus'; const ACTIVITY_ENDPOINT = REST_ENDPOINT_ROOT + 'activity'; // SETTINGS -const HARDWARE_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'hardwareStatus'; +const SYSTEM_STATUS_ENDPOINT = REST_ENDPOINT_ROOT + 'systemStatus'; const SECURITY_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'securitySettings'; // SYSTEM SIGNIN @@ -322,8 +321,23 @@ const GENERATE_TOKEN_ENDPOINT = REST_ENDPOINT_ROOT + 'generateToken'; const VERSION = '3.7.0-dev.0'; // const VERSION = '3.6.4'; -let hardware_status = { +let system_status = { emsesp_version: VERSION, + bus_status: 0, + // status: 2, + uptime: 77186, + bus_uptime: 77121, + num_devices: 2, + num_sensors: 1, + num_analogs: 1, + free_heap: 143, + ntp_status: 2, + mqtt_status: true, + ap_status: false, + network_status: 3, // wifi connected + // network_status: 10, // ethernet connected + // network_status: 6, // wifi disconnected + wifi_rssi: -41, esp_platform: 'ESP32S3', build_flags: 'DEMO', cpu_type: 'ESP32-S3', @@ -331,7 +345,6 @@ let hardware_status = { cpu_cores: 2, cpu_freq_mhz: 240, max_alloc_heap: 191, - free_heap: 211, arduino_version: 'ESP32 Arduino v2.0.17', sdk_version: 'v4.4.7-dirty', partition: 'app0', @@ -347,30 +360,11 @@ let hardware_status = { psram_size: 8189, free_psram: 8166, has_loader: true, - // model: '' - model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)', + model: '', + // model: 'BBQKees Electronics EMS Gateway E32 V2 (E32 V2.0 P3/2024011)', status: 'downloading' }; -const system_status = { - emsesp_version: VERSION, - status: 0, - // status: 2, - uptime: 77186, - bus_uptime: 77121, - num_devices: 2, - num_sensors: 1, - num_analogs: 1, - free_heap: 143, - ntp_status: 2, - mqtt_status: true, - ap_status: false, - network_status: 3, // wifi connected - // network_status: 10, // ethernet connected - // network_status: 6, // wifi disconnected - wifi_rssi: -41 -}; - let security_settings = { jwt_secret: 'naughty!', users: [ @@ -402,7 +396,6 @@ const generate_token = { token: '1234' }; const EMSESP_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'settings'; const EMSESP_CORE_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'coreData'; const EMSESP_SENSOR_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'sensorData'; -const EMSESP_DEVICES_ENDPOINT = REST_ENDPOINT_ROOT + 'devices'; const EMSESP_DEVICEDATA_ENDPOINT1 = REST_ENDPOINT_ROOT + 'deviceData'; const EMSESP_DEVICEDATA_ENDPOINT2 = REST_ENDPOINT_ROOT + 'deviceData/:id?'; @@ -423,13 +416,9 @@ const EMSESP_RESET_CUSTOMIZATIONS_ENDPOINT = const EMSESP_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'schedule'; const EMSESP_CUSTOMENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'customEntities'; const EMSESP_MODULES_ENDPOINT = REST_ENDPOINT_ROOT + 'modules'; +const EMSESP_EXPORT_DATA_ENDPOINT = REST_ENDPOINT_ROOT + 'exportData'; // these are used in the API calls only -const EMSESP_GET_SETTINGS_ENDPOINT = REST_ENDPOINT_ROOT + 'getSettings'; -const EMSESP_GET_CUSTOMIZATIONS_ENDPOINT = REST_ENDPOINT_ROOT + 'getCustomizations'; -const EMSESP_GET_ENTITIES_ENDPOINT = REST_ENDPOINT_ROOT + 'getEntities'; -const EMSESP_GET_SCHEDULE_ENDPOINT = REST_ENDPOINT_ROOT + 'getSchedule'; - const EMSESP_SYSTEM_INFO_ENDPOINT = API_ENDPOINT_ROOT + 'system/info'; const emsesp_info = { @@ -634,74 +623,6 @@ let settings = { modbus_timeout: 10000 }; -const emsesp_devices = { - devices: [ - { - i: 2, - s: 'RC20', - t: 5, - tn: 'Thermostat', - url: 'thermostat' - }, - { - i: 3, - s: 'Buderus GB125', - t: 5, - tn: 'Boiler', - url: 'boiler' - }, - { - i: 4, - s: 'Moduline 1000', - t: 5, - tn: 'Thermostat', - url: 'thermostat' - }, - { - i: 5, - s: 'MM10', - t: 7, - tn: 'Mixer Module', - url: 'mixer' - }, - { - i: 6, - s: 'SM10', - t: 8, - tn: 'Solar Module', - url: 'solar' - }, - { - i: 7, - s: 'Trendline HRC30/Generic Heatronic 3', - t: 4, - tn: 'Boiler', - url: 'boiler' - }, - { - i: 8, - s: 'Bosch Compress 7000i AW Heat Pump', - t: 5, - tn: 'Boiler/HP', - url: 'boiler' - }, - { - i: 9, - s: 'RC100H', - t: 6, - tn: 'Thermostat', - url: 'thermostat' - }, - { - i: 10, - s: 'RC310', - t: 6, - tn: 'Thermostat', - url: 'thermostat' - } - ] -}; - const emsesp_coredata = { connected: true, // connected: false, @@ -716,7 +637,8 @@ const emsesp_coredata = { d: 8, p: 123, v: '06.01', - e: 69 + e: 69, + url: 'boiler' }, { id: 3, @@ -727,7 +649,8 @@ const emsesp_coredata = { d: 8, p: 123, v: '06.01', - e: 73 + e: 73, + url: 'boiler' }, { id: 1, @@ -738,7 +661,8 @@ const emsesp_coredata = { d: 24, p: 86, v: '04.01', - e: 57 + e: 57, + url: 'thermostat' }, { id: 2, @@ -749,7 +673,8 @@ const emsesp_coredata = { d: 23, p: 77, v: '03.03', - e: 6 + e: 6, + url: 'thermostat' }, { id: 4, @@ -760,7 +685,8 @@ const emsesp_coredata = { d: 16, p: 165, v: '04.01', - e: 3 + e: 3, + url: 'thermostat' }, { id: 5, @@ -782,7 +708,8 @@ const emsesp_coredata = { d: 48, p: 73, v: '01.02', - e: 22 + e: 22, + url: 'solar' }, { id: 8, @@ -793,7 +720,8 @@ const emsesp_coredata = { d: 8, p: 172, v: '01.20', - e: 152 + e: 152, + url: 'boiler' }, { id: 9, @@ -804,7 +732,8 @@ const emsesp_coredata = { d: 56, p: 200, v: '40.07', - e: 4 + e: 4, + url: 'thermostat' }, { id: 10, @@ -815,7 +744,8 @@ const emsesp_coredata = { d: 16, p: 158, v: '73.03', - e: 63 + e: 63, + url: 'thermostat' } ] }; @@ -3871,10 +3801,26 @@ let emsesp_modules = { }; // CUSTOMIZATION -const emsesp_deviceentities_1 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } +const dummy_deviceentities = [ + { + v: 'unknown', + n: 'no entities for this device', + id: 'unknown', + m: 0, + w: false + } ]; +// no data for these +const emsesp_deviceentities_1 = dummy_deviceentities; +const emsesp_deviceentities_3 = dummy_deviceentities; +const emsesp_deviceentities_5 = dummy_deviceentities; +const emsesp_deviceentities_6 = dummy_deviceentities; +const emsesp_deviceentities_8 = dummy_deviceentities; +const emsesp_deviceentities_9 = dummy_deviceentities; +const emsesp_deviceentities_10 = dummy_deviceentities; +const emsesp_deviceentities_none = dummy_deviceentities; + const emsesp_deviceentities_2 = [ { v: '(0)', @@ -3916,10 +3862,6 @@ const emsesp_deviceentities_2 = [ } ]; -const emsesp_deviceentities_3 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - const emsesp_deviceentities_4 = [ { v: 16, @@ -3943,13 +3885,6 @@ const emsesp_deviceentities_4 = [ w: true } ]; -const emsesp_deviceentities_5 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - -const emsesp_deviceentities_6 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; const emsesp_deviceentities_7 = [ { u: 0, n: '!reset', id: 'reset', m: 8, w: false }, @@ -4076,22 +4011,6 @@ const emsesp_deviceentities_7 = [ { v: 102151, n: 'dhw active time', id: 'dhw/workm', m: 0, w: false } ]; -const emsesp_deviceentities_8 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - -const emsesp_deviceentities_9 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - -const emsesp_deviceentities_10 = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - -const emsesp_deviceentities_none = [ - { v: 'dummy value', n: 'dummy name', id: 'dummy', m: 0, w: false } -]; - // END DATA // LOG @@ -4160,22 +4079,21 @@ router // SYSTEM and SETTINGS router - .get(SYSTEM_STATUS_ENDPOINT, () => system_status) .get(ACTIVITY_ENDPOINT, () => activity) - .get(HARDWARE_STATUS_ENDPOINT, () => { + .get(SYSTEM_STATUS_ENDPOINT, () => { if (countHardwarePoll === 0) { console.log('Resetting hardware count...'); } if (countHardwarePoll >= 2) { countHardwarePoll = 0; - hardware_status.status = 'ready'; + system_status.status = 'ready'; } console.log('Hardware count ' + countHardwarePoll + ' of 2'); countHardwarePoll++; - return hardware_status; + return system_status; }) .get(SECURITY_SETTINGS_ENDPOINT, () => security_settings) .post(SECURITY_SETTINGS_ENDPOINT, async (request: any) => { @@ -4289,11 +4207,6 @@ router emsesp_sensordata.ts[2].t = Math.floor(Math.random() * 100); return emsesp_sensordata; }) - .get(EMSESP_DEVICES_ENDPOINT, () => { - // sort by type - const sorted_devices = emsesp_devices.devices.sort((a, b) => a.t - b.t); - return { devices: sorted_devices }; - }) .get(EMSESP_DEVICEDATA_ENDPOINT1, (request) => request.query.id ? deviceData(Number(request.query.id)) : status(404) ) @@ -4501,11 +4414,11 @@ router }) // Settings - board profile - .post(EMSESP_BOARDPROFILE_ENDPOINT, async (request: any) => { - const content = await request.json(); - const board_profile = content.code; + .get(EMSESP_BOARDPROFILE_ENDPOINT, (request) => { + const board_profile = request.query.boardProfile; const data = { + board_profile: settings.board_profile, led_gpio: settings.led_gpio, dallas_gpio: settings.dallas_gpio, rx_gpio: settings.rx_gpio, @@ -4629,15 +4542,32 @@ router data.eth_clock_mode = 0; } - console.log('board profile saved', data); + data.board_profile = + typeof board_profile === 'string' ? board_profile : settings.board_profile; + + console.log('board profile for ' + board_profile + ' fetched: ', data); return data; }) // Download Settings - .get(EMSESP_GET_SETTINGS_ENDPOINT, () => emsesp_info) - .get(EMSESP_GET_CUSTOMIZATIONS_ENDPOINT, () => emsesp_deviceentities_1) - .get(EMSESP_GET_ENTITIES_ENDPOINT, () => emsesp_customentities) - .get(EMSESP_GET_SCHEDULE_ENDPOINT, () => emsesp_schedule) + .get(EMSESP_EXPORT_DATA_ENDPOINT, (request) => { + const type = request.query.type; + console.log('exporting ' + type + ' data'); + switch (type) { + case 'settings': + return emsesp_info; + case 'customizations': + return emsesp_deviceentities_2; // fixed for one device + case 'entities': + return emsesp_customentities; + case 'schedule': + return emsesp_schedule; + case 'modules': + return emsesp_modules; + default: + return status(404); + } + }) // upload URL .post('/rest/uploadURL', () => { @@ -4673,7 +4603,7 @@ router } if (cmd === 'restart') { console.log('restarting...'); - hardware_status.status = 'restarting'; + system_status.status = 'restarting'; countHardwarePoll = 0; return status(200); } diff --git a/src/system.cpp b/src/system.cpp index 1c646fff0..40a0fb50e 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -1128,8 +1128,6 @@ bool System::check_restore() { bool reboot_required = false; #ifndef EMSESP_STANDALONE - // see if we have a temp file, if so try and read it - // TODO find a nicer way to see if a file exists without reporting an error, like using lfs_stat. exists() uses open so same problem. File new_file = LittleFS.open(TEMP_FILENAME_PATH); if (new_file) { JsonDocument jsonDocument; diff --git a/src/web/WebCustomEntityService.cpp b/src/web/WebCustomEntityService.cpp index 62bd12e29..aa86fde16 100644 --- a/src/web/WebCustomEntityService.cpp +++ b/src/web/WebCustomEntityService.cpp @@ -29,9 +29,6 @@ WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, securityManager, AuthenticationPredicates::IS_AUTHENTICATED) , _fsPersistence(WebCustomEntity::read, WebCustomEntity::update, this, fs, EMSESP_CUSTOMENTITY_FILE) { - server->on(EMSESP_GET_ENTITIES_PATH, - HTTP_GET, - securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN)); } // load the settings when the service starts @@ -711,17 +708,4 @@ void WebCustomEntityService::test() { } #endif -// return entities as a json object -void WebCustomEntityService::getEntities(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - - root["type"] = "entities"; - - System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); - - response->setLength(); - request->send(response); -} - } // namespace emsesp diff --git a/src/web/WebCustomEntityService.h b/src/web/WebCustomEntityService.h index 1d77cc097..16d6a96d8 100644 --- a/src/web/WebCustomEntityService.h +++ b/src/web/WebCustomEntityService.h @@ -22,7 +22,6 @@ #define EMSESP_CUSTOMENTITY_FILE "/config/emsespEntity.json" #define EMSESP_CUSTOMENTITY_SERVICE_PATH "/rest/customEntities" // GET and POST -#define EMSESP_GET_ENTITIES_PATH "/rest/getEntities" namespace emsesp { diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index 861c6bb1b..c461b367c 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -28,13 +28,6 @@ WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * f server->on(EMSESP_DEVICE_ENTITIES_PATH, HTTP_GET, securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); - server->on(EMSESP_DEVICES_SERVICE_PATH, - HTTP_GET, - securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); - server->on(EMSESP_GET_CUSTOMIZATIONS_PATH, - HTTP_GET, - securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getCustomizations(request); }, AuthenticationPredicates::IS_ADMIN)); - // POST server->on(EMSESP_RESET_CUSTOMIZATION_SERVICE_PATH, @@ -166,29 +159,6 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques #endif } -// send back a list of devices used in the customization web page -void WebCustomizationService::devices(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(false); - 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["devices"].to(); - for (const auto & emsdevice : EMSESP::emsdevices) { - if (emsdevice->has_entities()) { - JsonObject obj = devices.add(); - obj["i"] = emsdevice->unique_id(); // its unique id - obj["s"] = emsdevice->name(); // custom name - obj["t"] = emsdevice->device_type(); // internal device type ID - obj["tn"] = std::string(emsdevice->device_type_2_device_name_translated()); // translated device type name - obj["url"] = emsdevice->device_type_name(); // non-translated, lower-case, used for API URL - } - } - - response->setLength(); - request->send(response); -} - // send back list of device entities void WebCustomizationService::device_entities(AsyncWebServerRequest * request) { uint8_t id; @@ -425,17 +395,4 @@ void WebCustomizationService::test() { } #endif -// return all customizations in a json object -void WebCustomizationService::getCustomizations(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - - root["type"] = "customizations"; - - System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root); - - response->setLength(); - request->send(response); -} - } // namespace emsesp diff --git a/src/web/WebCustomizationService.h b/src/web/WebCustomizationService.h index 2955e792e..7762b032d 100644 --- a/src/web/WebCustomizationService.h +++ b/src/web/WebCustomizationService.h @@ -22,9 +22,7 @@ #define EMSESP_CUSTOMIZATION_FILE "/config/emsespCustomization.json" // GET -#define EMSESP_DEVICES_SERVICE_PATH "/rest/devices" #define EMSESP_DEVICE_ENTITIES_PATH "/rest/deviceEntities" -#define EMSESP_GET_CUSTOMIZATIONS_PATH "/rest/getCustomizations" // POST #define EMSESP_CUSTOMIZATION_ENTITIES_PATH "/rest/customizationEntities" @@ -98,9 +96,7 @@ class WebCustomizationService : public StatefulService { FSPersistence _fsPersistence; // GET - void devices(AsyncWebServerRequest * request); void device_entities(AsyncWebServerRequest * request); - void getCustomizations(AsyncWebServerRequest * request); // POST void customization_entities(AsyncWebServerRequest * request, JsonVariant json); diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 841df8d08..f1470df8f 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -66,6 +66,7 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { obj["p"] = emsdevice->product_id(); // productid obj["v"] = emsdevice->version(); // version obj["e"] = emsdevice->count_entities(); // number of entities + obj["url"] = emsdevice->device_type_name(); // non-translated, lower-case, used for API URL in customization page } } diff --git a/src/web/WebSchedulerService.cpp b/src/web/WebSchedulerService.cpp index 6dabfed49..fef71c7f5 100644 --- a/src/web/WebSchedulerService.cpp +++ b/src/web/WebSchedulerService.cpp @@ -25,9 +25,6 @@ namespace emsesp { WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager) : _httpEndpoint(WebScheduler::read, WebScheduler::update, this, server, EMSESP_SCHEDULER_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED) , _fsPersistence(WebScheduler::read, WebScheduler::update, this, fs, EMSESP_SCHEDULER_FILE) { - server->on(EMSESP_GET_SCHEDULE_PATH, - HTTP_GET, - securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSchedule(request); }, AuthenticationPredicates::IS_ADMIN)); } // load the settings when the service starts @@ -613,17 +610,4 @@ void WebSchedulerService::test() { } #endif -// return schedule entries in a json object -void WebSchedulerService::getSchedule(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - - root["type"] = "schedule"; - - System::extractSettings(EMSESP_SCHEDULER_FILE, "Schedule", root); - - response->setLength(); - request->send(response); -} - } // namespace emsesp diff --git a/src/web/WebSchedulerService.h b/src/web/WebSchedulerService.h index a0e806f77..6f208ddf5 100644 --- a/src/web/WebSchedulerService.h +++ b/src/web/WebSchedulerService.h @@ -21,7 +21,6 @@ #define EMSESP_SCHEDULER_FILE "/config/emsespScheduler.json" #define EMSESP_SCHEDULER_SERVICE_PATH "/rest/schedule" // GET and POST -#define EMSESP_GET_SCHEDULE_PATH "/rest/getSchedule" // bit flags for the schedule items. Matches those in interface/src/app/main/SchedulerDialog.tsx // 0-127 (0->0x7F) is day schedule @@ -91,8 +90,6 @@ class WebSchedulerService : public StatefulService { HttpEndpoint _httpEndpoint; FSPersistence _fsPersistence; - void getSchedule(AsyncWebServerRequest * request); - std::list * scheduleItems_; // pointer to the list of schedule events bool ha_registered_ = false; std::deque cmd_changed_; diff --git a/src/web/WebSettingsService.cpp b/src/web/WebSettingsService.cpp index 16983ab47..23c964cf3 100644 --- a/src/web/WebSettingsService.cpp +++ b/src/web/WebSettingsService.cpp @@ -28,9 +28,6 @@ WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, Securit server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest([this](AsyncWebServerRequest * request) { board_profile(request); }, AuthenticationPredicates::IS_AUTHENTICATED)); - server->on(EMSESP_GET_SETTINGS_PATH, - HTTP_GET, - securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN)); addUpdateHandler([this] { onUpdate(); }, false); } @@ -463,25 +460,4 @@ void WebSettingsService::board_profile(AsyncWebServerRequest * request) { request->send(response); } -// returns json with all system settings -void WebSettingsService::getSettings(AsyncWebServerRequest * request) { - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - - root["type"] = "settings"; - - JsonObject node = root["System"].to(); - node["version"] = EMSESP_APP_VERSION; - - System::extractSettings(NETWORK_SETTINGS_FILE, "Network", root); - System::extractSettings(AP_SETTINGS_FILE, "AP", root); - System::extractSettings(MQTT_SETTINGS_FILE, "MQTT", root); - System::extractSettings(NTP_SETTINGS_FILE, "NTP", root); - System::extractSettings(SECURITY_SETTINGS_FILE, "Security", root); - System::extractSettings(EMSESP_SETTINGS_FILE, "Settings", root); - - response->setLength(); - request->send(response); -} - } // namespace emsesp diff --git a/src/web/WebSettingsService.h b/src/web/WebSettingsService.h index 6b7b2ec0c..ed20485b3 100644 --- a/src/web/WebSettingsService.h +++ b/src/web/WebSettingsService.h @@ -25,7 +25,6 @@ #define EMSESP_SETTINGS_SERVICE_PATH "/rest/settings" #define EMSESP_BOARD_PROFILE_SERVICE_PATH "/rest/boardProfile" -#define EMSESP_GET_SETTINGS_PATH "/rest/getSettings" namespace emsesp { @@ -136,7 +135,6 @@ class WebSettingsService : public StatefulService { FSPersistence _fsPersistence; void board_profile(AsyncWebServerRequest * request); - void getSettings(AsyncWebServerRequest * request); void onUpdate(); }; diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index c9939a7da..00fd35aa5 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -26,13 +26,16 @@ namespace emsesp { WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) { // GET - server->on(EMSESP_HARDWARE_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { hardwareStatus(request); }); server->on(EMSESP_SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { systemStatus(request); }); + server->on(EMSESP_EXPORT_DATA_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { exportData(request); }); + // POST server->on(EMSESP_CHECK_UPGRADE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { checkUpgrade(request, json); }); } // /rest/systemStatus +// This contains both system & hardware Status to avoid having multiple costly endpoints +// This is also used for polling during the RestartMonitor to see if EMS-ESP is alive void WebStatusService::systemStatus(AsyncWebServerRequest * request) { EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap @@ -40,7 +43,12 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { JsonObject root = response->getRoot(); root["emsesp_version"] = EMSESP_APP_VERSION; - root["status"] = EMSESP::bus_status(); // 0, 1 or 2 + + // + // System Status + // + root["emsesp_version"] = EMSESP_APP_VERSION; + root["bus_status"] = EMSESP::bus_status(); // 0, 1 or 2 root["bus_uptime"] = EMSbus::bus_uptime(); root["num_devices"] = EMSESP::count_devices(); root["num_sensors"] = EMSESP::temperaturesensor_.no_sensors(); @@ -74,20 +82,6 @@ void WebStatusService::systemStatus(AsyncWebServerRequest * request) { #endif } - response->setLength(); - request->send(response); -} - -// /rest/hardwareStatus -// This is also used for polling during the RestartMonitor to see if EMS-ESP is alive -void WebStatusService::hardwareStatus(AsyncWebServerRequest * request) { - EMSESP::system_.refreshHeapMem(); // refresh free heap and max alloc heap - - auto * response = new AsyncJsonResponse(false); - JsonObject root = response->getRoot(); - - root["emsesp_version"] = EMSESP_APP_VERSION; - #ifdef EMSESP_DEBUG #ifdef EMSESP_TEST root["build_flags"] = "DEBUG,TEST"; @@ -98,15 +92,16 @@ void WebStatusService::hardwareStatus(AsyncWebServerRequest * request) { root["build_flags"] = "TEST"; #endif + // + // Hardware Status + // root["esp_platform"] = EMSESP_PLATFORM; - #ifndef EMSESP_STANDALONE root["cpu_type"] = ESP.getChipModel(); root["cpu_rev"] = ESP.getChipRevision(); root["cpu_cores"] = ESP.getChipCores(); root["cpu_freq_mhz"] = ESP.getCpuFreqMHz(); root["max_alloc_heap"] = EMSESP::system_.getMaxAllocMem(); - root["free_heap"] = EMSESP::system_.getHeapMem(); root["arduino_version"] = ARDUINO_VERSION; root["sdk_version"] = ESP.getSdkVersion(); root["partition"] = esp_ota_get_running_partition()->label; // active partition @@ -170,4 +165,36 @@ void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant request->send(response); } +// returns data for a specific feature/settings as a json object +void WebStatusService::exportData(AsyncWebServerRequest * request) { + auto * response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + + String type = request->getParam("type")->value(); + + if (type == "settings") { + JsonObject node = root["System"].to(); + node["version"] = EMSESP_APP_VERSION; + System::extractSettings(NETWORK_SETTINGS_FILE, "Network", root); + System::extractSettings(AP_SETTINGS_FILE, "AP", root); + System::extractSettings(MQTT_SETTINGS_FILE, "MQTT", root); + System::extractSettings(NTP_SETTINGS_FILE, "NTP", root); + System::extractSettings(SECURITY_SETTINGS_FILE, "Security", root); + System::extractSettings(EMSESP_SETTINGS_FILE, "Settings", root); + } else if (type == "schedule") { + System::extractSettings(EMSESP_SCHEDULER_FILE, "Schedule", root); + } else if (type == "customizations") { + System::extractSettings(EMSESP_CUSTOMIZATION_FILE, "Customizations", root); + } else if (type == "entities") { + System::extractSettings(EMSESP_CUSTOMENTITY_FILE, "Entities", root); + } else { + request->send(400); + return; + } + + root["type"] = type; + response->setLength(); + request->send(response); +} + } // namespace emsesp diff --git a/src/web/WebStatusService.h b/src/web/WebStatusService.h index 0eb3cbe2f..d4c4806b7 100644 --- a/src/web/WebStatusService.h +++ b/src/web/WebStatusService.h @@ -1,11 +1,11 @@ #ifndef WebStatusService_h #define WebStatusService_h -#define EMSESP_HARDWARE_STATUS_SERVICE_PATH "/rest/hardwareStatus" #define EMSESP_SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" #define EMSESP_CHECK_UPGRADE_PATH "/rest/checkUpgrade" +#define EMSESP_EXPORT_DATA_SERVICE_PATH "/rest/exportData" -#include +#include // for version checking namespace emsesp { @@ -15,8 +15,8 @@ class WebStatusService { private: void systemStatus(AsyncWebServerRequest * request); - void hardwareStatus(AsyncWebServerRequest * request); void checkUpgrade(AsyncWebServerRequest * request, JsonVariant json); + void exportData(AsyncWebServerRequest * request); }; } // namespace emsesp From 3904b20ff9daac297e603caf1ad2240d31b46096 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 11:13:45 +0200 Subject: [PATCH 06/17] update doc in prep for 3.7.0 release --- CHANGELOG_LATEST.md | 4 ++-- README.md | 46 +++++++++++++++++++++++------------------- media/main-screen.png | Bin 0 -> 132337 bytes 3 files changed, 27 insertions(+), 23 deletions(-) create mode 100644 media/main-screen.png diff --git a/CHANGELOG_LATEST.md b/CHANGELOG_LATEST.md index e9dc87b96..0cd015359 100644 --- a/CHANGELOG_LATEST.md +++ b/CHANGELOG_LATEST.md @@ -35,11 +35,11 @@ - RC310 cooling parameters [#1857](https://github.com/emsesp/EMS-ESP32/issues/1857) - command `api/device/entities` [#1897](https://github.com/emsesp/EMS-ESP32/issues/1897) - switchprogmode [#1903] -- Autodetect and download firmware upgrades via the WebUI +- autodetect and download firmware upgrades via the WebUI - command 'show log' that lists out the current weblog buffer, showing last messages. - default web log buffer to 25 lines for ESP32s with no PSRAM - Try and determine correct board profile if none is set -- Auto Scroll in WebLog UI - reduced delay so incoming logs are faster +- auto Scroll in WebLog UI - reduced delay so incoming logs are faster ## Fixed diff --git a/README.md b/README.md index b157e14a9..81711ded8 100644 --- a/README.md +++ b/README.md @@ -14,43 +14,47 @@ **EMS-ESP** is an open-source firmware for the Espressif ESP32 microcontroller that communicates with **EMS** (Energy Management System) based equipment from manufacturers like Bosch, Buderus, Nefit, Junkers, Worcester and Sieger. It requires a small gateway circuit to interface with the EMS bus which can be purchased from or custom built. -## **Features** - -- A multi-user, multi-language secure web interface to change settings and monitor incoming data -- A console, accessible via Serial and Telnet for more advanced monitoring -- Native support for Home Assistant, Domoticz and openHAB via [MQTT Discovery](https://www.home-assistant.io/docs/mqtt/discovery/) -- Can run standalone as an independent WiFi Access Point or join an existing WiFi network -- Easy first-time configuration via a web Captive Portal -- Support for more than [120+ EMS devices](https://emsesp.org/All-Devices/) (boilers, thermostats, solar modules, mixer modules, heat pumps, gateways, switches, heat sources) +## **Key Features** + +- A multi-user, multi-language web interface to change settings and monitor incoming data +- An advanced console, accessible via Serial/USB or Telnet for more operations and monitoring +- Native integration with Home Assistant, Domoticz, openHAB and Modbus +- Easy setup and install with automatic updates +- Supporting over 120 different EMS compatible devices from thermostats, boilers, heat pumps, mixing units, solar modules from brands as Bosch, Buderus, Nefit, Junkers, Worcester and Sieger +- Simulate remote thermostats +- Localized to 10 languages, and customizable to change names to your preference +- Extendable via adding external modules or adding your own custom entities directly within the WebUI +- A powerful scheduler to automate tasks and trigger events based data changes +- A Notification service to alert you of important events ## **Installing** -Go to [install.emsesp.org](https://install.emsesp.org) or look at the documentation link below on the different ways to install EMS-ESP. +For a quick install of the latest stable release go to [https://install.emsesp.org](https://install.emsesp.org). For other methods of installing and upgrading, and switching to the development version go to the section in the [documentation](https://emsesp.org). -## **Documentation** +## **Documentation and Wiki** -For the complete documentation on how to install, configure and get support visit the [documentation at emsesp.org](https://emsesp.org). +Visit [emsesp.org](https://emsesp.org) for details on how to install and configure EMS-ESP. -## **Support** +## **Getting Support** To chat with the community reach out on our [Discord Server](https://discord.gg/3J3GgnzpyT). -If you like **EMS-ESP**, please give it a star, or fork it and contribute or offer a small donation! +If you like **EMS-ESP**, please give it a ✨ on GitHub, or even better fork it and contribute. You can also offer a small donation. This is an open-source project maintained by volunteers, and your support is greatly appreciated. -## **Demo** +## **Live Demo** -For a live demo of the Web UI click [demo.emsesp.org](https://demo.emsesp.org) and log in with any username/password, and change the language to English. +For a live demo go to [demo.emsesp.org](https://demo.emsesp.org). Pick a language from the sign on page and log in with any username or password. Note not all features are operational as it's based on static data. -## **Contributors ✨** +## **Contributors** -EMS-ESP is a project owned and maintained by [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP). +EMS-ESP is a project created by [proddy](https://github.com/proddy) and owned and maintained by both [proddy](https://github.com/proddy) and [MichaelDvP](https://github.com/MichaelDvP) with support from [BBQKees Electronics](https://bbqkees-electronics.nl). ## **Libraries used** -- [esp8266-react](https://github.com/rjwats/esp8266-react) by @rjwats for the framework that provides the core of the Web UI -- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these open source libraries -- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON -- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client, with custom modifications from @MichaelDvP and @proddy +- [esp8266-react](https://github.com/rjwats/esp8266-react) by @rjwats for the core framework that provides the Web UI, which has been heavily modified +- [uuid-\*](https://github.com/nomis/mcu-uuid-console) from @nomis. The console, syslog, telnet and logging are based off these awesome open source libraries +- [ArduinoJson](https://github.com/bblanchon/ArduinoJson) for all the JSON processing +- [espMqttClient](https://github.com/bertmelis/espMqttClient) for the MQTT client - ESPAsyncWebServer and AsyncTCP for the Web server and TCP backends, with custom modifications for performance ## **License** diff --git a/media/main-screen.png b/media/main-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..71cefdd5ca2dec7c107dbff41b70964df4ec607f GIT binary patch literal 132337 zcmb5V1yo(jvMwCl-912XhhV{iy9IZ5cZcA<2*KTgySpqjfxyDu-CY;nH%S*`c=>cPLe8|?NRr4}_ewRLp$=r6c-boWf+x7H217@f-%4z_qt@mI-r z-I@FHH%TD_7i{rQEi$Vo_21<1=P7_O zVz{Kl{wj$}2Sd#;h}cSBL@(^q-&$DugRkjG1$|58&`9||>*{8HR}?#_Z)_A-p4GvT$NZ_R$)x3Otb|U8;ynL7|B;PrHpRNZ zuC?d+@$TaO!h|V2B3t87g7nw_^7LDm$tpX8yXrq#iV_3s6Y=?vC~OwGA9hDGw3#tF z;a4PM|LZm12rmZC#>yDqqEO^H{t<}Y?H)t1>$QFV*8kuJsT@-U7DKArml=MJf0iSE zPOGa|d=f3&&6AJ*p9RUnp*4+XbWHvN0}8W8lov}YcuZw`FPATQS_DgD;q zZ4|Tl@SuPF^`}j%;7kgmr-Bxfyci30fg zySMhQr_mDa`xpGj`>e{}?AVOw27YHbyU6_Z?JE)u@G|14@ z^hbZr7XU1XofZ%qt7adrR#L-zOt0GWn@T9Z>`F)Gq4t|7t!fGDZze_~TjPpt0YE^^ zPX z>ASRG4E#87Q25hn;Vuo9BYlF_1$PURDI_Q6uD|FL34U}xVRRxA~)6XjVpHqI$h zj2+ZAROr9er7Y69zQMnAa_Ik3lYfcC{0MW3v)Va- zuB>EcY)hE1PF&u|X6$~GD;5}z6c~xLabGt?v-m}dE*=D1c zO>10vE7Mdpv{nV%C#l>Rl3bO-OAfduBZD^;entGEcOy9evJ8Koys|H2nS%yRa68c7 z1u$!mDWt76U-A*-1lFrep(#zzlGer~UTUK+c`BRaU?0=S1@7v^}g3X<^k?<+OjQeggfMo+TcXryY){L4}QKH6cP!`a1Ol zAQ)E}46N8_BmiMsaMY=dwYRlb^9xInkTcEVXx)8mb-N>Lcb>f1R+{VDts^? z{2KVhRbmX<(eSGG?Or#nj&vA!QC3`cmId$Q?8=xV!R&{8@iWQ~5X8|j zp=q%k%SRfRKJ9@gCgnYnyrcyD9wLQAaJBX+t5-EuArdHA%9D(^d+Hvd&o4`jkad4= zM^^spuG`_K-N`=D>#ZJUCLz(F-(F@s?>i<5C4Exf>* zW6sINaXXCvBG1ec*U%7x;^Q$c_cV?&UG&ZweMR9CM-<3ihW1grgCQ*MBzXMK_JgW)8f{A-oI{?jNspPUM2|joQAo`N?TxF^?tW6z zk($y?WWq61L^b~Mu$x+F)_rPvZp#$3cT8=Q?V|w;cw$F2I2~t)$!O*?3iIHc=kNG> z2FEf8(iZ$nFU<6Z*LgKKmuBOE&Ja%DoMl)X$DVtgj$5S4xCbHztpS2})#>zsSG8Mo zz1Hm%-`pl%v!~E93mxSa{n5Ee-%(}pS$VMx6BI^8Zl8AZZGi%A87U`*Y){m ztG6|w_Mg!h2lgh7(`wbbeDRMT4pfyC61og1XWg3@=;?q=_tc@;g)$pIOkg=b;%|)f z822#PDhBD~XREJTor}c_VXn1Mt?4I#B%+=oQ(wDM9VW55quc_X`Mq-XqDTerox*et zR&Hkr3=A_h(oC0xBMJAPAC#WJSxo^8{Z9$tZ`?&wOd4$pvcEI0-8S8W%wt1xG>aP4 zvu%C;&D@&1l(A^Qf~v!Kh##Nd8ynF;jwAxB_`IiUp-74Q9foEm2CzccaE{(35k3~Q z2d5`lO4z8<8Q?POsap}S9O754VM@n;vgD>R%h?e)x6{Nm8{r;eWg7a%7x#r&h|X2$ z!PKKHf&I1TwU?YvkVn0u`uAQi=VHJr7Sxdz<;x+#@%|XXui?c7yQ?YMg5og1uoJ+Wi)&l=C>S?yR z3vCL|GyDZRXYvVt2({gWG<4M+=q2!Fjj`_s+4IFsOz1r?BLsC5C+lZ*p);P~@$j#W zekdQ6=OD|bg$Im3`}Pw&<(g4xK;&>$yt^v4COfL`cc*!7LC*25N6S-0$}h?Y|5C48 zFDvVr#3i!5_OgF}LT~nJ5PLV2tz#T8b6C*4Jl&qOVTmjj#wgZ3;LKM(?vOmMkg2&F zOK8cILjK3|@|MQu7iy+(%t;;GpL*Q0-0_Z4Hv(om7KYtD1GTfy#U(uw#duH|bwf|h zWUN|0ZD@`!LUkcEZ!ND-lx(k}8u$`@{dPq0O`nf6jcDl;)=-Pv`@?49C^tzn*Rz-+ z0m0(nn2OwUORCA4v3$(W<& z$Z%=(w8qYWfatq-Bi}7m#mAty+=e68xgquxVM+<;)Jo&ZsKmW@7|r)zzhX8bWHgZs z0P4Aw2xl!X!!-8~)Q%r6Dw@8!;94k?rbt3@X+WX zinSojYO#B3?Gw=sHRxee)S=j9ZTX%8;eV_hM4JtzFf`7)+!DdZaQMVXrt~&T<0LZe zK;$5l*X%XG{}|>eSh>!c=T$zLO8;4_a`}9c8ccdh@gD5KN9~~yaD6tXX8x%3G^a{a zaCs??81>4ebcR*QQfqHbL1as_K$q8tW@(Z-~Dtk_*qisT5 z4!|!MV|XpMGW;q;U9}KQ=_q0)8z0||ym)k`BS)FFv$*IT$cOIuLi+n;na#Nu`w2XX zmpa!@(9sVk8PNW3c4AkxEDm_(65V&B*L8l9V2la0NbfZ_YF_Oza_@4R3G8*38&mBe z=<>j!cC$iF;pS(xdeuu!@!vwV08ucZ|PPI#-C z<5})Mh=>#0n&`lBDw8Rg%}_51l@1)7YS7F$?H4<7HwaFY7DH+5Kw4Zp$4H+)+Y>=5 zJVonl67bBN_pcinm;fc&Q$dE0|MrIFPH%7M(u6d`YPVkVN$-=97?y=wZq3KD=O@yq zTLWNHfQNBea>6#g`LjQ=$3VfCrZc0Nkl(O_R`{Jbc(0v7-*Vb)2&8-G9*yIW!=e*K zs5oWa?rblg{R9zYn~PkqjAX7-==~P-R`V6Ke&)4_fX-BQ3&^Nw4?64XSZal+>HQKC zipYYJj5prjKKY>0YQf4c&I6gd1F4rLYkep_z{$y(j=E!d`2xl`$A759%&*g*3Sklq zB1Ak1R6aZOf{Gh=j?{3Mkb5&9);1EV2lKWj3nJd4?#jKi3eeSvVD~=};lEtnzr)08 zpVq`J;1!;LATT_Z(Dc{z?FsDu>JJF&>j%{(Z)Q$W5}x0uS*0>$8z12iRh|GQbDM_h z^91sEMW-vv4GLbgeJiXv0NIR2O4QW`>un z#O;mLOIA^zg0Gsz&u#ChVfVpwNDnd}`+80V@fXTaWws#QC4Y8}nvMU|>Eu+~e96)= zG7Tq`(NDM=xXfwjE4G*3iHAd@UrJe1rM6Dq?9L>M{9i(4Ggaol!Z=J*AwMuS0s=yd z<3`YzZzQM7t-%0Mi9FNROYN}$O0*~aV-+#It{=4J1Q zsijX3Nef{$^%VL`3RXWKg<8iy=A%P5Bz0!@UHItWxz51O%QRMq8bCt>!jBbv@798O zYJ`YAjKaRm9OWw{eP?ZNgfm&S%d%HF_)Tgu<@H!|yd}dL-5KZthqkV1%4ld8{>kmI zr%H-(tnxGr{M;Okvun6ksZfI5hB%-LSGM#%*w)TYdAhOn5+d{ zA0ac~J-cB@zB|tPm$vuknk3KOV78UZBsNo93$y;CM{eeIsd<5ZBCTBOB*Ypvz#sr; ziuEAZ{*m*1^ds4HJ@&=j!sz|_l7RH1-J3V^i+bAo!Az{?bgl^UH`!{>+EDdomuI(n z#S8T@qJYTHFfaTLCPI+dH$fXs+3AmppIz_0h+C=8(DX4m8Bzk>mSGt6YVd_RC*B+z zy9^<~;4hQcO>Ia+dmVzCVQjId2RlnaO4FNH%s07x z%7W_;y>VH?qLWw55$KD3R77{@hu#vjOce#zS3Jsx;~Ey>@b?Kr=Y@-*dpnV6&t1qL zpJm?Gov=FV8n{|(B2YzJHWNm5MiW^ynGB|MX?m-U%E+3>DLbF?!fmy8$9+N-H#GlY zN`5=bd;H)<9Tuxi)9V`vyt?`htZ#(RuGjIQ@>E#WC5$5@f7(Q_U92I6DD{R_l{oWf z+E8o#@H=+kcnTUrDo1jC*WltAxZU0G@xk_k#3!PSpDbJFJE%-5m~Rk}qZ_auP!NtL z(NF=)=W-K^9q~yC82TD3lVE0si1;GH|&VXoJl9nz# zV3@Vdxx%(GO~Z`{7N?ha3_HMI`(Fg@-gf$Wt4x;neT~PLdPC4H+182rNds^0^H-o_ ziMCz_Jh4cfP#b~9TNYYjbJ`T5_$Cf!s=#vy}Jm+wREC9vKCl;{s?b{Ki=HAQQU z6BTxbwz$wdE;lrCNyU|8TUVz3d9nJskHUcyD%SxgBt;Y89t&U57*W1=@Uv zzUU!vD!%)%hTo6Tf_G$U$T_+GU*zQ;OI#eX3YhPR-rB{rhm}rHkkrY^X}IfyR)KD- zx?W=CI()l~nvuO343>(@_8jB}jdAP!yk@`Hn%I4sN{cf&HVxY8Q0LObPnK-4Ku8!v zb8}b|6JB4|iIE|QzP}iG*_HBXv8hWkjx^7=bI@|Uk*q44H;iEjb!%+Kv0uRVD^1*1 zQo0pgzzZa;p)q8F$S$q+Ebc&-HLxxp3zaD?a33o?u_uj|`&a2BKgWORf!XlK$H^4$ z91FkN+S(ega?(%!cN{Tta*fL|D_-~TXrw}es|S>hR!iQg>E`}=`I$ZGe?g#cxXs*h z*>Hb9G~V4=Z~rH*)GalnfH8u&ks&lnu3f-nvDTin2>+?LUf;s&bKu%w0Dx0K=<_yE zpvB`9AL<_%br^%Ca#!oSa9!rMKN-L0*WS?4i~R{vGwc&z8CRC!9DeZ^$Oq*bLt*}w z0J7cP-QzX6RzjQX$Uhvp?9x@adJ7*%wgZ1^TmIVHVlMg8NcdY$Ua7xVR}PmIC$5}t z?(UnX`+wj*jjNHd&DYC6q3tSWBpZ{;HCl1J=%r*Y(Jn(g}1o z$^U1izC);7jh8uHMf2=#Juv0@~xSLn;Oi5 zNRixJMlmdr)~%Mr=FaH)wK$2Z+%t-A?sUCai+h5lSg?pQYV(#=Hbf3ZGNC|QpL)8& z9+2amERlqHd3MRsFR>!IerRLaZtzh54E{1^f$+gc3u}PfGM@)TGtf6_K7S!@<++$1 zLE!XKwK6zay6M(k#8|Tbs4OjaO%KUX@7uG*letP7nar?-QIurSfKolEj(;;q83PtR z))$}uTQ!kTd`Zw|OqBs3Lhv3Fs%r9@yJttd3=-%1_1(DV!T9=z&F4w+r> zbR_wC5>=}cH!;>soNyi#a}Ecu1w2z!`O z2H80Mwlo1O32zL8pJ#=Ff;D(69Lka`jES;uDwNk&F!dLGy#?*>`J}KXT&5en<2^phMFnoP@LC;d(#dG%Vcc zi(?S{?J>r-O$F08AJ^9gZ2lZEqZ;JQM*jDtkGMxXC7G1cCtpBu8rpWjN4qene3u>ER5{F0a%?1 ze{^%A{NzHV0##9|I2dgm(-E$Q78w-7{9-^z`TI;AQXQ{4e{23R^#`#}ho>(=pmNc< zt)3=AzrIdfj#2O%*W@+i*T4LNHv)Pj5em+0^-jIe0iL|Ep2d_pKk=i=C$IHpO{(8( z`m9)ZY6BVR2@})@8J09_4q*KeIYs0>PM*w-iGqvu#kv&5#tX-a`rt`yuzRz3uHF+h!NqLH%a2Kk^IG66oPnp@> zbLS}0aR+H8f@~1SvVyN)|6>4%q~k*Lqj6<)kL)9x#q?wbd_5CDx$2M~gYC_0%Ab=z zR_V7!bF*&41(w3#T-eG}@$0BzG)txxRO`c}1=|^g{GJ(}i@3BBXA_0yh%~)gwYt@A zr6et6#6#?|3XPT}nKAQc3|}8SctUWm`>KP0(Qwih_nApH=_^Wmz7rT%$zUY@`Quz% zv+Uy8^7s4FI(6!w)a@W@ts^E%fS)G0XA*PbwQv7b>{Bmet-JI|iWX!>_`>D{yop38t zM2muvN~&ssBe{h^7o`yffw=btFjEoj)#;5*8z^!wt)1(yBfv2Rp~jb{-TNv zd3WZW+C(7gGpNz_rE?HgwqZdPxeM1Dv?HmUy{YTPRUaZcEno{j!(P`5^{|qP2IIzJ zbL~eQ$tod#hb`X`sc-UUSJ-ddFf@xI5u9a>1_%K5 zBm!e5LL0wMVhhDGN7JL_Pg750Rd2d(VBS0Dwk}r8&O`G_q=f4Pwp(AVMrt^UCCANn z&vT0VDXJVl3L=w)8}x?Ja!kL@e>y4Ja!8F>-)6Iyw7T+6wr`0nb0IZsWVeVRnL3#$ znun^?a^is`OWoSq*fiD?atsiKPR_H&T2u~1Gg2=g<^s_o)UOB3bO@35mMIX($yrk( zYvP11P3hqCUs8aX+9Ua>uCuFqu{l>_(CZH9)g3f!y3CPlCD#yZHNmm`$+Gtc+T>1* zRBWOMUpaWfXLmJ)YCc4T6?vk7Eq3!)REgVpt6(HeYM5K-R6jr6AvYJyEKFYleyvsqixru#Clma}aN+!QX3<_)E~{N(0D^e|n! zEZw|Fg>x>HyQolx_S2I?_u24|BGeb{f2@G5@lU>Amg|V|tKB^(+>D4+h&!KBeGtU- zienlt(!lVos3hlY!5)ksNJ-pl1{({iTA4)WOqL2fUyh3OWNC)r+k!LER{Ui8Mz|n~ z(GIO&uZ(_4IWdd-JDd+*tuT-qVDWn^vu@7GA2KS%P%L-B6pO;)oBHDwwT;q%08 z3!kY^fIUvzP?Lk^=4SN-i!y$b$46TgPuOW5@E*7*oaCQ_SI6B1gQo==5pI5k<2PQ{ zX`Zqr;x~FJduj`PUcX+lzS37dZMui8O2Y}sDA4`v9plGPU9cs*AjVE=_lhYT9!ju0 zd5BbsBJ(}3$hkWXokwS`Letjcw;HjRbzl?Ofu5g1M z6S0>iG@N9o+v#$@*oiOW{TA1!7bmisX0f&YTt)sIGKz`ql*j!R8i*Q(AizwHQBL=% zCTYRYbp|{~eUOGrt1s-{_#nRc09T)wVZILv^|K=mk%FLnnVDjEU%R-{+NNO8Z1mPo zH@S()U-)x?atIU6aX(@&TL5@8A>9hZe+6HIc?RQTPqI9^aefYQ8~NVrChd{cr{Ei= zYJl!9;t2FT2|X$j-2JLf&`t4a@{!R$SCr0aR1S!|Gbea{+1TWV(-+q{ zsh@SS{cyV?+kM+0gMjs(UNE+6Tl=KV`3ayoIZRv&SDnA+ppDX)MWwAi7DxHg<|iQ0 zeSk6V$eEzW!0yYWY805VQTN4n4051#{BqqAHD&Uy*1=|Y(fQd#A^i&qYLV27e{0J) zsh!Lqg=6+T^YkP6#?MO6o<(TRMz8-887iWdeaz&r^!2Ukk#!m>Yb?B(rUxgQYoj{C z%o;tk0hq2TuTv<-l^giNPWsJ-d}p4UP@F}6zYt}j%|ya=mXlF2)q8j#m~xV|6Ds3$ zGyhYq^o|Pu_qpd^*k99ZyVECCpc?bMyL{_&=g**^54e|niKD+UP~av&1db(Glm;i6 zdTq}4->_Y)$8#!xgT%giNMW5y2_3kX z-3wH6SZCkqGzZY5eC<*Q4Me(QlQD&RzIiuSff$v$2#s3!)dr6p@lyiYyTS}E-N~pz zWP@T09y@btNXt(1B|6Ehu?o|i_AAE&^r#@wGvi$s6nm=G@KQn4Uspk-KkuwBM;0_6 z{1vdnRW|Fb%#D7GS|q=GHNu-XYo}eV(kDIYW>o`e#ENX{3iceB_EiXppHp=fy@r|I zYnK=&?WHWIj7I0W?yr1Yz4{fW#XX8F?Jn~1*BT2`dyc5!Mb-?v7{lxjH~&a|i>Ht1 zJ71iod^wyjOziE)BC%*X4_e=rl9p6}daeHea`)W2P-7}RFwGysvj8M62R;!zO=J%0 z>LbQrXY{huNN&ZihAtDAwY>5c^j{+^hQ(Ew730)UvK}F$P~s|_X@8$GwSIC)5eC{& zxyJXwV9p6QIRHw&DG0QLg7at7W@LTJIb%x`7RX~Evv*~C8(0?xf&E>-N(Dr184b|A}|4Kt;kRe9u7%AitI<4eVxa>d;bkIMq1 z*C$!dXwMLR(-4igA^pHIfZA-#bWS8lZc%Qcsf`Wrbn`xzOyxUSy?s=o->8c8i$8*# z1>+~U9m&Su&$*J5q*{(Ph$ZY28W znzN^JvmdU4>d;T-jx|2tkMsT3)K2pGgI(qaM+l30K%fjF3Zpl@IGb)iBhOxu$$pu7HIxrIR5Z z!I`6uLxCc(npXKZEp`Y_cE$X=n2d*N=V()gT zy?Nh4haC}W>ILsck!x?ZvADRCnCV}?urr2Iup!1pq2Wr^oP(hpHWVVir?UM(2M?Pa zrkY$0i3g5nP<+Kg()C2-Xvf^=`$(qojWwra3-Cjn!tX{P`I9eduN%O_ztd49IAZ0P5jF z{osT+quU~JW0c(z4hro$u28jpzlvF(0|^qpclDSs1A=5CKJ72u1f2@6f`fJ#wryT` z%KF7!XSm`uDYi|O8c+c`fS6sW+(9(TIY#J$yFWad&r-fdA~n^qJz!i6$uiPp6DxA%H--v>6>=6!GJ ztig#u@0Bj_QcrozeGKdmHHJ(PiE8mryWMtFkaz6_%cM-@+rb%?o?|KOhYpI@;6I8v z!tZm741*|$s=yMr!6I)CH`nLY=nXGxZ zqlZ=W%w46Y2SaEpv_`R(Po|dG4x#FsvuUz!6nSGj^N`9@KSi(8sNwp>A|dQrP@EQR;g9EZ~{q zbh)ooWPsJ=`}`@Mb8ayaKIe|`RP`JTyrnFXL>GbXPJ&+l)+ql=ehXLB z0h{rOGh9-&IejQ6)biyvfHGDC8R8^soel!ea`fPr*M^KAx2c!a?BEt>dx<3R(R)kA z)G|EFXun%MKQwWHlf#X`Gq=Qht0OT zvdQOJM9w&@rC_VYwPTQgm6KS+2xIA2iR4GUC0394lDFIAFAn;L_8S|o!)@Swzd&+;Gv4><$aRVdzi7m>ghN`urR3x9 zV8#{J=-&x}I#)W&S{eEGm%Ns3?*(ojBBW8!3h%1eHkSp8B}15aiwi9S!D7 z?lXEuTlcuP4(C(O5&9^$P4bDI^R^jp!_}!&*)-{$^<_I+O<+(R(_8WW>F=$yPRSx< z+jzN2IO(_%zj#;r(9`{sc4wco1*}&qb(X2DS9q|#Q7SZ&wPR*Emnd-X*s34!p7IE^ z+<7EmeC;D4`tCA7)PjRYFi`V=MpWqJ0I}y@TBj z5i#7#jm#CFA6W}as6BU5N1;S{N-cxtFIY7{g-$YfFRD>MDNo(Rj#-*q_NZgd_whoY zKNGByR#kBnoMUk^Xt$JXxyr_19o^kG3nBzMEP5>R|2^+cIbJ;ey^)lPR(F{hfu&rz z!sdon{{2nJ%&2!V8drgZ$)O@=xx;%9`!Ah~9ZMdAGOFcPl!)5BcIm0Fha7Iap-9&9 z-@S68hpea06`nh0C=OylNX=e1GwWOkL2FI}y!t}e$u>87~W6Ora{V0)F z`+iW}Q}MH>W)q$EgS+zVKRM)m&WxU2o~~%K^0%Bk&o@`Tn%F9RK>m?==pyz?Ft2qt zM99koTppb1)oCmbn*~`F0bl-iJoM(Rkjs`{pJ8oQyW@yWCmJWPhnpZl^_^0s)JIe% z(jWFmJAId~$2< z%k5v5Tui^hf^JtPVf<*Zg0W~%CFnD!z#x4(d@C`3U5{ifmm2Gh_PlX7>c8U@yHBNg zdxBUS(iV4#hif?V)OhI5kl7aog4;-Mi!_Z2z>T=&9Bt(FyK~xvV>w>ki?XJq$&c?u z$X<>WyD!Az=^P>3pb=@@p=H1kV|)|XhSt5i;{^^)O-)M|mff|0*BMfbPH&mmdmZWj zM)ajUDwW?30`Lh4$OHU2CB~YhS`$UpS{n9KPgN)LqMAM^^~^)tpMZ0>e$3ooFRh)w zEZuS50Sm(Av2r_lKsB~y_pMB?#Cd_lJl&8p<=!YNW(%$fdU8UC!le&~^tHmT*_6eDk z5-(pyt#WxDmMUuhWN%u!wt6MP2Ob;j$fb=+5{sFl{@!)rz3odGM^hN&K>6GpSnjXX zZj5;H1wwuciB9zu<;fR$JLXncK`5p1UYU#$vlu2rts4?HKlpY4(nMDQ5~8H-;B1b_ z^rh$v4_#*+jpYU=Io++r4>nddYQT^ykK8H@tjfU$VlhzfLDm{aIh;IjnDD2qT79bF`w zFBe1U1S%Iw4C?7JAkD8UDes1Ga~MXN?izqMLc5gr5l!$E7~cHYis-S?KC{+dR-P@m z?cG;H2O-v$%y$b{q8;&$kUHH{;LkQYk`8#Hoy?c1gX^8v7d&lFh$0RVmwv%DMtbm@ ztM}+9jW@C@Yq9e6)bACl{+S`H+0s{|I*`i}#+r>w>92`Khmb6FFwaQQ;=w{ESSNG7 zRr&2`{F%oPU-@?Pt5Kqc*3x|5sgE8y2?2AFEKh)Ev$_aNhOga+hedSd)x@N=T3$gz zO>^mCh)NM$(tco#x0w|F@f^}s%MPis-rqGn*115QedUuf)97~@g)Ej)j>t= zp3f*=Wf!nLekLBY{X|0=*E?i_Td>x9viM|aS2`En@$;nFQKzodxKcvfYAgY78ONrx zauh>Z|9iq(ElcOF7NCp?4o-HYn+9$DZXvjlH@_p06C}29)M}kAJ1Z`kWA5013-Ok@ zu-r`;GutSAfxYyXCetKDaBKHbW%yLviGX$_TF39|@uQzrc-=zy}lIU|Cbo$K^YP68pSGrA58;N9|ay)Bh z6l;(R(|akr2y5FlvKW9w2CG?trlx_D;`MXIC;KXcz(yK}zTX#6_wJ5^jRw@lmEb)g z*$-&hDpCaed#qX+)_Q}a~&W@~aj!jb0q6UbLo0fXmhz<3G_ zA)L)kM)^b^U^rffeE^+5%(i^qm-%MU0lQ2N$kk+_I~1%MvbGzXC44eZg|jlni51CU zBWU+W7V&RS^s;vy3%N&{EIhO}NFJ!Ppgsvc8lrL7m7@K(2TyU_ zxjxMQJafT(VnV|#0C;@zn2`}=q2+=@@=$%*CIzlW!Prqa@Ea=H5$`gYLdrH!_>mbV zd3UQ?n|8KVcIi~5lf%)HSH<-?jy8~_&Cvz<+9H;&LJnUIc#Q6 zn!guFVKQK|OBhlT8fOJMl%9IE3vD;i*zZpw0B&NYJ}S^n#_df>Gx9v@u3we?b$ED6 zuV&V222RGetme##<_*f5+>BiN(XfU91Bvo+N*zDihOg?_n?DEHal{aE;F=7@^!5PU zltmtF$RcykZXhjywYmrVlOsfTN;#h-(^wgX+-qIx@64VCqvTQ*yU00e+jrt%(L z+-J%$J>zx8RKA{Bc0>#-yOtK3HvjFQkk?U+r8M~NfZyXK&v4R#PU(9m?~iHDyIG{C%T(6wdD!_nIP9O({GR33f`n(r?W_xt$5)TiT4UHAz z6VLLlvxEkrU;Q`(+Hop?!c;rv&H(@9=+EoRF!whV7}oyNczu$wy@nX*8WRCv50RRa zfOsi%G>0=R2nT-#Y!*uMRcDE$kS+KpChS_pz>xCxizDEYV~LhVM*#&oAt{oM&qDP) z#u%U(<4FUXxLh6Ys;QYU5Ul9r~K`>r=f#G~+FldofU{M*EL07@l^S#g(WTvfY4d58ni2 z$`ogQU>oI=h}49-I3p^HJj1IYv{L@ zBn#p1GuJS*wJ?~G#c6$Sv2~y8$5P%cydhx_TD$ZS_ur$-ak%I#wvneWoAIy>yxbXy zOF}bMQC@K6JCznJ{2HMjQ`^!J9q9!u*N-hNExp|zSnkYd9zvv@H>LOX+X#kj)Kjik z5S_kxf*<{KEtYmE?zFMb-2V%ZnFP+A(Fh)|%hQx#E*6?`?70c<-tvB^K7WbX+22@# zI6Wmb<~suxh>~?^b-jOi@WI0*)yZ3b^xtQ<;cat>s>);I1CCJY6AB7sqtG-A72} zN(<4?IRc2w-3+jw`2|s*2#VxEdN^L}`(ZzOQiH)w67m^*JZ)Q;6=LU$?J6$Qvz01} zD^){2XOtVOoMIZ+;yEuT>tzAIe-#}@bf>?2JT=JAvT)>A^-l^mr|MUq5@p zr*|)5S6z0v5(TAmo;V%M>tA#w>?sge^LU)192JabaqzfZc6fgoX%MYv+Zx|Jp^rdY z2~}$C$K3$ld1{J&!~>^MQp;% z=404N-}VT9hc_WjUqSpivL~1o@->|YSpUWU$%U1%7OmkyXLbKXjd(~MY?R`kdAy8W z8I?J}5+F$%Xw9AsaCD=K8EJnB^yEs177Nc3+n)*l#x#qS585<3kZ@%3Cu&z5=6D~` zvrw-g*|NL}+kI0^zBQc~rH;FIFj{6g-@-=7kU$xg|DIIhxcA}-b}Zwklo#sv(c(|$ z&u(@bo60arS#FQE$SHL&fxgWHHok<#ikad;exe`kz|84hExlv=hzi-QX}cH2A0BZu z0v@4kGdc0&zQnBL!`5dxJq2`I@k+0rjvKV%cYF_JIv-Z|mOUW!5HxMBbMSJayK}Jo zj+bIZVxazQh+M(B4X@^M2!^1?9PUB;2^5g+48a8YHAzlJhc^udsR<@~P0aOPG{t!e zIOo1{V+iClbeXuVFU=>mkM@$>XYg=4hg>K=F~Rs4eY&uB;xf>V}t+P2ZS3(3|fNeCMNR&}V|=)8c(6EXu6~RTw{X**t%n zR{$T|0cBFoy)p6N!ZSCi7F&3$d3;yHpDk+P_<(AtTL-Is^GY})&%Aynuvkml86xSt zLF0i=pIz?#)b4oN_C4drSBB%qIMKbq+ZtaAzz$kK#iN}N^9qM(>0-`$0!w#Lp+8dt zj{ypwKdR)zlYt5qzb{)yGmUM-Lr6y6e5W}#g`7+uSAq5jG{&cN?8FmX%%mE2yt81< zMxo;i6?jgMuR3;c{D=a8C5oQ{erph8r%kjN7_gmf%fBOI#YLi?JMrN>-Jjku&o0^$ z#t;jBzEdxBvK}CYrnV8Vg>C+X3eSh1iEnE0a}kEj^;*taKkLg&e#ufR!!jw1(TgJ7 zB#9Hhu*B*sY?*xbO;HY@WM_d=`1npx#9yjQap8#%Q-YN{PW&erCY4QVb{!6ivvZ=X zsL2|3`&oR7(uULQJo$_JwC!+wr8g(b962Cig5+2H0a@Sg)?W9EaHE zqj>0U-r#-aEO7jo?WCY`-oSD8L|24zn z<7Ak1@yy;Z+-*zh_0TQWm>Rbo{E^nV3trQc+FdBx%m(ciIU}kbx;@hhi)|3xE`{T1wE2A4!pNVGFQqQDSD5GES2u|nmgw~HR`oj9 zzx}$i2a3qB9J!_f8Amr&c>I9KWBQ}(v;mFiXJ|u3dK;C??jyL_IjCZHMTb}4p~?i& zc-NB?7nVe%+uke8x|&mIjpW;(m2OHC(&X z@AW=^FJ;!FqN=p%Np}QPU4_uBpzb%s?n#}`zi~0aIsb4+#m}rn2x!zZs#x3OVTylK z-(>h8r1=8(BhZFsc^LeUxXsB$huZ!2h4a@dK^awgrl1K;UBNaow!4NK`;-3KScrLo z4y0GzHq=6rolQEl zNEO(k1=P{!>(_ zcUv?_fCP7k1cJM}1xp~f5AN>n8eEcK2`<6i26qb#E`tnCaCaSeLw@JpbI)4$t@R#% zb`RZM)m2?z?fvcj&9C0`bZ=<;bJ!eeqdA&~h7r!kqHTm~R!CcY*Ce9Pz6b)+ljBEb zdluW*9r(=POSr4dK-H@XHNNN{yrQwukm%k-&Z+}H*7GYtoSrL=hn*AlRS4h6f=v_A zx}@3lR=ZJTFbs&w8>?zU+oY`0dbY%wp<8$(BKM_`J$*_UON>(g?_5rY^VT`hjkWsv zOrcV#37eO3IHzR71mtS7B!g6Dag@O2GWe6+ji$bb{0e=%_{=0RuCVpF>`Vbdbu)~p({lo9mjoj0M!(=~NG z6gy~8vwhO-iLAc9GZcE!w%+NITI=CrK|ddWi-buqNR@6+*&G%@rOm3oub^IH^m>!D zwR$b)ePnCM*eLmcKI9IuI`1`8lIWhYHC?CN%Z)O>8-)(V63RV zGc>-1=q-$`K=fm7~vzZEMXQA~+8Vq`L7;w0L{xvWye|9~)X% zXhkV3(c7fFfc{(C_Vr|iP?P&+nxM2n?^Sy3Ha$T?qkDf|K=0b~U_e;(t2Xtx?OkCX z7MbU2f@_Zy6QTY4;m9Ro4hHlcpGqfp*ROR`3HS8iQ7B37&JQFTxe}uS@aY+O*x0h) z+Ixf@I!`BNqxT+1_X)wa(SVyl>jrv%oS14JP&J=w1|MYGYPRF;TN~*lQh~gqwP34* z-z%w2Rw7DG+A{ACLpakBdQK0}kj8XAgMGHuZWC4&QoMfPY$m8kRZ{S zB8_zHVo0no>igSaI0N78w9??zLbza-O_*s9SVj6l!5|3qSu}<4uZwuzp(qlSkMqmc zK52Hf2A0Z5??`WifJ%xT6di%-XgDaT@2aSiDAY_r+h$p$SixwzT>EOvLs?^sC7scr zXT8SJwA)vjJ#XCZkg)rA0g8=oqnlLQRO}*JfApS~A*8qV$fZ6Fik#;0K+j;*>57-0 zG8P`VrefY_xCvhq*=%#G*c62jezfrQ=z!3qJIC{^H+I1*jYJh^}rniF? z%CTCkz0(@q^V%ekDmax>{(jY+s!*HR?miDuM2f2Y!rJQoc^|I+iD~)C?XRetL|*P^ z&m|oNuumBjiz_RusPi`FTX)Tebo&J{sy7N`Rnr1>@iXO9#HJM^cA zRK%QpN{+KJ`lhS_oohp`)z_4gl6EQv@7U(IZyZVyP0#Zb4VH$mv$j64?V5d~2f20Y zY9{hSscl-xXV&!0zgF!wITadM=&Yk&aqlzAx69Loo$9V59b`3<)sAVOU|&mf3|rgCNA3PR=}l5m}v6N7LE+<%EIfUEW-(7 zLp=qc|B39_%1EphDliwldBXEiGEB$p`x6o))>XqC>X{`F6DyA%*3?!dKC2mGTkT+W z71F@*(-1V&SHUF!vvXW`z)q}4!Y%KHH68o%{Y`5u3dQ1=Yd_9<&Yp*B$o29+kz7|k zAw@hZ9`x*EP}o0U3n>l4e_g?YKwlL`*|%nAcfWP>SGwLjZ>y?tnWOoTq&^-q{;<&& zx#N0JEEbRfMK_rumAJq3MA2(SZLHU!8umViS5mCy)ixO6V5g=U78HOD)=6MgEs-o_ z4E{R1YZ5y8`vF%B8}6ha6J@zh!@IoND%OPs&?Q)*cEyg9>fx90la#6pAB1m96|zl& zQSFBlRh_TvEXe*U!5#9wJT1n)K_7MRdi??!$ zH2#V#i1Y!=qn`q!;VAfzJ_^({b*gWvrUjkCaGok&phBhXD#;H0f%eLnm@<6Aes%Nv zaf%LYCH>V?1ihs*X{skQ^57h(^OlKd?jR0elBr7TiAB(cH2Alo%x#=5b2Ayjv^@)N z&O)(1TzTRw|BM_dyq!#L|H8Jre7%%`DB=qnHhnXd^u=la0h6;5!@yzcf3m2gOs}&4 za)`=(v;A?n7PcG%)YP?U<6b(9xs zOxdmkdT~P-7ECQapk7*xg9)ZQU<$3Ib~m2!Il4Ku7jLn=^53ms7$jad&h=lcKhl3I zpn^tWuT0y)3V5`?Un)Z7bM;uYkt#O~^O=&8N+SPHUcpNy!|R&uU-U6s;c1q6S~_|~ zhDk{<7UtzA+86(&2fGZZ74d>;pTHF6D>3DgFAoemuV2gKl_GH(iA_CGuEWJbXNu3L zt_&_wD~eA^L|tec*lpm!KV zV!idW9spta)pY8Jcoo2czrzLZ9&{%@yb(06%i3nZ*+`{BK_!OV7uu5l>Khxpj_8fFht6rTH6vN_F17b zl)yt_u~0AYVyN$mS`n!?@OP0W{qOmJ((|k*eqv`FT}?Zc^wg7#N;56eCbDk226wm7 z(WB&-*P5zm5Ei%Kh5_wZ9eb4)Nl)lY-dR=0;st))(V}ZOufHn*C7;N2aS z)r2qAb~8w|Vb4ozXC80sVr^Ad?02ISPa_q72g55kT}*`Ii)yQCy66nUcojLIvxfD7opJcR;t@h48{oh^9cz$aMgN_`SJP9s(ms~`(J#|^>cbxMd9sRMs{Nipp z36*?YP&w&$l1cg?zwfCh5x%zqpLS*Ok$uFI%Q4Y!C~qq$;WwsR6EoBgoQW0C?s#H*WD1nGf}koerf>AwI9^UAH|{5} zd{41j6A`bH5ypt<^bAcvODeiYz?aX7{PS=Vls%tf=dgn6N{DO(isGM{0>7j3nO$1s zLJQqbqfICH5JO!tQQaBb#dfOy<&)lxY*=*p#O!BC+Nn8-#NJ^e4hT7J`KxYIXuD}5 zSmnC&($+49J@jDE*0`jShFeB*b(*j%%+S{JZ=eEw(`kX^`s`XIN(fnY^7%=HM| znD3o(a>(Q?CXWYbjAFU^QO7S&*MR2Lskoy)t3b zgvJXzOK^bnJoS3C#alnofx+A5lD7nGHhtP+3(A zkP3}gx*`~GVI^>6U4hgfb1tTF*xOkz+jCF4F(o%Kyi@srszL)W@}B=3c8Jz>Uf7kg zAj$5ZNbi;iN$9$xq?-APFTsyTfRI!#jmjd6G+yJ`5HXbygXN{ECw7G~a2FU-V}2w& zAAXnn{8O60oaLj`<)SxH%ukcJN#lzvkUFbwL_mF6;z?$syQ_MdWewCKz%BS zXQDa0jt{cyScyk#xeb^hB$TL}Mq4OpvAL}>w0!)aZ#|q*kIBUn$6ZT{O z3riU2)W>NMN(g`6W+BRy;rcd$+VjnmF|WU9dX179J|KdCh@I=z`xpTke(d&vjT=+_ zE}A4CPiDYV(aAg^)-Ae67MEm&hnjKJ!09fSsGs$<(K1P|d(&Lw$iR9N$>}dH4bW%V zug*?Yv~2S}rjRUo`kiY5Icw>AlMv7KAJXVe9uu4&%=Mj(8+XtsY;_i_uWqxV2u%df zL+lPVqU4BSNeWmk=3)*yv*Pyc7Lyw3GeKK%(D{5Vi0&yDwzAk#0<^BP|4IJ3I8*Z= zTW{a}sbdUi0r`OzY2HD~agrk@|fzg~O|$v*+EB_*Rws9o0(Fryy#WZ_ykIi$@XwyP%$ zm@Mnhd+UKdZ7bAIixrtnT~R-?U9$DLVLWzx^o2zW$cXow^XN?cjYO5^v1(~{hGMm_ zd|wsQCUEWGRqs>NhbN4~C1*Tv3EU3Gihs#~W1rz}-K6F`XYKCb!7zWD=dc!qBN&0^FpW5NTj;S3|)gQo2I zZy;Lx3S-CC51U$6^ZYMT-WsK%Nahlde^2`fyJzqGh5m_(G|&<=Ir(l|UB37cJ-n4K!ZlZZzH`KoL8B=UL(BJj z<6l|#fGg3kG_ZIDcfiuf+md@>&;5$ziHl)aNQE@ai3MIh(b0lrP`vo-K{P+Nyb|`* zLCn_7uYM#_Zrzb8An;jXr#xHd58g8L=>I0-^6MSiof$m*ShTrd8R(0hA;ohgMS@CM za-7*38`|D`aHrl|mJU2vw_>{U^+w@`P6ozT`c?BIad|OrQ4v)V#7M5*M2z3;eI4sD zp}c&4V(Zhy?FI@vV9yK5ICj@}K>G>y+-XDqPBQW3om`%%D#$&>o)C#ompLjiJ)REo zBweJ1hWFREkvYF93RtZ|WAyOaWM^UHVqHJ&I&mJE!MCUTt#Wj*g|PD@$R8qBzZhP( ztA}1)erLSsUogkkyH2{;Wo$1NR+sEytd+~{a_NSJz2)4Pax`d;%0ra0sYqnFm;m(= zQ906W&BHsKw29NiZOg|jP5YUvDgX5L7sOomlsVK~KhQ$|$kk$3W;-RgzVeM{rK`1o z%upfh_Qtklii+;Ab)L4pOM`j3vjCM*&jyzM2I8Td2avF?g09w3}j1791eB4OClA-@%>c`dY+y$){!OF=fD`uY`y z3Ii6uW^`G$UOAqOCj>2pM}ijY>AsH`OOzH`MK%S7oK1RUtvU63-T0vA(ItM zWXoyMJKKyjOG<#>Zv%Tbes4c1*cI}hVYIF?ToX zy9~fQC8|O4RkGe999y4gc{2nwhIq4jkiD7Pt_9hZr#GTp zXad4b7?*6*-d}!O`BNEP<$SAd*U~8MUGE{rs?(I0OGaAO`{YEgwk$Gd6`O!+tIF{;1^%pV*nt(=jbnH463twvch zxA7FLAy&RbTErL$cjU_Wmerm|to9{`7cBvXmbRzN?Vmcg^cLoR?c$s31JI+#DN$9X z>ZJ@5)K!;j1qK$;5j3HVDx~rRysud)2ZFMdHvZNmcGWr*+iSfsNNjkGMm&Y+;o-5* z{ho+p!|)W*-r$QuxD}|KJAd+b2)WI}u>E2|EVrx6tyN~rSy8|irY_a?=gh=BH>-vmiiLYn&qAOkk z4B&mG1Dfz$w>=biuPUHC@594nUxJL5{xANQGwg$9C^98Jz1Ham#3lJg6}o?ykxD9K zS&mZM@V%R?so>A>a7bk$oft1EAFbCr;;cEAbkFP!T>Ec*B8{c5sfSUxaL7~ ze-BB>DD~0lXw_x=2Cb8d2(fNH0jhd&Sd_j!Se?Bi;$v*e-AFXLYCxY5HAWmT-yPVik1^o!FsR=mG zCw&t)M{7K0uc;1OjW+NafIh`Vrf1$mOCW7)wBLEUYqYnR$^%0MJS4uB&9PG_g@!!c=zab zV~H1mCnO_Bn%KGWLOJUYa(3qg{!oM+69DfLgrAiagPlkE&DnhKBterO4hWWhW<9Vk zJ%71l9I1t(i_9%i(ATv<;Ls7^#6%czf&7;REo>@ z(b^ZOB%yZLaD?GXpT4gc8N1w@CL3tj#<#$&Ry9)Pg(2Surj{dDl*+Ps&C43?%pp`? z6FHslOj5mz4Kg=Z`fHY-+e8go=kXKewa1W=vWVZSMJe|uq`uW=2VNve)^d#*jZ7yZpDy*Z61A*ea^lT=KPcf}AMg@A~<6P`(7sL~k_>z0m6di=N zGTadh!OcYM!n1(Ox6_^PeDzuTV17<{b5{>(u4ZH9+uh&OB$=`IJ|Al@xL}0Y}8cMvy|D2RaHZ zFR#F+KiiPK_`-7VpM!g^vT4BgbU^=gi~Vu`5`|(Uq!C53#WJA!Q)a*DY`-W;Uhm(E z$O<7u5blG*^ub3@iGi+Pk@TJ~pbZQ*RHV`}R;h#)(hy(Gq~@uy2QBiCJ&62}fto z`x!9=>Q^KD0f}bCCfJThKEp-8TS5i~WUa!0tWg*qc^=fTd+pC|a;V!q__<0^fC|Z3 z24BTDh?fmUIzL~_3LJ}(Pism={;8AtwYYFfrbxvIuxm9*G?OT=;0H2aU0B^x!euNf z$+uQDWZ?R#URF>DuVA_kUa7_xfu`E|Z{})eMvpc(l8nga`n((JrH|}(vlU)o zLE?V|koFXu>rG$Rlq#E7)Jm)>Bp9?&tW?* z%9T72UK1T;`|r%y!Ngn$P95J!TWp{+p_VMNPW3ElN`|3t$d`4p; zKfvw5P0&NMJksFen(DF9`jpif9%LCWQ|MT{MHf;BN^weWLJIJoCQ3SNhBlf;|6F4V zS!#9K=SC0iWRcWLSJwHJN%I#NQ7)W7MS+V&kGw^)AKoaUg2;gdGhLfA@5aKHEm$yU7p<4GfF#JEmQ58LVq|MXJ^mM?ustTWAAl=Ocb`40fh z+4aIFXd95)r_)z`&$ow2Bln8>WT(7f%SrC6I&-p34Y~u3rO^oqT5ltF`(aKv!=kY3 z!O(LdSi*XIo4XRjyF5a*k)EU%BeALFodwzntZ?$3*HS&LY z6Az{J>0MtSv|o38u+*0?7ZbpD(oL`TgW_+fCe-fkf8)S@hTNzO%PZk`+L zKG;wam6qPq_t6-oSO?esAHA?e1o{Cy-4%I_E=C+0k^%-efd6^NRaL`0ybBNppw+L1 zFbpIXjw$mTf=#s{ws06ydfmZWp*36TWMmltdU;(uZt11jIutCBfk4wM`P7R36jKus zm6XXASW_-tG|E?TDC3`rlb3XD1$1Iw-c@_g1~zHF2%azq5BaS?egv3VS5c%i9Uh=n z!V*X>>9;j@>%ViNU1!C)zx1Xna)`5Y)1}bc7W4urMt# z%(^Qz-IpWJLSbemdoflm8e`-zT1J1s__H$628dTGp$1g#UkKI$a8|RzMo;_VOT#B^ zHxDa_a+(m9^c&EIfaQxt#1)gCJ!Y5gXk8(1ppy;e)Ugi-6w!0mD8!t;Jt99w|m zJI6M}r9heG^M1H9*;@-*u(USbaW}lVXlYD~JCQ0(UA0wz@xW`k`SY5;kxm>m1o(H^ zD{Kzb(7{USpVE?O&wD5VhL^AR2VNTweYun6eFdc}?-P5y&uA_ia8Hs&J6P>;Ze%y) zq;Gs@K-Odv+(P}xzBwIkLjh~BdFxM7?D;#W(;?JZn4(|Gwpr(2{er9^WEejp{qZ9_ zmE*G7%hbfHV}}``h4J1zW{LPBp`xO~3_Mk%4=!VVEF#|jQ=_(bybS&b@c3X|ky3re zGwT#c=`+aj1euze`tNuZSfFnES0s*xABbkwOdsZ9_ivK9q=$Bn3{7<{V1Z%GTTPqx z1#{?Mj8NGk(hstR34I~m*$fPmpn-p;lK*C3p4(OCQ|6D#UmS3#;eIJLKkmnFS;yzZ zZ!X2+Pjjpn$;`?5xHB4vvu~~H*vdIXwVU85x#{yqVLgexMFHzP1J{2;s!ude(Z_N*=QwlRObfmS@u)EIjr__L;r!pR)iR@yIgwC;exrpAV1~?P#vE%mCk3 zu3=P4>Cx{Zw9;702+X%nUlpFjr@ua&9RceLk4_zaR~kbn{m@o(wj3AYRMe1q0SpUY zyMoG!dE5xnG*viXddelPjZ`>YUAn+wH3xL-I8o~@!ZIBc!lP1h!Cy}*h*NpRX!A?T z?7z2syJ@xuDWeP=541gFV;CNeo@yQ}mP)K$>WpQNYk z!3}XxAQyxt7W?H4q5CeoU*Ox$I@E!vofckt|EA}gGvHRppEbpQl0;F4qe-_5uh7OJ zFRN@jFBKI_xB`J>(cAcPthIRFo13wagDL4E;k8L<~`?b(DSwXQx+M2JKoPqu-@;t;-=t?=wv505r zX@YIGz{pO2EoRLrC(NFOr)rRd409C@Dl;#KUTRQhrwgn8<11IDAX1BvWpicm!;{u% z^U2lb?yKv3Ya3-oJymnXW@kk=M)T7d&$p{;xvYS=au>A0n!*UdvO^`UM89>f+9R4d zOay=?BF260(9T7TyCI_DlK^Fh{@jKc99=!pej!V0Pfe!w*_BL2B=$q;lHRE91UfpC zx@@mUaMO32@>teWw_2%@VCfBC0U{GN?RCr67j_mBloYHh5#$>KJId0%_@yT(RYJWec zOLGV<0A{@TCEO-CzpDK(xW{gN`v94*l|Mu5+fe!nBq3}ym4e>I;dOY&$yW#Yv0ku& zRFvSgNX<5cwb;uVTd-{zi@fj%kp!cAY43Az*?(`lBnPgl7oQZz)EaM=-{4sbBTl>X z^xZGcgxjz4XDsmr;fk*k)vilVY;UF<0-+pZA-eg=Tf~0sFm9os;BZcQd@x-R{kzpAA7acerWWxKQd>34U(ma;&4J3?N^UfMRu^GM7B+t=?U zY@LmZEr>fONgAXKDhd_81;jc~rQkyBRw%Z}rme>8Rk8b*7B^Xx*t7wh6Gd8DKA~TS z_7XJY>kC{`%%Lha;)MUUO|swBKpZ|^KEdWLK!1^S^|cT1NO1#;rgSx~!E7lJeO3jv zOUMqdKUObUB85o5B01cN3EFfnzSXp~fAjA6kBb+2c7j5>d4;`9bk__w2KFGh6p}80 z>8j<>vtDM6I1aA$b|-^vtS*R)=MBn6F);h;9Tb~d-KoMmCge?Gy6bfFP1M;REp2q% zkEu3X5FHNF%DCsUo_5fa%2!cww+q!CDo!%x=*?YF=Vm|gqc2a4<)g8lT=sInsNLb) zqgxLMQtWdr$6Ja=xEKP;DY@UXO&)3)v=Lv(5MZBg6^x;6(edr#zW~gFdLx3bwmr?k z)R+4K++cdJ3mFo$9z(4Vt*ZzD$>`5VF|@mVwWKK)y(S79^sC-5fzWkGBcEtCCsD=f zm$w$E9SbNGtqrmf3DQ{hOc0B--dY1xzZw0%-h3ZR@bK4u)VMmjoju@lZO7PS?8d!! zB`_XI`d)0tL7yl1WWF5(`gQ)w&rx=B$cW?rxi||SdpeK>}p~M@xE<4=ag7Y8@@y>U!z%0@BGc8$>Y1Nq7T* z6+`i3BNBS@_GWGKwcjd+wyzwsei;+zQs`|6You@F=c3j&6)h!o4uOcyz!}U~jiN#B z{+-c9qmdDPFZCk6j>mn33MqGidx}_vsoRYg&jFv$wf)u&d%J|-b9$5f|Bv=0ip`7_9w6D>7|5V8ba>~)mZ07G3N zSJk72FTVAM(;pz|E zaCn<(bT3z{@oqN2B8}?wMBf=JC1vk&4tzn6@n*4iMpV4alkxq!6xMa&gS$We%@a|4 zSKx83_Ur(C*%mD5#NLwmp9mn9w>-w)`NmtH_}-oD*8G`#r;HZ!&{7ZDrZ#`pZ8m;5 z2;Anx+%!_cN2Lu-0lFlvsJ^ihv9%0c%3EIGz-EjPyYJ-(y$*W}5axif@^~6OOx6_e zvx9I;^g@~oJJfLHQN)4`rE7D8Dl&6I_ixmZV;E6dU@LeMR??qZuI8Tu{?rwNzbFleB(4Q|)U$YW zEMp$-o7))ti#`T)4Cl|t{e+def?2iq~tzX;ie*mxMr}VB6 z00ERH%@qWEKTgCnvRu$+olHKuyG0T+$D`jKTo3~)D)~~#)4~BeiH?#5Dc({Q;=Kg< zS7~8Iek-uDA1hts9#))E`X5P}X~^1{8}lR)46$nue*2GoD1x(H6H_MJA)|Er>8lFT z;K^=9aJ7{-G6{8+-+Qxo8f|M^QS4=+2{6WPbOcE4bgmk8zgcJ zjygBBNKZd+$=}vM2vKIwOTR3}8<=C7era4E&N2DXwxuzBJ4+ ze<=zpi3p2i4)kg(6P#@Ml2%tRWn^UjWE)nvjt!*kc!hlp`>2_h8_Ba>xPk&)BZ;f&E0p{7l|p_9(#^SFO$dvxP3xQ@<~F4zFwo`J)sP zW!I3A#-s$ktbpb*C70yiu|9qy$#^0TCUtpN<1DhieTa18OgfntQd>=BB7vnS>iqFw z0e9_)8BE!N*1`HYQzpdHzI%vYmpgkmf^{s&9-4Kk+krruS{TSwK0(S+?e>HNQZ3t{V&m&RejG`1?n>K>R{I*{GDV>^EYfv%6S$2*oDJ)<&j@GanH}&12v8q$f}+-+0&I>tGwBdke?gc*lg&*ZDO&MWNMx&-!iV#Bos6 z0i#i{nz*rNQv!LEha#KmMH@;w3nb6bm6S*SwtIUFV1*BfFGj^J=t|ou&jIJP&`1| z9Q+e9^d?1yYAseY>cW|-*uNMoEPoDGu|@Lf(u{A#@~7xlp;@>14HjnFqWluH%8$(r zDD#w!7ieX0ez2Yu24T0PLb(wsw))QBa76NZ5=xg6sMuzuMs5<I@~;$A z+j9I~wmMXwQ|vE+=#7xili@c&sacVBZthG?<~}b9+Kjr^=Avx{VBVY7CpZvi*4t(! zFM738;^Xuqnwnf;e3NG!T>ebfD6Hi2;0s-YxQnVrEHWfZ^a_x!;di1@hwsKU9SNf5 z56lfDd&iw_Isy#xIO(tU_%Hpc1fz#m6|$FlVd_!i$)C-`{(1PUCQycCXTb^*dkI*3 z3(G`R|2wHt=OUw``=TYv)v0~x)1^&mE2gV(PXK=K@v6qUkQ{23d7b@@=&5_-Kt31T zt;eOFUZ4>?C}q`1`6P{=fHFQv2crC2UdwBKp9ezFT{jr^-DUz-9PTb6W5Ur2Hz|hj zf&2#lI^zq4@Hk<2otnw1F!GZU!1NO`_K4v#saWiN1$`aJrc=De7aFI!A z=EvKQ?=%A*5FGHW<5H-7@)t;Hn;Ld}zhqx?Q53WkF~W@LeMbKjLPDcW9mTR?js%Yx z8AXROMIi_5CTmOF59!J?i!XfMnQf=xY_4`7I6y!)bTUwG6RVPKeB8Sx4QK8J* zOC%T#?GvRBubTL(qFki6o;I*uA4GA8_@|k+mlZ{lUI|o`^sY_9vOgIf1&E*C_fNRZ zqx^Xwd(@IS8Iy%DYSlm=>JeTrxV%)F^ia#Sv#3tz+q^{qf$fo1egcvbVepOBs*K$t zN%T)TTKa8uOo}WjWgfx<1F?`%+r~9;zLVZ!(`#Qzb4oK?b^9emimO9qWwD_4CIkrx zY%y+oLq_78t1slK4&w->dVXnW*U@7=>m|r?SbEkUFOiJ?<)xI~m;l=IKRhtny?rYi zJD=TlQom#{o429e`#b;~ZC%*;Wx#OXFjSke&{8jmR)6e#+3?An_!kb1Cw|eOUz{N& zk2n)0%fVNkaIFJQe&HijJD9ojSv9bEq|wV zyzd}zEdwo!qbvA;UJz}L4443ylCDK_d) zU#qy$Ti3>E3b5i+6sZo)&x}GD?%y=sNtTYa*UbkbQ{D15M}Uf+`!{>QR5qCXCI0L5 z;8Sw`6s!Y^r4TjCp5!fKRqO)ccI8e0hj51rP6QA+dUNt<8ganUCpU#(6B*>CC)7;& z(0I~C?cF4`_s4b=s7BK6l8-}Q^^4>Ef@$7T2rM!A1<2jf&bG{((>K7(GPke$5NZJ( zlxlwc4>289WGjKCG;i^6DuZ8x?*A|F@k`pZficC;Q;2g|L&n7t*!d(Jf)`s;l;*zGlLmz`@JQ3)qdTJ|CRep0{cJE92nf9!C+vIwpR) zgmJphkFDEqsHLV@9q{)XDRZ{W&|mVzFZXM?Uz;etv$9}Uq!5ZCq#R~*Bv~H8@TlyV z|2?`>{(~LANNnTuRXP67)8Cr^akahW4mINgbtS}cXdQQu#Xq$2LqU|=L-a;MGpWqi zgV{fVH=%~#z~x`Ik?(Sg+5w1PdgD(wQ7%`5T?v1HYmS5oh2o1r5r+H`?N8L-XNVRF zL^>hCn==mR@cQT)FX;}Kb zmnPrHJYjI8Ki9;1dS)c!PPlwE2=?Q?AKJl$3`N@l%?$znq36 z5WEn6HE+txtlg`47OE$*I5@Fv#Q2K-UF+`1>T;xUhkdYWa~rPY|7Lmzypw|L^>w~= z0}nk-j-3o|F|-n>H|Aj4PvUC-x&}Rg#J{c&So!_eN>2g^!F19ebX!PTB5@!cSx%fH z2|=QgH6DiS9;~PR=U6IPw9e(nz{o{D@@0!?(>A1Cc2o&r!I-QsadT+SRVi;ho zl9g1_ncOTp+@%xU>`eR+kX1HnPX2Gwr!m1#@4OXP6Ka;?l>}#(=J(=MoC*}QvfNnz zEaQP3Uv~h2*C8#64k}W2*g>#wn8-8K(cI$`o0Gx0&h=6u$4l9o{}+(GFD7B{;eVUe z4b0AJ_`<$2cZU6J$un-VvT`;Pm*gmp0SLJ6{y|$^fP8XiuTS=F)6l$?0AdV)qH}TZ?DKN>DEs7<||EoR6O`z}O{t&?47q+X) zS3dgN*Vkd;(#7t$JFF(gx8;?gSiEBy&96n-Z!C?=77LCS(P>UAP`TM6;>2rc-M7hZ zuQ{CHo)N5qbhdmMsyJ^hk^h}33uCqA!ULK5{f0ZMQ~}-#^g;+bO^TiL|7UWCC5#}z zo;)xeqCzxeg=_2x*wryaEWAQC9aY9mY9fo3-kZTgu6i@zO-<-_MTy4e+f|ZINqcz_ zE-!FLz2J9y5)%S*bg&~^mJ6#>Jf+|x3=R(dsVu86cELHX>4vtUjO`ErT|0|MzQ3!G zxad>qDX55yCLqKGZ>?*tDwIPrIxu^N=oGC)eBs;r?i?y`X=Q9^kd>;+a%~7_*h7US ztdBvf?Q+?Khf9KuN4{2^lKzdk8y1OBn;VlmCr|-(SbdEKo6x>T+Ihb0eYJY0d}6W} z765|9#S;W6wVxpf*y5EWaTtl7j0N{-bHX6+UdTBSVPtb=Mp7-mGdAvH4uSC76R8NK z4mmNK#!1rkxl!q)>_I>)ZP&$&aE!NiSt$>Kh>@=Lh*Y+$llteTh2I(%%mw_KHIHCQ zjU{o%h#XFz0yqn?P$8?H!U>jnnoT> z?!@UgNXA>^fDS+Vo$H`7!0$iBFDfwlBG?P?8Px&kGVN_mDAOp!RPq8E?G&4z$6dH> zRtVxm$zxQQFgCL)gj%kx^OCozShI~62`O_H6F0Rvt(jXe)8lCdgKUnFj6GU^EPkv? zC=uzmr8VShx8Cm->YBwWpZ}0*6~nQ-ta7+mMf7Z~>y}+d*?6dHbW7xE4vhu9aQQA2 z=`W0b8`w_w+S6e!Fh{jFgMyeFl(yr3u}!4MdH~z5R~EY&3$%qpOSejR(pYK`;(P*% zMj+hB!5kth!D`N?YeS||*>|{V9eN>9xe|IuKAbv#JtI?Ai!5Prvp=-4B<&RYTu$AV zYQA|24L{f!-dUKkZjR$8vOnFB0_u)bQSP8{dI0_|y`(`y%Mc?K`AW^eH1eN z$GP9n$X{O0unB8A^C+^>Y@YK)iy8WaU?flJe7N!G@hetLj5QiceQ%U>ec4`ADZV;2 z$WeUY7G|b=JpLaMV%&=e5sg#5ten*OVT<8Ss)yv7>NZD@(xFP-uwN_(f^OIGvBMYg z9I)bwt6gwZomhBWt+>{g!wvWt)B}#)X;Gs3Ybxe_zu0yEnKYx5q0luo8j98(G?{!Q z%id=jm9}YrtQPtL)z3{WdV}ZKp&V9Y6ibZ9AsFpbrFU+!4V(j!m}0qv{PKe}>y0e8 z7ulfUvw1h-u=SJV-U|KIT;GfCpCo>i@fG1F#)Qzcy&uJ9?nJA@{;Y4hp{lIALcc{f zJfq!_BHvvjuHCK-QZa)W&{}Kf*2Rq3TgDed5??d+7R|l;z(c@>CL1w0-(kXASWbZ5 zfD&(sNw9M`T(vK7cgDU(HMU7On_M79`oy7!YS0&L?7t>rCo+cbCXo;A6P{y>R4EA^G%*mi(gbA<{2geWHcb6y{X!4A|R4)bri*lV2aloGgDW5 zNu|Jf`J(j$vo#rbK-LNmjfgh#Tg(@YEjIq<=Fi4j*eH(Ojjr)b=Dea;Yi2m%M~NN1 z+pglfzy+cf8Z=r*uq0uDVLeLM7Yb_5OQkTq_TX>$2Q`m3BK+7Ia!LNN0~&9s&rfKG zI$6+~T98*2Akomdeh*yTud7{8chfc3+3aC9D1ZkY$?iL(^TN0olxVyX4xLa`7#;tMZHu?T@&K+mm zhr6E`MM3RRyK1jmbIvtalmX+cAWQMsa?|9sh2GSYBXngn2l zb)6O-YTOcxqALbp6Z*B^2glH_MG0w5gM{ZSThT9YhXd!rJ7se*x)kND^!vGz|qrQ_Q=ihNdpE>t7iF1mZcw!K|NpHN|nZT zST$R>^z|yt1O?FmrfCUs=HI*;Bsj!+4fUJFwrL`zL5CNom75jAVeH3&YzE#z{+tJ~ z1fUAy8CMvjr&|UkNh0YyGd)hP6LfDghYyfsh|KIB) z+fuQH6p`4q^u3|Hn#mZ`8D~U#2(~8KCyG--OghiDgwypB#iQW`^MOjMGcO$->2&=$ zr>nB4bPl~m0nM8)7r8a#;Y8KTVe`N^XP=RRS?RRn7-i^ihq5`7N zi9dXPbI82sH)Luq@0VbsR7yC1JokUdUH&g}pBanGm&UVca6 zQ%1QS$JIK#mT(J5C%(D%Fo5$(H^5b%!)pFR?MVw_79z!$j;d;>MKL?L#O%$xr&|5t ziDhqpj|(mw}&ieQqKz7SJ57_0BFVw<$JRh&GP}khEVX=v)`6UD||BMaR4v@ zrr#{X=o>d+_>NzLu`U(U!SWooIm$8%oeMl)Ds;pGrkwv@yekvzDlUDyl39{bb=9 zwm0M0pHUqu!_A&1Edh<=J-xwR3NbM&lJ~qH%c?a#9KjEeB}i#^giD{+NsQ~C(9W~H zNpxTJR}AP6i&fE3lyF7A`1#a|W$ZY#1#l$JitXWRcI_25?XjM+LRlOT+bd`&R_x(^ zKhD}`hfRb+CK*<4If2c(Y8^XkTX(0seTcF7$xLGN*Uo`4J#Dtg`f&SMIV!o6o5ia@rRO`K{wKBO`=nWUI_I{g=4csEutynb%@Zc-wty;C#}-(Wtt zD>P64fkLM}A&>n z0R!q+%^|n(C-i8Av2RUZd%|4oDa~;bAR2uAA&rH%z2k2{|*V3SszPl88Y_K(2)8&!Z5^qe&CZ1 zE?nGS=@#T3{-UIIy5()HLWI7UX$sveP4C6Vs~6nxmLHy|@Goq_s)HqG)3~)BT#*$f z>k{mF$cJTWL!6l)$S<oA=JNi=l8xLu$yb25x)asDU6pjMlVIJ`Aw^dSTi8yd*M0DT{tu+YA&K2KaLQC#0 z6%ytO=j3eJPCfUbqT!Daq9Uh#y7o3Po zUBJtGn532_9bTP`m`bMo?X(tikHg_j41ovUYKBi1;euPpnxwtJV~Z+6_-Uv6sy^i7 zUgV(h;rm`zGvDa3G041d7QEH$kw2n2%Vg!8i7BYr(bg(^C!YiI87apSxdnA8#KJ=n zp^3tW)9yhr-lqjEq~U9%_V_dDYQmPodg$}nF*l;uD7j=(atx6B%yq5-`=!HikNSG9 z^OT2Wjj(@FjoJN)^rGD+U^7d;#~BCA-Q(TurHXCR9V#1MpR-YB^6vw#s+4dFGwG1PfddN1) z@~h09^YW;e!%bydL@@9cmxza9_Tp82L0T2|2W;9$q5qy5@*)6#J}X5_HGMyr3(#^Rf0Ibx%jIx`+0Ze`Z4Ui8IeJD6$8pNE6Dj z`;#KjSSe0O-Wte^OayYj)?a2(BT6&4xR1BNN_P#YX{YN~vWWf4z76M=y8+a~Q)W{jPqbQxe zez84JS>b`S&zVcU)ybPeKN8DL@B<_Fx52-GA{YS)A#h*>5p!+UljCo zhON8x*{xLh1~i`=*6Mhu*H3#I)DnKP(BCu^&s8IXvRD&4-YTVQribaKH75-8^ zoCpIdhjm*lOVjKSatgq_Bt~_{t_U`?=uf2zfrV1P_mARYYb_Hxe}-13q?GM5Z^Ch> z^U%)1Z(qfl+`}#1sitIHo00%$Pc4GMJl^qW8RN-Yr9w*=Byk^Z+#nf+Ugd&-;#K2H zi@3O##WUjHFMrEq{;QETsb;0E?#tv81K)vZrsaqiptc$u%4X4Gh zHMnoBM{8W`rkg=RrWmd#UkHt%{=31qK}k=R_E83H1RYP;+ei5WCBO%x6EFO%bi+Q8Sk`laHRC0MCQl{Ovyz9&j)&s!zR#q#5y0cS`?r(;X%>Kr zNA8c(j%drm^*D5VakAJuHmtfh8@mWK7Fnv{MlN|Cq0acWjU#K){ z7NW1(UsM#?K+3NI_CB)?&S`rsh;){`*M|*YB%g37YOu#mmWe)%s`8x zWi3oleJ}J*H5&*A{#5kg2kxX)KMcRan`zuC7~Wob9t;(Ub9Oemu%ZnZy(-yh>7=4^ z@Z@T%T4$egLY$Lim=nPr#!%^Nk-3Jr6u-j)VeA(ns|XC!2!Ed^C$S-@-_YOHLWW zl;`!@ms9oRA;nuBJt?l-o!or<8`6RF zytX$UZ%x8o%Q;(Qvtyo;8Wgwv2=mA@&V_cCSX?f2B3!C;^B$=H1FKvWs)9HwwwM+3 zkyA)y=&0cu>GGCa+tGXAjBm%d#vs6T94w*UGLFb1L3vKlFAn|VdRtX$B{oT=P@=Sr zqpy%Vb#bP7&rRIYd&Q5JCFS3Iu@EZAZ1~>05xnq$3?~UrK2kdPs7^mQ1XeB8ADr#j z;4e?%r9-CHS>Tq~wz6?V7T`sN8L>qB#n}_W$HACqF1SnD66-B{A227H&}`UJ`;hX6 z>uX7Ms@XqIdBNeDVc{7$6L}zv%BVWw26~mKhlLfI0y4t7iAvXb1W8vnA4dBuNjLLb zx(>RG-mZe%Vv<=ro*jI^>zess(a{}Gr)gU}!OuzPN#GCPP9-IQSfp-Co`XoUo8W^E zcakZyF?JvLlN`7zRmC~5>x!_)LKgl*Vv$}48q4HMLIbww2jm+{A4vOAoF*{(rq}D{ zi(n|qCrzc^8b7u#Es+(V=W0x1%0~Q)_;q#DNs>05ysf7RL66foa$*}@h{pL>0m9QB zFPc7)d91E!fW!>Rh%M+LTgl%NbuHMr112O8Z=N+0c|_u9Ny4aXE#k(kH6(n4%;5l* zp_Nns>q%wGO;dgR$-@OZoja-i4jmo3pbZj_I68zjUxwg;6p}@5jH`bY`G9yhGg2KW zu&4Q%pig342Lf(A>BJmtAeeJ9)euMM;j!hk@MK@THD*}xF@|nKsnBzKbe%+ zSk}pL3lKmU3HN3Ks$)>TC`zlR3_av@rVg|5I=NuwVt6va6j`1os>?6E^@zdJe7M0xC>6Vh$ z824ma{`0tJ`^w*!>>3z)gAxGs0x4@PHombnE;3NH z7W;uUomLYoSz;*?%`?@5gTs=o3RSqSI#oWovFQy&O$&qo&0FTI&|MX*wzV7G|z<@BjhqZn!IFI)V; zp-{f<^IM#jivYU{8;P+1+xcoUN+H5B3D7CI0Q8|u+^w#=b!n=SCvWyN^!>?fGt@5q z?p1S=y`&n4H2xbs)70Ho7HMqfMj!=wtQxJs^NY{YeJ(NmX5Ljs$^Q8fQE)A*iie)! zEcj8T!e~8gj$=2+W&3G@uuasQmgWwxmG?v0nef4FL~Cpl>)2^}P&gHdjvE1`Jm(96 zX6>^X^G?)Z%eHcx&Ear7Iqwrh?av)LWd_(%m+u8~oJ`V&CUjEv=`~ z1Wm|_@lWeUk9Vd<%}1yFTz_MuT^w}UgX8esnVk*b(x*ny5U6>+v5)58YcR3qeKsv) zo~`4RS)2P|)B+(^N$S#CX#ziYvu&XdjS76f2tq}i=fCr@8B)6-E#$o3T4eDhwwIHdE!t-99KEHwQWJ$kYu;Siy_jmi-kWwMaB9ZobCi8wv4c8ycTfT<^ckC z7vanYSL?s+jW3D&k4b~x<7|tq|KJzbiQqRNjo9e!-%R7BGEyLdA3N5!CFfv)ppU(L z3s^PIKD&2NF&`4i#o#;DP7C_0K{4Ssq7#-*o5+b@;pGy7h|VZ#U#fDx#cS#^z50zp zSui51kca#}i#0v@3TIViR+wZ`UM71<6mfpVLShZ0r`2?8Qil%M#6|{mTAGnv2)Qu* zhIR}&>bKu8Z5qAc-*8>9eSnoWrRLoaIW8~8xi)skF+3K)kDDWIFus-lmLhE7PsO$s zul*|Vgoc4C9?vsf&2^T+&YlsOjrL>sz3C4g&pt$BmZ@j=OBdLp1_%y%eti(v(@y^B zY1I~DdDStHAvcQs7?G0||DYn>dH2u79C+fIT;&4(ZKk{;@8q+Dw2MQhA z2L@rs))A!f2-j9#>7CO4o;gj!n~q~hb@ghINBuFqP3(7g=WC`Kp1_ZLw(NluUPqiF zBaM3b`>c1yQ7Mr(4MZ?8#*mn0GfhK3v#P=u2A8ibDQk@@>bzaPZ`(usW2+%hp{Sc= zhbUp%a~qL-;7-yC!|N+8DLE~W>{5Gtk1)1Vj5MkqWR)!p3oWIz(q=WUwS_{7%@i{{ zi*9j<<6J1f&PrLmfSNb(7R^&Dn4Qiq&rdV%lC0ytp$kLI|JXSz)Y0d{_ZKSlhhzfs zPy<#79s>#V)qEY3r{%IOw(?H+wj>Dr@k?>=!$J1h!h^>X=L*xmN&4)+>MxwX8W}2P zE$E~x+P!lCLK`#w_m{`ngF5NqCww-Z&}mhJ7p~<9kIKFCc3w$1-t;a$_%G9ad3VrL z{w-G6iOcJWCjZXP_e$qIH2A9j`YY17ecd3|*BaZ`f$_gRAqz2Ir5gXn!G8oD^ymMd z2kkPi(u0zIzL_Ytgzht_b`!SaQYtDq5l(UIYKr>u|E{53I?%R>=53#w+}yUTzqAvS zyG*P39uuw zR@LHfra8*eb$+ZTpiSs2uGKo0V7G#(Y^UE&o?5Q-_*VKXQ(R2*Ky$!zn>Wx*TRn}wlkdc`-kq7&`^QPbc<-EHA=qXalqy@ zv3G?@E5d1XX#AF`SQ{jnk+d3pL;ZZXz?A00xs1T#cl1?{Q~Fv}pi~2`-Xn{sa5#UO z2=kM|%BSByE$^RjJ2d}Tdk?j|dw9E>ZQ+MIODR$U%#gZAtvfv5s}oR-kIZF~Q#Zo= zJ4Qg`92}YK_HntBHdPVhi)!CmTLgI9Zmv_2DZJEksjFdqfXQ`9$@E)UM~?P4o1(Fm z^dBw&{Z*;*>cwkCn_rMqDVrM0J6W1fG8*?fPy|s}ZhSvMd~S3sBmOkB3UgDw8`0SmP_10& z$qLn}Ww)fFhkdALE?#wWKhsU@^vHaEd<;xB4}Um8L{;m?rqJc2 zx5Je(P>`9gdE%V%CT)AOrrQ#dI=&l;3Yf=>3(iQ@?;Cg?>e?ejC+rYr+U-ekX4<^5 z;0QF?*%Oewy9(Zjq;8CKy2)dh{QjBx+oNgLP`R+S9}a58hJM)XCT;EbI4{s%EX-bx zHS0JBDXQk7Gb;f_w#B2cBhGF@41Jp_n($Py!wUjkt3NFcRTl_*@rK-mi?&nu^fYF_ z;oAXQh?)>#DoCEzCK+d#_b2>f7B9C@BOUz5AmeDg?U9)(dp5M$Z{@dMf=!=T)@CWP zzTNpexr7OB1yk1J47^u=+4=5al;B91K$!*bq@6g8B+2)m_oF7Kn%iM&E84_dW@qa~~z!DFD!299GmGQ)3NgH(EAoLR;Fk{=vXoqX%8bg|~`28awu z0b$r{{Gxqj#e5a?P;HY-qV>gDblKpJXa0x#i>s0Z>gGG`j8S|uqd6yWNgn`QG?cX& zYGwGw0eK_8Cw|diSm`=2FeuTt_$5l)Pa$<1E2zSTf_w>U@z8UgggmE0(RrL17D>*Lj>|w_Q4qf!S5Wco^W^k$to{m*Y+fVm zg~q*31q>`rWhp(6l+p-CiU~5YK7UUxYVJSVDN(euwM`wk<{dxp#=lA=k|$hScJ9cf z(%LZmL7|fBQK7?Y>Cy4Bm2;vzose5ZFHOPSwc87;l#X-`9N~G|5}K?Fgu_}7G54M$AY1{lk?=gh{XbdY z926kIDQT1>M$exIaSm6o-^2NdvIt{sK0(Xo-Dx3BCx5FD0Fm!#?wQ-1p0}@V(BoZP zIMWSQUd1aaWhU0n*C*rgK=Yzz!%xAj%jno%2%RLli)v+b#S(dyfE+yjF8d=WmTX-WLhZqa(2GZ4Gj`? zptOfEcd&xy^+?L%*WTwC`0}ACs5x+S;FHQjyl5q<2rk^c(P4?h12BODrUb6uv&tHhtbSd{fvxSx`MuOcJNGRK3m_b81q z2G1_kuk?7WR`_MKB5sJ#RO5@KnNZG&(L0EF0VSRS9vUoCZ+b)%eC9GfhuFAF@48ju z`$bF4rOfL5$ldK-`#G;!lLPI1?2dZZ^lTuiWcOw2Z-~7Eq?vxvRb$GX2^u`Umh83` zFvg)HKy#ug?$IUJr5;CBa@tS}BLOe$Lz58lcsL~81XhEDT<`Z=2_TAj0 z4Xlww@2y*Sf5-J0>84uko^j$PUzsuzjF0yyS3c;B#Hj&>NTVPB?C_dVuPY zR+_XWx?usY&)n$t)3|2)OZnroZrTlF9({9DvmJ8~Q4uS^azkRW*@2l>Kf~SFeWn=! zQ$uM7+?M1yn;y0Va9q1={&V6$u^l{7r&Fcw_5fV@P3h9JzF-whDvCTT4lAx#_LoYS z4xRa3ti-pjclcCGKSn@WMiv!pttkiU_ACPwei$8|QV67N6hxTrS$#CtNO z-Is`*D8wc24ryELtjReC`eA2xFQWA7>3x{c%g84x{`zb!o_9dqo142+o5KDg*X`Lo zKXKHjp=8KALZXt}<)MGuv)UdVaW^5D}}~@#5sy?NP7N z9S)swiDujK>nOChuEWqQhr4+xa(cUb0Os7Yc7^SqwO4a4Wb$@ak&FUrD-f^45ed%E zU?CB+v>1PFWLOUI_|z~sK3}(>TVOO#J4DedKHe+T=*rSNN#TUe!GtCwS!wYU#(Ppsmdu!lR-tSvu99VktbzFYEQW=CIM_FQR)64y#C17wN`?+ByS;Ro& zn{T7qjkmotmN$f@SE}ZP@?{Ue;2-Q40jqewc$TDCR&ek(UCwR}f@BiJpY-I;>=t%Z z8pDo@h_{xOMUF-Z{ESv=Co(>B)K|)L4i5Qj_~P-zDc7p(1``D(B zB~=o?JYV=VJF(d{XjR->;C+23O8r=vAOU}Fds)Z;Iu`T))Iv2^5?=maW5tp z70ZRyQVSbFX8`n1anmFRs{QSzh{~UOb|Ux0c;Ec_w&pU1WWsV8)bTg4ROXzh|I4B! z-0$D6NrfYhbPGdv*sd49N1AQu5aaZtKlR08o<)yJPF{cZ(9V$T>iWWS!GH+ORwB@E z+bDxeHQ16;Qo~2KN%r)cp&i{H!hg3cymnNuae{wWjVi&RO9)@i5SD%nq!()ZM1NbRwhcLU?2SHRmeg zBb+jXF|k3*q@{lU(p<(KUl-iug8t5z=r<0JG>E=Ifj=RV=v;HLl7|)F5>#RZG~-@govEY4dAyzC}y#O&(_&A;|eOoZkMl1Cl7F9hN-?hd zuOBreTi?T(1Hkfrx2*Bwb7?d~kw359l?CFH*7(c%Tj%I1>vDz7-jeBzgor`ik~*JV zk;YUV`$%-{>_gklRvat*$fF2~5;xWx&{bOIXx5wRZ{K-R;wlDk3xQlc#I+7$smq!{ z0Ec6{&=-OoE{9hIPIGi6_)p=l6f!6!LISJe>a{$tYl;G@bU+h&IXx$eSN|hm zyaB{UUZZ&}VRUS0JBt3xmsRRsUvcoZ&uG4e8Oi6Azh9LN#{16+nkpe@ zGG4rg`O#j8J{5Ldf8E78U3nv4vtB!_2GfRP@s}pv=cm&WtBAcZCkEH0cg=XbrVXzM zK(=uHQhnQTP7?15R!&GuiQvEd8Hxs0tkHV_S%&uw z2>_mgOPKsmR!Um9o;uQ35-u}dYyj!~)GbU=GM{EuOe#n!^8d@d3*RYHiVTA^k%pXp z!`8MYHf8SVkc&I2dh*WvTB!xU4KkITX9X{NAf~|JGq3P67DsUA7O$=>^9&S41p;rjP+hO%VuDEW-Do|aO`7l6^z%u+n_94r|9E|Lt zUIw+&c^#}WaWVC_R<^)^O7wWe<#h5eKZ7=HO2!m!*HfS=7pVQ|2QBLyeDX?#(b7cq{Gt=mmp^ zGa^>#Yz zlA&ij;9vq1PbC%~tIQ6`3tcGqS;fugkoT_rwco1G@#;3nPOtp%v^qzMiNk5J&2aSj zHbgk=eP~&yptlN4$RKVhsqqr{2iUAgC6|I1TwbctQx$LcQU-vg3j{6AKvU0`3yCtF zt22l>Jy2?w3R!rXqyI@*1Cm^YT71g+u&F~?#r0T_sOyptF zL}ck1j&GDWND#A6!)mxXFyh=&4RRzQsC7Q4S*gmBWxUStIb{O2KnxHNs|@U_9!F>u z?8DrhYYS6R>GiPM;Oh~$4!+p8u6)}@Oo6P>S<-!M1jwux(VS~$4KjzK_*hjK{Iw!p z)M9k_Pkzgh2~@dTBF}*v_EG(6Hzvk0OJwu8^`$zb5snt_Y;x`6(xAUzx15S_>qYQ* zS*L1BrO62qKzVEt_fBo6S06o35d&q~#!Jfz!#IZouRzkqy_-2=nfUHD*?SSK;f{m6~ zW2zCU8zXdA-{P6YAZ=n2b>cErcQyE4;e-!8akyOu=pJ$<0lKrl*=$wd3rwUsq<(Jb ztbycTgkekZJuqrZa%xrIRB_*LI8#7d!xe9I#O?ZfQ zeckQC!cH_4-NtKLD*&r4EL4i>3FM!T_8IizHNlXtf(*ktMT$3a!w*>{WYG`qM7M9o z6!!cj)MbV!v4byfKXT+=2S3bFQ9m4~3lQxFIu1`eDM%jyjX>p`Nf2Yj8#SRI_FK+E8d8(;|@Q3F8i`1 zI&PG06J_~i7t#P->@8$VGI2&l*(QN}xxPjKu;HaosTzjR{ zF9bq6pcE^_mj8xzI!#|0&Ol^UUuO2X=#+_zkn7H(Vwre}whi+$W(mQfir7&5^sAIC zEG7hwJkdDQ=Xc?<-||DAGRG;sikLT7c7w+jpvpQ=u&;O84qj~804C^(gGKj(P#<{c zvCsOJ!A3%^G|aaOjf#pHsX0or>-XRgU#pm3oKuEtQxCVmOC;j=*zm5yA-*w*MZ*hJ zb?q8f%)ja(c&$@1W&bs%aY?kQ2AVH?XVLj(8tLR(Homj{G+K?g z$fG>7`)SRMk|NUGWs7rp5(!9Ztg(M1INxr;wkof7>I{r6))rDns3nw3wCKh{oNs%? zK*$X{Cza{qv%jnB9KOimaCI=(8kG6+^bM4Ur&C3J>0_hWXLuMjrx^kA@Q-%9>s=7I zR8tml9UnX26%oI>W(d1JLYL2zcOy|UHTWPi=T+6RI9VTDU{32h`&op(9zfG@wy0lT_Sy z->+{oeNY0c*F&R7bAABGq>0G^_>u3GoVxc3HoAap%|DhWKc;#1Q-L6(Mpg&Xe0auH zTkDSGnhk&=KWfZXD?#Yiy3+g(BVAFi-jstyCllN@$`uCGt5Jl#@^TIuqLNq7Ahddo z)IbrY_|5+upXEh$oe*v+5kWrId5Z0?5snt{(zz{io`uY8UM=3+KCOoVV5hAVI$Z+I0 zA9zrbA=>gB{zEeB{()f_%4k9}G;H`9EW zVLp|+*`4boz|Gkvm zE|x_tHhLECf}avZS@mn&92e_VZJK_zyi%~`yZ`xFLh1{Vk`s1 zJ&gxZD+^q%`g>1K0;+8DAnxrnt5ZCn-t3Oo!d3>=!$vTUua?W_kyCyuBe@SuI`FNN z!%$NgKjBFau&6gGu1|*KX>cgCV+)1;Jel%6DV64z!{)jJw+wleW~1@XkI){;yco2^ zF_UdX8xAC2D(m>a-%zqT6+20}O!G8~Ilz_p7;w}}i|`QFh=plrBdID8!5qK9-BC*} zbaC8rI$mG-i+(R=5bLHqg&EC*%Z>EmBNEdtwJ%8`Li~KZLY9+Y_?O@!aUA!>{C$7d z;R-%}q~X=^mztd7W7Od%wDp^6kr>lTPbeozqsE15sy5fy7+ zGay@+g}p#s*#mh*Q~B(m25R}@X~s)9qW1&;S8AQ%yAXg+bkCf@hf^Gy`3LBelK>tx zULY$PV#}L#V6pyUN`Y~=LQ7jrR>0JY9QPz&1WX>+r(fnX3^y)FHa)Hf& zObQ>NoVQu2ub*cSq)z6(*>l6?aUF7_wrTwWg8N}3iV-G+_6;j%KATy$pJcb(Fo=mR z&C%Wt^-&{C=)U`NY8##)lGo*TX?$ghKz(o-><37>6bcRl9#N0?jH`c%^$K5{-elg4 zW$q{-)1`atkpqUQ!HJM-m28ZHjm8U%&N9xXp-uM)G}%-|HqSH7^q3P@fwq`vT3a-_ zl@I-fkFT}P{GZGD>EilFWsb}aLLL<5Y ztOYBy^7{y?iVgQzR*C!3}j&H5J=N&!{-0oD11n>(S#Q0? zLkqO{u~j@iCQzQRa(@dw>KN`p9#Jb%4W^{urbls@Sy(How+O0Cq^vp>h~n!5Ou-HzHTi}=k~UTeU%V*DQ6bTj^ME^%li zE2jWsQR`BD)!`j$acxYOdEB}YQ5=vJty{B5?aBt=zFoEJ*6 zS#I-;%qdDFmJQ>G`OxY+pvjp1AxO=LrwEKxxu!Eb73kH{G=fjDQsx+2KktAo=@7|U zHMcg&QLg|Gm%9-1?U}A7ob&>cs5bSAe1jL~+HL{`NWKrCwjDTDtFhnFGkRshH%EP) z`umv~M=UYx?OKw;qYNxMh3>}WKIyZk34?XxyBEA;gEXczIHz=9?qSNtFx~ zdsXapw3^n46@zv>VH(=5=lAeQOVCF^e0ZvS1X@nFn{{LS4PANM`+fRKa^r;X=!sx!(;JN^n35eY>n~pNIM|8d_O0KA7`cQ- z2KCJ+xWAa<8~{M~D&_*hgRDh9E4|iSj`!b*8pqKHhY#WANUD-1YVu*b4~%?hF%2pM zr?xFTgu|)F{*S^jS^HDN3my?=CGJN{Sf}{b?$0kfxHgixp8F{-HEe_G_+cR3Bb`tp zaC>-7jk?ZHAK9REc6vh~xn6S$a^Nog#?-dq-uB%>mT{lWMn4%cSsed zzd0*iBl_YQ^fvB`7mp`LUL~69ZvF*v^9(p=?}@l;l~B_6qS%za-5nz3T*s{b3qMwj zkTwoG(ro^*{`LBTstX@p58aIDK&sxGDfGJ)n)b-lRvgjV8m@KY{Kr;rG4wZNc-Ysi z9u;n|?&+NJo4{z1blY%54U}ATA1;}ivf)!V~zFZyo5HuyznzL`JOkU)TTdy6gb9{ zSszLnZ0fk!FN@|=bdVm1wtC)#I1-m=&y^Yc@K5-|m@vNlC?Jcl$9G%stP#RGD*0jE z$z*LS3IGwVr1M2>2Id)i8h((9toCKt&MceA067_Bx>4R0phOKvu}<>J4&VngA*M=f zVm}p=w+It(uWH4NP#teP-B1WTI}(d5`bJ|g6H@mJ^eZxU2m3uCiZMqotsctYT(ZA` zekPDMx2K^bWdu%Pq4(A1RfVN3BlgOmzQ^c_^Z0;y0*+e0wNRjB^u0c1`!vLap}Q6( z@ps6uaZRms)j+G}zgH&1`)m5GKFXP7h4mk;vtlB`gxJ_BQkrIbeD^aBU!vaezzb1^ zpM@zjVobrILZH=7N{V>vs%o@bCEbJd=)0w!8)N_5$1&NSz=lH#A++AlmsbQCuBLlJ zLg$1y|%sZ{^GLBqpYK~2egdqj-(_8JeiA=#ZF z1^?xx=rsAA!}FM^lBduAjY|LEJEjWI{Jhm$qSG7t()mF(Ry$e5}-!n$gE*S#i4-dm-_sS*ZGl6 zTeGjr7Go3Ji6C4T(S?IYSU`7ES~LdOJ}K9gIiv`>+%g|djPr6}%}-fF7c{~Ajj6$Q zQ&bxxfef zsC9N8NBm@`=ALgSX6^G*tS|}%t)LO=#EFX0d!K8Wm=p#K;;cdQa%8aCc#%yT^qHGh=J z91V~CdE3-#G@W#FSv_;+sp_pxFKOJl9sc?86YD3!>mHL0hJr-S^AH(f?8)dZ&g57R zXd=9X@T$nsO$oKPQRExvM*N#mVNixJIXZW5lh1+H0(_u37{;}*dH6`;v>#5a;N69L zKmN%1-iCt9>HKFEAAZg(6}%8eP=&YL$c4{F=3u{4?3dhan0wm`?5hOIy*>Y|A+C4X zv1zdVd=ExxEHCd#KSJ3^mxE9kfPUgL`$k0?+xlK;Mj=U;gSd#bW|(b7RCoPo%30eg z{@0TBn2$RP^|vL79myYGp=5WsSDKx9VKKGsfjbWjC}x|tW1|nrfQ?2X{o}C+tG)Lt zF+M9kK_@Bd7P>M}83Qs_NZGL=0*O3+jIB0&Ufw`l_!!V4I V7@z5~;EK^_0{3{@ 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 Date: Sat, 14 Sep 2024 13:29:36 +0200 Subject: [PATCH 07/17] Update locale_translations.h --- src/locale_translations.h | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/locale_translations.h b/src/locale_translations.h index da0c78d35..0e3b893ba 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -64,14 +64,14 @@ MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos" MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate MAKE_WORD_TRANSLATION(setiovalue_cmd, "set io value", "Setze Wertevorgabe", "instellen standaardwaarde", "", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io") // TODO translate -MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Sysloglevel", "aanpassen log niveau", "", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu") // TODO translate +MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu") // TODO translate MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Lese alle EMS-Werte neu", "Verversen alle EMS waardes", "", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS") // TODO translate MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP") // TODO translate MAKE_WORD_TRANSLATION(format_cmd, "factory reset EMS-ESP", "EMS-ESP auf Werkseinstellungen zurücksetzen", "", "", "", "", "", "", "", "továrenske nastavenie EMS-ESP") // TODO translate MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Beobachte eingehende Telegramme", "inkomende telegrammen bekijken", "", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "", "Gelen telegramları", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy") // TODO translate MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "publiceer alles naar MQTT", "", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "", "Hepsini MQTTye gönder", "pubblica tutto su MQTT", "zverejniť všetko na MQTT") // TODO translate -MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige System-Status", "toon systeemstatus", "", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému") // TODO translate -MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplan", "activeer tijdschema item", "", "aktywuj wybrany harmonogram", "", "", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánovania") // TODO translate +MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige Systeminformationen", "toon systeemstatus", "", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému") // TODO translate +MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplanelemente", "activeer tijdschema item", "", "aktywuj wybrany harmonogram", "", "", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánovania") // TODO translate MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Schicke einen kalten Schuss Wasser", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate @@ -117,7 +117,6 @@ MAKE_WORD_TRANSLATION(tag_hs14, "hs14", "hs14", "hs14", "VK14", "ŹC14", "hs14", MAKE_WORD_TRANSLATION(tag_hs15, "hs15", "hs15", "hs15", "VK15", "ŹC15", "hs15", "hs15", "hs15", "hs15", "hs15") MAKE_WORD_TRANSLATION(tag_hs16, "hs16", "hs16", "hs16", "VK16", "ŹC16", "hs16", "hs16", "hs16", "hs16", "hs16") - // General MAKE_WORD_TRANSLATION(on, "on", "an", "aan", "på", "włączono", "på", "on", "açık", "on", "zap") MAKE_WORD_TRANSLATION(off, "off", "aus", "uit", "av", "wyłączono", "av", "off", "kapalı", "off", "vyp") @@ -126,10 +125,10 @@ MAKE_WORD_TRANSLATION(OFF, "OFF", "AUS", "UIT", "AV", "wył.", "AV", "OFF", "KAP // Unit Of Measurement mapping - maps to DeviceValueUOM_s in emsdevice.cpp // uom - also used with HA see https://github.com/home-assistant/core/blob/d7ac4bd65379e11461c7ce0893d3533d8d8b8cbf/homeassistant/const.py#L384 +MAKE_WORD_TRANSLATION(seconds, "seconds", "Sekunden", "Seconden", "Sekunder", "sekund", "Sekunder", "secondes", "saniye", "Secondi", "sekundy") MAKE_WORD_TRANSLATION(minutes, "minutes", "Minuten", "Minuten", "Minuter", "minut", "Minutter", "minutes", "dakika", "Minuti", "minúty") MAKE_WORD_TRANSLATION(hours, "hours", "Stunden", "Uren", "Timmar", "godzin", "Timer", "heures", "saat", "ore", "hodiny") MAKE_WORD_TRANSLATION(days, "days", "Tage", "Dagen", "Dagar", "dni", "Dager", "jours", "gün", "giorni", "dni") -MAKE_WORD_TRANSLATION(seconds, "seconds", "Sekunden", "Seconden", "Sekunder", "sekund", "Sekunder", "secondes", "saniye", "Secondi", "sekundy") // Enum translations // general @@ -149,7 +148,7 @@ MAKE_WORD_TRANSLATION(seniors, "seniors", "Senioren", "senioren", "Seniorer", "s MAKE_WORD_TRANSLATION(no, "no", "nein", "nee", "nej", "nie", "nei", "non", "hayır", "no", "nie") MAKE_WORD_TRANSLATION(new, "new", "Neu", "Nieuw", "Ny", "nowy", "ny", "nouveau", "yeni", "nuovo", "nové") MAKE_WORD_TRANSLATION(own_2, "own 2", "Eigen 2", "Eigen 2", "Egen 2", "własny 2", "egen 2", "propre 2", "kendi 2", "proprio 2", "vlastné 2") -MAKE_WORD_TRANSLATION(singles, "singles", "Singles", "singles", "Singlar", "osoba samotna", "single", "seuls", "tekliler", "singoli", "slobodní") +MAKE_WORD_TRANSLATION(singles, "singles", "Einzeln", "singles", "Singlar", "osoba samotna", "single", "seuls", "tekliler", "singoli", "slobodní") MAKE_WORD_TRANSLATION(am, "am", "Vormittag", "ochtend", "Förmiddag", "do południa", "formiddag", "matin", "sabah", "mattina", "doobeda") MAKE_WORD_TRANSLATION(pm, "pm", "Nachmittag", "namiddag", "Eftermiddag", "po południu", "ettermiddag", "après-midi", "akşam", "pomeriggio", "poobede") MAKE_WORD_TRANSLATION(midday, "midday", "Mittag", "middag", "Middag", "południe", "middag", "midi", "öğlen", "mezzogiorno", "poludnie") @@ -159,7 +158,7 @@ MAKE_WORD_TRANSLATION(vacuum, "vacuum", "Vakuum", "vacuum", "Vakuum", "próżnia MAKE_WORD_TRANSLATION(co2_optimized, "co2 optimized", "CO2 optimiert", "CO2 geoptimaliseerd", "CO2-optimerad", "optymalizacja CO2", "co2 optimalisert", "optimisé en CO2", "CO2 verimli", "CO2 ottimizzato", "co2 optimalizované") MAKE_WORD_TRANSLATION(cost_optimized, "cost optimized", "kostenoptimiert", "kosten geoptimaliseerd", "kostnadsoptimerad", "optymalizacja kosztów", "kostnadsoptimalisert", "optimisé en coût", "maliyet odaklı", "costo ottimizzato", "nákladovo optimalizované") MAKE_WORD_TRANSLATION(outside_temp_switched, "outside temp switched", "Außentemp. gesteuert", "buitentemp. gestuurd", "Utomhustemp korrigerad", "temperatura zewn. przeł.", "utetemp optimalisert", "contrôle par temp. ext.", "dış hava sıcaklığına bağlı", "temperatura esterna cambiata", "prepnuta vonkajsia teplota") -MAKE_WORD_TRANSLATION(co2_cost_mix, "co2 cost mix", "Kostenmix", "kostenmix", "Kostnadsmix", "mieszany koszt CO2", "", "coût mixte CO2", "karışık maliyet", "co2 cost mix", "co2 náklady mix") // TODO translate +MAKE_WORD_TRANSLATION(co2_cost_mix, "co2 cost mix", "CO2-Kostenmix", "CO2-kostenmix", "CO2-Kostnadsmix", "mieszany koszt CO2", "", "coût mixte CO2", "karışık maliyet", "co2 cost mix", "co2 náklady mix") // TODO translate MAKE_WORD_TRANSLATION(analog, "analog", "analog", "analoog", "analog", "analogowy", "analog", "analogique", "analog", "analogico", "analógový") MAKE_WORD_TRANSLATION(normal, "normal", "normal", "normaal", "normal", "normalny", "normal", "normal", "normal", "normale", "normálny") MAKE_WORD_TRANSLATION(blocking, "blocking", "Blockierung", "blokkering", "Blockering", "blokowanie", "blokkering", "bloquant", "engelleme", "bloccaggio", "blokovanie") @@ -650,6 +649,7 @@ MAKE_TRANSLATION(mixingvalves, "mixingvalves", "mixing valves", "Mischventile", MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere Anhebung WW", "Verhoging WW activeren", "", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV") // TODO translate MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung Heizen mit PV", "Verwarmen met PV activeren", "", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV") // TODO translate MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Kühlabsenkung mit PV", "Verlagen koeling met PV activeren", "", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV") // TODO translate + // thermostat dhw MAKE_TRANSLATION(wwMode, "mode", "mode", "Modus", "Modus", "Läge", "tryb pracy", "modus", "mode", "mod", "modalità", "režim") MAKE_TRANSLATION(wwSetTempLow, "settemplow", "set low temperature", "untere Solltemperatur", "Onderste streeftemperatuur", "Nedre Börvärde", "zadana temperatura obniżona", "nedre settverdi", "réglage température basse", "hedef düşük sıcaklık", "imposta bassa temperatura", "nastaviť nízku teplotu") @@ -667,7 +667,7 @@ MAKE_TRANSLATION(wwDailyHeatTime, "dailyheattime", "daily heating time", "tägli // thermostat hc MAKE_TRANSLATION(selRoomTemp, "seltemp", "selected room temperature", "gewählte Raumtemperatur", "Streeftemperatuur kamer", "Vald Rumstemperatur", "zadana temperatura w pomieszczeniu", "valgt rumstemperatur", "température ambiante sélectionnée", "seçili oda sıcaklığı", "temperatura ambiente selezionata", "zvolená izbová teplota") MAKE_TRANSLATION(roomTemp, "currtemp", "current room temperature", "aktuelle Raumtemperatur", "Huidige kamertemperatuur", "Aktuell Rumstemperatur", "temperatura w pomieszczeniu", "gjeldende romstemperatur", "température ambiante actuelle", "güncel oda sıcaklığı", "temperatura ambiente attuale", "aktuálna izbová teplota") -MAKE_TRANSLATION(mode, "mode", "mode", "Modus", "Modus", "Läge", "sposób sterowania", "modus", "mode", "mod", "modalità", "režim") +MAKE_TRANSLATION(mode, "mode", "operating mode", "Betriebsmodus", "Modus", "Läge", "sposób sterowania", "modus", "mode", "mod", "modalità", "režim") MAKE_TRANSLATION(modetype, "modetype", "mode type", "Modustyp", "Type modus", "Typ av läge", "aktualny tryb pracy", "modusrype", "type mode", "mod tipi", "tipo di modalita", "typ režimu") MAKE_TRANSLATION(fastheatup, "fastheatup", "fast heatup", "schnelles Aufheizen", "Snel opwarmen", "Snabb Uppvärmning", "szybkie nagrzewanie", "rask oppvarming", "chauffage rapide", "hızlı ısıtma", "riscaldamento rapido", "rýchle zahriatie") MAKE_TRANSLATION(heatup, "heatup", "heatup", "Aufheizen", "opwarmen", "Uppvärmning", "nagrzewanie", "oppvarming", "chauffage", "hızlı", "riscaldamento", "rýchle zahriatie") @@ -747,6 +747,7 @@ MAKE_TRANSLATION(switchProgMode, "switchprogmode", "switch program mode", "Schal MAKE_TRANSLATION(airHumidity, "airhumidity", "relative air humidity", "relative Luftfeuchte", "Relatieve luchtvochtigheid", "Relativ Luftfuktighet", "wilgotność względna w pomieszczeniu", "luftfuktighet", "humidité relative air", "havadaki bağıl nem", "umidità relativa aria", "relatívna vlhkosť vzduchu") MAKE_TRANSLATION(dewTemperature, "dewtemperature", "dew point temperature", "Taupunkttemperatur", "Dauwpunttemperatuur", "Daggpunkt", "punkt rosy w pomieszczeniu", "duggtemperatur", "température point rosée", "çiğ noktası sıcaklığı", "temperatura del punto di rugiada", "teplota rosného bodu") MAKE_TRANSLATION(battery, "battery", "battery", "Batterie", "", "", "bateria", "", "", "", "", "batéria") // TODO translate + // mixer MAKE_TRANSLATION(flowSetTemp, "flowsettemp", "setpoint flow temperature", "Sollwert Vorlauftemperatur", "Streefwaarde aanvoertemperatuur", "Vald flödestemperatur", "zadana temperatura zasilania", "valgt turtemperatur", "consigne température flux", "akış sıcaklığı ayarı", "Setpoint temperatura di mandata", "požadovaná hodnota výstupnej teploty") MAKE_TRANSLATION(flowTempHc, "flowtemphc", "flow temperature (TC1)", "Vorlauftemperatur HK (TC1)", "Aanvoertemperatuut circuit (TC1)", "Flödestemperatur (TC1)", "temperatura zasilania (TC1)", "turtemperatur (TC1)", "température flux (TC1)", "akış sıcaklığı (TC1)", "temperatura di mandata (TC1)", "teplota prívodu (TC1)") @@ -754,6 +755,7 @@ MAKE_TRANSLATION(pumpStatus, "pumpstatus", "pump status (PC1)", "Pumpenstatus HK MAKE_TRANSLATION(mixerStatus, "valvestatus", "mixing valve actuator (VC1)", "Mischerventilposition (VC1)", "positie mixerklep (VC1)", "Shuntventil Status (VC1)", "siłownik zaworu mieszającego (VC1)", "shuntventil status (VC1)", "actionnement vanne mélangeur (VC1)", "karışım vanası aktüatörü (VC1)", "posizione valvola miscela (VC1)", "pohon zmiešavacieho ventilu (VC1)") MAKE_TRANSLATION(flowTempVf, "flowtempvf", "flow temperature in header (T0/Vf)", "Vorlauftemperatur am Verteiler (T0/Vf)", "aanvoertemperatuur verdeler (T0/Vf)", "Flödestemperatur Fördelare (T0/Vf)", "temperatura zasilania na rozdzielaczu (T0/Vf)", "turtemperatur ved fordeleren (T0/Vf)", "température départ collecteur (T0/Vf)", "başlıkta akış sıcaklığı", "Temperatura di mandata al distributore (T0/Vf)", "teplota prívodu v zberači (T0/Vf)") MAKE_TRANSLATION(mixerSetTime, "valvesettime", "time to set valve", "Zeit zum einstellen des Ventils", "Inschakeltijd mengklep", "Inställningstid Ventil", "czas na ustawienie zaworu", "instillningstid ventil", "délai activation vanne", "vana ayar zamanı", "ritardo attivazione valvola", "čas na nastavenie ventilu") + // mixer pool MAKE_TRANSLATION(poolSetTemp, "poolsettemp", "pool set temperature", "Sollwert Pooltemperatur", "Streeftemperatuur zwembad", "Pool Temperatur Börvärde", "zadana temperatura basenu", "valgt temp basseng", "température consigne piscine", "hedef havuz sıcaklığı", "temperatura nominale piscina", "nastavená teplota bazéna") MAKE_TRANSLATION(poolTemp, "pooltemp", "pool temperature", "Pooltemperatur", "Zwembadtemperatuur", "Pooltemperatur", "temperatura basenu", "bassengtemperatur", "température piscine", "havuz sıcaklığı", "temperatura piscina", "teplota bazéna") @@ -809,6 +811,7 @@ MAKE_TRANSLATION(wwPump, "pump", "pump", "Pumpe", "Pomp", "Pump", "pompa", "pump MAKE_TRANSLATION(wwCircTc, "circtc", "circulation time controled", "zeitgesteuerte Zirkulation", "", "", "", "", "", "", "", "riadená doba cirkulácie") // TODO translate MAKE_TRANSLATION(errorDisp, "errordisp", "error display", "Fehleranzeige", "", "", "wyświetlanie błędów", "", "", "", "", "zobrazenie chyby") // TODO translate MAKE_TRANSLATION(deltaTRet, "deltatret", "temp. diff. return valve", "Temperaturdifferenz Rücklaufventil", "", "", "różnica temp. zaworu powrotnego", "", "", "", "", "rozdiel teplôt spätného ventilu") // TODO translate + // solar dhw and mixer dhw MAKE_TRANSLATION(wwMinTemp, "mintemp", "minimum temperature", "minimale Temperatur", "Minimale temperatuur", "Min. Temperatur", "temperatura minimalna", "min. temperatur", "température min.", "minimum sıcaklık", "temperatura minima", "minimálna teplota") MAKE_TRANSLATION(wwRedTemp, "redtemp", "reduced temperature", "reduzierte Temperatur", "Gereduceerde temperatuur", "Reducerad Temperatur", "temperatura zredukowana", "reducert temperatur", "température réduite", "düşürülmüş sıcaklık", "temperatura ridotta", "znížená teplota") @@ -819,6 +822,7 @@ MAKE_TRANSLATION(wwStatus2, "status2", "status 2", "Status 2", "Status 2", "Stat MAKE_TRANSLATION(wwPumpMod, "pumpmod", "pump modulation", "Pumpenmodulation", "Pompmodulatie", "Pumpmodulering", "modulacja pompy", "pumpemodulering", "modulation de pompe", "pompa modülasyonu", "modulazione pompa", "modulácia čerpadla") MAKE_TRANSLATION(wwFlow, "flow", "flow rate", "Volumenstrom", "Doorstroomsnelheid", "Flöde", "przepływ", "strømningshastighet", "débit", "akış hızı", "portata flusso", "prietok") // MAKE_TRANSLATION(wwRetValve, "retvalve", "return valve", "Rücklauf Ventil", "", "", "", "", "", "", "", "") + // extra mixer dhw MAKE_TRANSLATION(wwRequiredTemp, "requiredtemp", "required temperature", "benötigte Temperatur", "Benodigde temperatuur", "Nödvändig Temperatur", "temperatura wymagana", "nødvendig temperatur", "température requise", "gerekli sıcaklık", "temperatura richiesta", "požadovaná teplota") MAKE_TRANSLATION(wwDiffTemp, "difftemp", "start differential temperature", "Start Differenztemperatur", "Start differentiele temperatuur", "Start Differentialtemperatur", "start temperatury różnicowej", "start differensialtemperatur", "température différentielle de départ", "diferansiyel sıcaklık", "avvia temperatura differenziale", "začiatok diferenciálnej teploty") @@ -898,4 +902,4 @@ MAKE_TRANSLATION(setting3, "setting3", "unknown setting 3", "", "", "", "nieznan MAKE_TRANSLATION(setting4, "setting4", "unknown setting 4", "", "", "", "nieznane ustawienie 4", "", "", "", "", "neznáme dátové pole 4") */ -// clang-format on +// clang-format on \ No newline at end of file From 4881e95d28455d3ca6ba86cd05a767c1d7b60523 Mon Sep 17 00:00:00 2001 From: mattreim <80219712+mattreim@users.noreply.github.com> Date: Sat, 14 Sep 2024 14:27:06 +0200 Subject: [PATCH 08/17] Add "Betriebsart" --- src/locale_translations.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locale_translations.h b/src/locale_translations.h index 0e3b893ba..6a7e77764 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -667,7 +667,7 @@ MAKE_TRANSLATION(wwDailyHeatTime, "dailyheattime", "daily heating time", "tägli // thermostat hc MAKE_TRANSLATION(selRoomTemp, "seltemp", "selected room temperature", "gewählte Raumtemperatur", "Streeftemperatuur kamer", "Vald Rumstemperatur", "zadana temperatura w pomieszczeniu", "valgt rumstemperatur", "température ambiante sélectionnée", "seçili oda sıcaklığı", "temperatura ambiente selezionata", "zvolená izbová teplota") MAKE_TRANSLATION(roomTemp, "currtemp", "current room temperature", "aktuelle Raumtemperatur", "Huidige kamertemperatuur", "Aktuell Rumstemperatur", "temperatura w pomieszczeniu", "gjeldende romstemperatur", "température ambiante actuelle", "güncel oda sıcaklığı", "temperatura ambiente attuale", "aktuálna izbová teplota") -MAKE_TRANSLATION(mode, "mode", "operating mode", "Betriebsmodus", "Modus", "Läge", "sposób sterowania", "modus", "mode", "mod", "modalità", "režim") +MAKE_TRANSLATION(mode, "mode", "operating mode", "Betriebsart", "Modus", "Läge", "sposób sterowania", "modus", "mode", "mod", "modalità", "režim") MAKE_TRANSLATION(modetype, "modetype", "mode type", "Modustyp", "Type modus", "Typ av läge", "aktualny tryb pracy", "modusrype", "type mode", "mod tipi", "tipo di modalita", "typ režimu") MAKE_TRANSLATION(fastheatup, "fastheatup", "fast heatup", "schnelles Aufheizen", "Snel opwarmen", "Snabb Uppvärmning", "szybkie nagrzewanie", "rask oppvarming", "chauffage rapide", "hızlı ısıtma", "riscaldamento rapido", "rýchle zahriatie") MAKE_TRANSLATION(heatup, "heatup", "heatup", "Aufheizen", "opwarmen", "Uppvärmning", "nagrzewanie", "oppvarming", "chauffage", "hızlı", "riscaldamento", "rýchle zahriatie") From 35ffd9b2dcabc7d9dd2fb81d73f7d1fce498d278 Mon Sep 17 00:00:00 2001 From: mattreim <80219712+mattreim@users.noreply.github.com> Date: Sat, 14 Sep 2024 15:54:58 +0200 Subject: [PATCH 09/17] Update locale_translations.h --- src/locale_translations.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locale_translations.h b/src/locale_translations.h index 6a7e77764..7d9f9d0e5 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -329,7 +329,7 @@ MAKE_TRANSLATION(flameCurr, "flamecurr", "flame current", "Flammenstrom", "Vlamm MAKE_TRANSLATION(heatingPump, "heatingpump", "heating pump", "Heizungspumpe", "Verwarmingspomp", "Värmepump", "pompa ciepła", "varmepumpe", "pompe à chaleur", "ısı pompası", "pompa di calore", "tepelné čerpadlo") MAKE_TRANSLATION(fanWork, "fanwork", "fan", "Gebläse", "Ventilator", "Fläkt", "wentylator", "vifte", "ventilateur", "fan", "Ventilatore", "ventilátor") MAKE_TRANSLATION(ignWork, "ignwork", "ignition", "Zündung", "Ontsteking", "Tändning", "zapłon", "tenning", "ignition", "ateşleme", "accensione", "zapálenie") -MAKE_TRANSLATION(heatingActivated, "heatingactivated", "heating activated", "Heizen aktiviert", "Verwarmen geactiveerd", "Uppvärmning aktiv", "system c.o.", "oppvarming aktivert", "chauffage activé", "ısıtma başladı", "riscaldamento attivato", "kúrenie aktivované") +MAKE_TRANSLATION(heatingActivated, "heatingactivated", "heating activated", "Heizbetrieb aktiviert", "Verwarmen geactiveerd", "Uppvärmning aktiv", "system c.o.", "oppvarming aktivert", "chauffage activé", "ısıtma başladı", "riscaldamento attivato", "kúrenie aktivované") MAKE_TRANSLATION(heatingTemp, "heatingtemp", "heating temperature", "Heizungstemperatur", "Verwarmingstemperatuur", "Uppvärmningstemperatur", "temperatura grzania", "oppvarmingstemperatur", "température de chauffage", "ısıtma sıcaklığı", "temperatura riscaldamento", "teplota vykurovania") MAKE_TRANSLATION(pumpModMax, "pumpmodmax", "boiler pump max power", "Maximale Kesselpumpenleistung", "Ketelpomp max vermogen", "Värmepannepump max effekt", "maksymalna moc pompy zasobnika", "varmepumpe maks effekt", "puissance max pompe à chaleur", "boyler pompası maksimum güç", "max potenza pompa caldaia", "maximálny výkon čerpadla kotla") MAKE_TRANSLATION(pumpModMin, "pumpmodmin", "boiler pump min power", "Minimale Kesselpumpenleistung", "Ketelpomp min vermogen", "Värmepannepump min effekt", "minimalna moc pompy zasobnika", "varmepumpe min effekt", "puissance min pompe à chaleur", "boyler pompası minimum güç", "min potenza pompa caldaia", "min. výkon čerpadla kotla") @@ -651,7 +651,7 @@ MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Kühlabsenkung mit PV", "Verlagen koeling met PV activeren", "", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV") // TODO translate // thermostat dhw -MAKE_TRANSLATION(wwMode, "mode", "mode", "Modus", "Modus", "Läge", "tryb pracy", "modus", "mode", "mod", "modalità", "režim") +MAKE_TRANSLATION(wwMode, "mode", "operating mode", "Betriebsart", "Modus", "Läge", "tryb pracy", "modus", "mode", "mod", "modalità", "režim") MAKE_TRANSLATION(wwSetTempLow, "settemplow", "set low temperature", "untere Solltemperatur", "Onderste streeftemperatuur", "Nedre Börvärde", "zadana temperatura obniżona", "nedre settverdi", "réglage température basse", "hedef düşük sıcaklık", "imposta bassa temperatura", "nastaviť nízku teplotu") MAKE_TRANSLATION(wwWhenModeOff, "whenmodeoff", "when thermostat mode off", "bei Thermostatmodus AUS", "Als Thermostaat op UIT", "när Termostatläge är AV", "gdy wyłączono na termostacie", "når modus er av", "lorsque mode thermostat off", "termostat modu kapalı olduğunda", "quando termostato modalita OFF", "keď je režim termostatu vypnutý") MAKE_TRANSLATION(wwExtra, "extra", "extra", "Extra", "extra", "Extra", "obieg", "ekstra", "extra", "ekstra", "extra", "extra") From 65b90b595bdc817df9aec9c31700dbe12b23058c Mon Sep 17 00:00:00 2001 From: mattreim <80219712+mattreim@users.noreply.github.com> Date: Sat, 14 Sep 2024 23:50:56 +0200 Subject: [PATCH 10/17] Update locale_translations.h --- src/locale_translations.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/locale_translations.h b/src/locale_translations.h index 7d9f9d0e5..471947ab7 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -646,8 +646,8 @@ MAKE_TRANSLATION(autodst, "autodst", "automatic change daylight saving time", "A MAKE_TRANSLATION(preheating, "preheating", "preheating in the clock program", "Vorheizen im Zeitprogramm", "Voorverwarming in het klokprogramma", "Förvärmning i tidsprogram", "podgrzewanie w programie czasowym", "forvarming i tidsprogram", "préchauffage dans programme horloge", "saat programında ön ısıtma", "preriscaldamento nel programma orologio", "predohrev v programe hodín") MAKE_TRANSLATION(offtemp, "offtemp", "temperature when mode is off", "Temperatur bei AUS", "Temperatuur bij UIT", "Temperatur Avslagen", "temperatura w trybie \"wył.\"", "temperatur avslått", "température lorsque mode désactivé", "mod kapalı iken sıcaklık", "temperatura quando la modalità è disattivata", "teplota, keď je režim vypnutý") MAKE_TRANSLATION(mixingvalves, "mixingvalves", "mixing valves", "Mischventile", "Mengkleppen", "Blandningsventiler", "zawory mieszające", "blandeventiler", "vannes mélange", "karışım vanaları", "valvole miscela", "zmiešavacie ventily") -MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere Anhebung WW", "Verhoging WW activeren", "", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV") // TODO translate -MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung Heizen mit PV", "Verwarmen met PV activeren", "", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV") // TODO translate +MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere WW-Anhebung", "Verhoging WW activeren", "", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV") // TODO translate +MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Heizanhebung mit PV", "Verwarmen met PV activeren", "", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV") // TODO translate MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Kühlabsenkung mit PV", "Verlagen koeling met PV activeren", "", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV") // TODO translate // thermostat dhw From 1bb33fbd3c99a69eb7be1677af2027190b55df3d Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:32:28 +0200 Subject: [PATCH 11/17] package update --- interface/package.json | 10 ++++----- interface/yarn.lock | 48 ++++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/interface/package.json b/interface/package.json index 18e2225dd..b8baf3b6d 100644 --- a/interface/package.json +++ b/interface/package.json @@ -31,7 +31,7 @@ "async-validator": "^4.2.5", "jwt-decode": "^4.0.0", "mime-types": "^2.1.35", - "preact": "^10.23.2", + "preact": "^10.24.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-icons": "^5.3.0", @@ -44,10 +44,10 @@ "@babel/core": "^7.25.2", "@eslint/js": "^9.10.0", "@preact/compat": "^18.3.1", - "@preact/preset-vite": "^2.9.0", + "@preact/preset-vite": "^2.9.1", "@trivago/prettier-plugin-sort-imports": "^4.3.0", "@types/formidable": "^3", - "@types/node": "^22.5.4", + "@types/node": "^22.5.5", "@types/react": "^18.3.5", "@types/react-dom": "^18.3.0", "@types/react-router-dom": "^5.3.3", @@ -59,9 +59,9 @@ "rollup-plugin-visualizer": "^5.12.0", "terser": "^5.32.0", "typescript-eslint": "8.5.0", - "vite": "^5.4.4", + "vite": "^5.4.5", "vite-plugin-imagemin": "^0.6.1", "vite-tsconfig-paths": "^5.0.1" }, - "packageManager": "yarn@4.4.1" + "packageManager": "yarn@4.5.0" } diff --git a/interface/yarn.lock b/interface/yarn.lock index 7400933e9..f63b1f6ef 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -1054,9 +1054,9 @@ __metadata: languageName: node linkType: hard -"@preact/preset-vite@npm:^2.9.0": - version: 2.9.0 - resolution: "@preact/preset-vite@npm:2.9.0" +"@preact/preset-vite@npm:^2.9.1": + version: 2.9.1 + resolution: "@preact/preset-vite@npm:2.9.1" dependencies: "@babel/code-frame": "npm:^7.22.13" "@babel/plugin-transform-react-jsx": "npm:^7.22.15" @@ -1068,13 +1068,12 @@ __metadata: kolorist: "npm:^1.8.0" magic-string: "npm:0.30.5" node-html-parser: "npm:^6.1.10" - resolve: "npm:^1.22.8" source-map: "npm:^0.7.4" stack-trace: "npm:^1.0.0-pre2" peerDependencies: "@babel/core": 7.x vite: 2.x || 3.x || 4.x || 5.x - checksum: 10c0/658e3dc048d1f1d8ad7cb1fef4a3db0f933be4e00d3d6cdfbd29fe7ec02341b3a26747520a5b261992923b3d3f49800c23a4d77da849e708a5c1ad9a920343b2 + checksum: 10c0/6c2f2a7f06b08b2bd817d493101c4654891d6b86f661d48e2fb0b1388289bc4cb40b11a9ab30f9a12f818a28a1b48d60d97b24b8d3376c317a9d8abe06a68b1e languageName: node linkType: hard @@ -1417,7 +1416,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^22.5.4": +"@types/node@npm:*": version: 22.5.4 resolution: "@types/node@npm:22.5.4" dependencies: @@ -1426,6 +1425,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^22.5.5": + version: 22.5.5 + resolution: "@types/node@npm:22.5.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10c0/ead9495cfc6b1da5e7025856dcce2591e9bae635357410c0d2dd619fce797d2a1d402887580ca4b336cb78168b195224869967de370a23f61663cf1e4836121c + languageName: node + linkType: hard + "@types/parse-json@npm:^4.0.0": version: 4.0.2 resolution: "@types/parse-json@npm:4.0.2" @@ -1635,11 +1643,11 @@ __metadata: "@mui/icons-material": "npm:^6.1.0" "@mui/material": "npm:^6.1.0" "@preact/compat": "npm:^18.3.1" - "@preact/preset-vite": "npm:^2.9.0" + "@preact/preset-vite": "npm:^2.9.1" "@table-library/react-table-library": "npm:4.1.7" "@trivago/prettier-plugin-sort-imports": "npm:^4.3.0" "@types/formidable": "npm:^3" - "@types/node": "npm:^22.5.4" + "@types/node": "npm:^22.5.5" "@types/react": "npm:^18.3.5" "@types/react-dom": "npm:^18.3.0" "@types/react-router-dom": "npm:^5.3.3" @@ -1651,7 +1659,7 @@ __metadata: formidable: "npm:^3.5.1" jwt-decode: "npm:^4.0.0" mime-types: "npm:^2.1.35" - preact: "npm:^10.23.2" + preact: "npm:^10.24.0" prettier: "npm:^3.3.3" react: "npm:^18.3.1" react-dom: "npm:^18.3.1" @@ -1663,7 +1671,7 @@ __metadata: typesafe-i18n: "npm:^5.26.2" typescript: "npm:^5.6.2" typescript-eslint: "npm:8.5.0" - vite: "npm:^5.4.4" + vite: "npm:^5.4.5" vite-plugin-imagemin: "npm:^0.6.1" vite-tsconfig-paths: "npm:^5.0.1" languageName: unknown @@ -5568,10 +5576,10 @@ __metadata: languageName: node linkType: hard -"preact@npm:^10.23.2": - version: 10.23.2 - resolution: "preact@npm:10.23.2" - checksum: 10c0/6e0dc1b38ead7554c99ddec9a32162b456e8f622229413b136042a777445a12d115633cd49d6df83c30b64d721a0ad4d3c71bb468edc759c15799896e96fd9f2 +"preact@npm:^10.24.0": + version: 10.24.0 + resolution: "preact@npm:10.24.0" + checksum: 10c0/09d490d2326c511e205a96f81db0adf05f1b42dbe2a39be6fc494662c7476575494e96140252f351a0e3b3d15aee5b079bf963865bb01287f69c45c6755ed22e languageName: node linkType: hard @@ -5897,7 +5905,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.19.0, resolve@npm:^1.22.8": +"resolve@npm:^1.10.0, resolve@npm:^1.19.0": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -5910,7 +5918,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": +"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -6960,9 +6968,9 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.4.4": - version: 5.4.4 - resolution: "vite@npm:5.4.4" +"vite@npm:^5.4.5": + version: 5.4.5 + resolution: "vite@npm:5.4.5" dependencies: esbuild: "npm:^0.21.3" fsevents: "npm:~2.3.3" @@ -6999,7 +7007,7 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 10c0/2752e7dd5584ea7cc057742e8f5cbf2f2bd3a2bceb8794fbd3d52f1e88d362b5ac7f1c70be7a3d01b3d768320c8a8ad0df287fd72f253bf040423c36c67a3e89 + checksum: 10c0/89c6459452fc238cdf8e99681b30996af171c9c557af476f96408a18a639fb5a0a6ee2d2257e005b21dc284edceb604595c34920cd4a007ad18f7ebafb654c76 languageName: node linkType: hard From 9a20bf350ae0663baf3f733b364680e1921b7f04 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:32:35 +0200 Subject: [PATCH 12/17] more checks --- scripts/upload.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/scripts/upload.py b/scripts/upload.py index 3becb20f4..69d27d7f3 100644 --- a/scripts/upload.py +++ b/scripts/upload.py @@ -34,17 +34,24 @@ from termcolor import cprint def print_success(x): return cprint(x, 'green') -def print_fail(x): return cprint(x, 'red') +def print_fail(x): return cprint('Error: '+x, 'red') def on_upload(source, target, env): + # make sure we have set the upload_protocol to custom + if env.get('UPLOAD_PROTOCOL') != 'custom': + print_fail("Please set upload_protocol = custom in your pio_local.ini file when using upload.py") + return + # first check authentication try: username = env.GetProjectOption('custom_username') password = env.GetProjectOption('custom_password') + emsesp_ip = env.GetProjectOption('custom_emsesp_ip') except: - print('No authentication settings specified. Please, add these to your pio_local.ini file: \n\ncustom_username=username\ncustom_password=password\n') + print_fail('Missing settings. Add these to your pio_local.ini file: \n\ncustom_username=username\ncustom_password=password\ncustom_emsesp_ip=ems-esp.local\n') return + emsesp_url = "http://" + env.GetProjectOption('custom_emsesp_ip') parsed_url = urlparse(emsesp_url) @@ -71,10 +78,10 @@ def on_upload(source, target, env): response = requests.post(signon_url, json=username_password, headers=signon_headers) if response.status_code != 200: - print_fail("Authentication failed (code " + str(response.status_code) + ")") + print_fail("Authentication with EMS-ESP failed (code " + str(response.status_code) + ")") return - print_success("Authentication successful") + print_success("Authentication with EMS-ESP successful") access_token = response.json().get('access_token') # start the upload From e54d9a6c32f5d7b143b60fe70fa35ce4f26aca3c Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:33:27 +0200 Subject: [PATCH 13/17] minor std::string optimizations --- src/emsdevice.cpp | 4 ++-- src/emsdevicevalue.cpp | 2 +- src/emsdevicevalue.h | 2 +- src/system.h | 2 +- src/web/WebCustomizationService.cpp | 4 ++-- src/web/WebStatusService.cpp | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index cc674b7b8..fdfef14ac 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -578,7 +578,7 @@ void EMSdevice::add_device_value(int8_t tag, // to b snprintf(entity, sizeof(entity), "%s/%s", tag_to_mqtt(tag), short_name); } - for (std::string entity_id : entityCustomization.entity_ids) { + for (const std::string & entity_id : entityCustomization.entity_ids) { // if there is an appended custom name, strip it to get the true entity name // and extract the new custom name auto custom_name_pos = entity_id.find('|'); @@ -1112,7 +1112,7 @@ void EMSdevice::generate_values_web_customization(JsonArray output) { EMSESP::webCustomizationService.read([&](WebCustomization & settings) { for (EntityCustomization entityCustomization : settings.entityCustomizations) { if (entityCustomization.device_id == device_id()) { - for (std::string entity_id : entityCustomization.entity_ids) { + for (const std::string & entity_id : entityCustomization.entity_ids) { uint8_t mask = Helpers::hextoint(entity_id.substr(0, 2).c_str()); if (mask & 0x80) { JsonObject obj = output.add(); diff --git a/src/emsdevicevalue.cpp b/src/emsdevicevalue.cpp index 97bff85f7..e3cd76cec 100644 --- a/src/emsdevicevalue.cpp +++ b/src/emsdevicevalue.cpp @@ -369,7 +369,7 @@ std::string DeviceValue::get_fullname() const { return customname; } -std::string DeviceValue::get_name(std::string & entity) { +std::string DeviceValue::get_name(const std::string & entity) { auto pos = entity.find('|'); if (pos != std::string::npos) { return entity.substr(2, pos - 2); diff --git a/src/emsdevicevalue.h b/src/emsdevicevalue.h index 0a8ee1587..b877070b8 100644 --- a/src/emsdevicevalue.h +++ b/src/emsdevicevalue.h @@ -188,7 +188,7 @@ class DeviceValue { bool get_custom_max(uint32_t & val); std::string get_custom_fullname() const; std::string get_fullname() const; - static std::string get_name(std::string & entity); + static std::string get_name(const std::string & entity); // dv state flags void add_state(uint8_t s) { diff --git a/src/system.h b/src/system.h index 23b223acf..2e980a22b 100644 --- a/src/system.h +++ b/src/system.h @@ -201,7 +201,7 @@ class System { return hostname_; } - void hostname(std::string hostname) { + void hostname(const std::string hostname) { hostname_ = hostname; } diff --git a/src/web/WebCustomizationService.cpp b/src/web/WebCustomizationService.cpp index c461b367c..8e77de4fc 100644 --- a/src/web/WebCustomizationService.cpp +++ b/src/web/WebCustomizationService.cpp @@ -75,7 +75,7 @@ void WebCustomization::read(WebCustomization & customizations, JsonObject root) // entries are in the form [optional customname] e.g "08heatingactive|heating is on" JsonArray masked_entityJson = entityJson["entity_ids"].to(); - for (std::string entity_id : entityCustomization.entity_ids) { + for (const std::string & entity_id : entityCustomization.entity_ids) { masked_entityJson.add(entity_id); } } @@ -277,7 +277,7 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req read([&](WebCustomization & settings) { for (EntityCustomization entityCustomization : settings.entityCustomizations) { if (entityCustomization.device_id == device_id) { - for (std::string entity_id : entityCustomization.entity_ids) { + for (const std::string & entity_id : entityCustomization.entity_ids) { uint8_t mask = Helpers::hextoint(entity_id.substr(0, 2).c_str()); std::string name = DeviceValue::get_name(entity_id); if (mask & 0x80) { diff --git a/src/web/WebStatusService.cpp b/src/web/WebStatusService.cpp index 00fd35aa5..96777a91e 100644 --- a/src/web/WebStatusService.cpp +++ b/src/web/WebStatusService.cpp @@ -152,7 +152,7 @@ void WebStatusService::checkUpgrade(AsyncWebServerRequest * request, JsonVariant JsonObject root = response->getRoot(); version::Semver200_version settings_version(EMSESP_APP_VERSION); - std::string latest_version = json["version"] | EMSESP_APP_VERSION; + const std::string latest_version = json["version"] | EMSESP_APP_VERSION; version::Semver200_version this_version(latest_version); #ifdef EMSESP_DEBUG @@ -170,7 +170,8 @@ void WebStatusService::exportData(AsyncWebServerRequest * request) { auto * response = new AsyncJsonResponse(); JsonObject root = response->getRoot(); - String type = request->getParam("type")->value(); + String type = request->getParam("type")->value(); + root["type"] = type; if (type == "settings") { JsonObject node = root["System"].to(); @@ -192,7 +193,6 @@ void WebStatusService::exportData(AsyncWebServerRequest * request) { return; } - root["type"] = type; response->setLength(); request->send(response); } From d10e27c7c302bda3c8cd327d9607c7a3cf5219e4 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:33:42 +0200 Subject: [PATCH 14/17] remove obsolete last_transmit --- src/web/WebLogService.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/web/WebLogService.h b/src/web/WebLogService.h index a222f6d88..55886c324 100644 --- a/src/web/WebLogService.h +++ b/src/web/WebLogService.h @@ -65,7 +65,6 @@ class WebLogService : public uuid::log::Handler { char * messagetime(char * out, const uint64_t t, const size_t bufsize); - uint64_t last_transmit_ = 0; // Last transmit time size_t maximum_log_messages_ = MAX_LOG_MESSAGES; // Maximum number of log messages to buffer before they are output size_t limit_log_messages_ = 1; // dynamic limit unsigned long log_message_id_ = 0; // The next identifier to use for queued log messages From 9234bfd34cf8168f6ebdf000c598bb48dd9b9ce3 Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:33:51 +0200 Subject: [PATCH 15/17] add show command --- src/console.cpp | 66 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/console.cpp b/src/console.cpp index cd3dccbbd..786ac9f8e 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -76,6 +76,9 @@ static void setup_commands(std::shared_ptr & commands) { // // Show commands // + commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(show)}, [=](Shell & shell, const std::vector & arguments) { + to_app(shell).system_.show_system(shell); + }); commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(show), F_(system)}, @@ -125,7 +128,7 @@ static void setup_commands(std::shared_ptr & commands) { // create commands test commands->add_command(ShellContext::MAIN, CommandFlags::USER, - string_vector{"test"}, + {"test"}, string_vector{F_(name_optional), F_(data_optional), F_(id_optional)}, [=](Shell & shell, const std::vector & arguments) { if (arguments.empty()) { @@ -138,12 +141,12 @@ static void setup_commands(std::shared_ptr & commands) { Test::run_test(shell, arguments[0].c_str(), arguments[1].c_str(), arguments[2].c_str()); } }); - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{"t"}, [=](Shell & shell, const std::vector & arguments) { + commands->add_command(ShellContext::MAIN, CommandFlags::USER, {"t"}, [=](Shell & shell, const std::vector & arguments) { Test::run_test(shell, "default"); }); #endif - commands->add_command(ShellContext::MAIN, CommandFlags::USER, string_vector{F_(su)}, [=](Shell & shell, const std::vector & arguments) { + commands->add_command(ShellContext::MAIN, CommandFlags::USER, {F_(su)}, [=](Shell & shell, const std::vector & arguments) { auto become_admin = [](Shell & shell) { shell.logger().log(LogLevel::NOTICE, LogFacility::AUTH, F("Admin session opened on console %s"), to_shell(shell).console_name().c_str()); shell.add_flags(CommandFlags::ADMIN); @@ -176,7 +179,7 @@ static void setup_commands(std::shared_ptr & commands) { } }); - commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(passwd)}, [](Shell & shell, const std::vector & arguments) { + commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, {F_(passwd)}, [](Shell & shell, const std::vector & arguments) { shell.enter_password(F_(new_password_prompt1), [](Shell & shell, bool completed, const std::string & password1) { if (completed) { shell.enter_password(F_(new_password_prompt2), [password1](Shell & shell, bool completed, const std::string & password2) { @@ -198,8 +201,8 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, - string_vector{F_(restart)}, - string_vector{F_(partitionname_optional)}, + {F_(restart)}, + {F_(partitionname_optional)}, [](Shell & shell, const std::vector & arguments) { if (arguments.size()) { to_app(shell).system_.system_restart(arguments.front().c_str()); @@ -244,7 +247,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(hostname)}, - string_vector{F_(name_mandatory)}, + {F_(name_mandatory)}, [](Shell & shell, const std::vector & arguments) { shell.println("The network connection will be reset..."); Shell::loop_all(); @@ -258,7 +261,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(wifi), F_(ssid)}, - string_vector{F_(name_mandatory)}, + {F_(name_mandatory)}, [](Shell & shell, const std::vector & arguments) { to_app(shell).esp8266React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) { networkSettings.ssid = arguments.front().c_str(); @@ -273,7 +276,7 @@ static void setup_commands(std::shared_ptr & commands) { ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(board_profile)}, - string_vector{F_(name_mandatory)}, + {F_(name_mandatory)}, [](Shell & shell, const std::vector & arguments) { std::vector data; // led, dallas, rx, tx, button, phy_type, eth_power, eth_phy_addr, eth_clock_mode std::string board_profile = Helpers::toUpper(arguments.front()); @@ -303,7 +306,7 @@ static void setup_commands(std::shared_ptr & commands) { ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(bus_id)}, - string_vector{F_(deviceid_mandatory)}, + {F_(deviceid_mandatory)}, [](Shell & shell, const std::vector & arguments) { uint8_t device_id = Helpers::hextoint(arguments.front().c_str()); if ((device_id == 0x0B) || (device_id == 0x0D) || (device_id == 0x0A) || (device_id == 0x0F) || (device_id == 0x12)) { @@ -323,7 +326,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, string_vector{F_(set), F_(tx_mode)}, - string_vector{F_(n_mandatory)}, + {F_(n_mandatory)}, [](Shell & shell, const std::vector & arguments) { uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10); // save the tx_mode @@ -371,30 +374,25 @@ static void setup_commands(std::shared_ptr & commands) { // EMS device commands // - commands->add_command(ShellContext::MAIN, - CommandFlags::ADMIN, - string_vector{F_(scan)}, - string_vector{F_(deep_optional)}, - [](Shell & shell, const std::vector & arguments) { - if (arguments.size() == 0) { - to_app(shell).scan_devices(); - } else { - shell.printfln("Performing a deep scan..."); - to_app(shell).clear_all_devices(); - // device IDs taken from device_library.h - // send the read command with Version command - const std::vector Device_Ids = {0x02, 0x08, 0x09, 0x10, 0x11, 0x12, 0x15, 0x17, 0x18, 0x19, 0x1A, - 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, - 0x2A, 0x30, 0x38, 0x40, 0x41, 0x48, 0x50, 0x51, 0x60}; - for (const uint8_t device_id : Device_Ids) { - to_app(shell).send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id); - } - } - }); + commands->add_command(ShellContext::MAIN, CommandFlags::ADMIN, {F_(scan)}, {F_(deep_optional)}, [](Shell & shell, const std::vector & arguments) { + if (arguments.size() == 0) { + to_app(shell).scan_devices(); + } else { + shell.printfln("Performing a deep scan..."); + to_app(shell).clear_all_devices(); + // device IDs taken from device_library.h + // send the read command with Version command + const std::vector Device_Ids = {0x02, 0x08, 0x09, 0x10, 0x11, 0x12, 0x15, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x30, 0x38, 0x40, 0x41, 0x48, 0x50, 0x51, 0x60}; + for (const uint8_t device_id : Device_Ids) { + to_app(shell).send_read_request(EMSdevice::EMS_TYPE_VERSION, device_id); + } + } + }); commands->add_command(ShellContext::MAIN, CommandFlags::USER, - string_vector{F_(read)}, + {F_(read)}, string_vector{F_(deviceid_mandatory), F_(typeid_mandatory), F_(offset_optional), F_(length_optional)}, [=](Shell & shell, const std::vector & arguments) { uint8_t device_id = Helpers::hextoint(arguments.front().c_str()); @@ -420,7 +418,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command(ShellContext::MAIN, CommandFlags::USER, - string_vector{F_(watch)}, + {F_(watch)}, string_vector{F_(watch_format_optional), F_(watchid_optional)}, [](Shell & shell, const std::vector & arguments) { uint16_t watch_id = WATCH_ID_NONE; @@ -490,7 +488,7 @@ static void setup_commands(std::shared_ptr & commands) { commands->add_command( ShellContext::MAIN, CommandFlags::ADMIN, - string_vector{F_(call)}, + {F_(call)}, string_vector{F_(device_type_optional), F_(cmd_optional), F_(data_optional), F_(id_optional)}, [&](Shell & shell, const std::vector & arguments) { if (arguments.empty()) { From 5cb4f48905dd72b8eb72f5189b969e05eb70c0ae Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 15 Sep 2024 12:34:31 +0200 Subject: [PATCH 16/17] only show running partition which is boot on 1st install and then cycle between app0/app1 --- src/emsesp.cpp | 6 ++---- src/system.cpp | 29 +++++++++++++++++------------ 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/emsesp.cpp b/src/emsesp.cpp index 96b547dba..dafce0aae 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -1579,12 +1579,10 @@ void EMSESP::start() { esp8266React.begin(); #ifndef EMSESP_STANDALONE - LOG_INFO("Booting EMS-ESP version %s from %s/%s partition", - EMSESP_APP_VERSION, - esp_ota_get_boot_partition()->label, + LOG_INFO("EMS-ESP version %s (%s partition)", EMSESP_APP_VERSION, esp_ota_get_running_partition()->label); // welcome message #else - LOG_INFO("Booting EMS-ESP version %s", EMSESP_APP_VERSION); // welcome message + LOG_INFO("EMS-ESP version %s", EMSESP_APP_VERSION); // welcome message #endif LOG_DEBUG("System is running in Debug mode"); LOG_INFO("Last system reset reason Core0: %s, Core1: %s", system_.reset_reason(0).c_str(), system_.reset_reason(1).c_str()); diff --git a/src/system.cpp b/src/system.cpp index 40a0fb50e..b051981d9 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -337,6 +337,12 @@ void System::system_restart(const char * partitionname) { Shell::loop_all(); // flush log to output delay(1000); // wait 1 second ESP.restart(); +#else + if (partitionname != nullptr) { + LOG_INFO("Restarting EMS-ESP from %s partition", partitionname); + } else { + LOG_INFO("Restarting EMS-ESP..."); + } #endif } @@ -999,7 +1005,7 @@ void System::show_system(uuid::console::Shell & shell) { #ifndef EMSESP_STANDALONE shell.printfln(" Platform: %s (%s)", EMSESP_PLATFORM, ESP.getChipModel()); shell.printfln(" Model: %s", getBBQKeesGatewayDetails().c_str()); - shell.printfln(" Partition boot/running: %s/%s", esp_ota_get_boot_partition()->label, esp_ota_get_running_partition()->label); + shell.printfln(" Partition: %s", esp_ota_get_running_partition()->label); #endif shell.printfln(" Language: %s", locale().c_str()); shell.printfln(" Board profile: %s", board_profile().c_str()); @@ -1442,17 +1448,16 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output node["uptime"] = uuid::log::format_timestamp_ms(uuid::get_uptime_ms(), 3); node["uptimeSec"] = uuid::get_uptime_sec(); #ifndef EMSESP_STANDALONE - node["platform"] = EMSESP_PLATFORM; - node["cpuType"] = ESP.getChipModel(); - node["arduino"] = ARDUINO_VERSION; - node["sdk"] = ESP.getSdkVersion(); - node["freeMem"] = getHeapMem(); - node["maxAlloc"] = getMaxAllocMem(); - node["freeCaps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram - node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes - node["freeApp"] = EMSESP::system_.appFree(); // kilobytes - node["partitionBootRunning"] = std::string(esp_ota_get_boot_partition()->label) + "/" - + esp_ota_get_running_partition()->label; // will sycle app0/app0 - app1/app1 after OTA. boot/factory is on first install. + node["platform"] = EMSESP_PLATFORM; + node["cpuType"] = ESP.getChipModel(); + node["arduino"] = ARDUINO_VERSION; + node["sdk"] = ESP.getSdkVersion(); + node["freeMem"] = getHeapMem(); + node["maxAlloc"] = getMaxAllocMem(); + node["freeCaps"] = heap_caps_get_free_size(MALLOC_CAP_8BIT) / 1024; // includes heap and psram + node["usedApp"] = EMSESP::system_.appUsed(); // kilobytes + node["freeApp"] = EMSESP::system_.appFree(); // kilobytes + node["partition"] = esp_ota_get_running_partition()->label; // active partition #endif node["resetReason"] = EMSESP::system_.reset_reason(0) + " / " + EMSESP::system_.reset_reason(1); #ifndef EMSESP_STANDALONE From a80a5093d61ad8d4fc9fbfa21a3365bc99a619cd Mon Sep 17 00:00:00 2001 From: mattreim <80219712+mattreim@users.noreply.github.com> Date: Sun, 15 Sep 2024 13:39:33 +0200 Subject: [PATCH 17/17] Update locale_translations.h --- src/locale_translations.h | 128 +++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/locale_translations.h b/src/locale_translations.h index 471947ab7..830e3410f 100644 --- a/src/locale_translations.h +++ b/src/locale_translations.h @@ -43,7 +43,7 @@ MAKE_WORD_TRANSLATION(heatpump_device, "Heat Pump", "Wärmepumpe", "Warmtepomp", MAKE_WORD_TRANSLATION(solar_device, "Solar Module", "Solarmodul", "Solar Module", "Solmodul", "Moduł solarny", "Solmodul", "", "Güneş Enerjisi Cihazı", "Modulo Solare", "Solárny modul") // TODO translate MAKE_WORD_TRANSLATION(connect_device, "Connect Module", "Verbindungsmodul", "Connect Module", "Uppkopplingsmodul", "Moduł przyłączeń", "Sammenkoblingsmodul", "", "Güneş Enerjisi Cihazı", "Modulo connessione", "Pripojte modul") // TODO translate MAKE_WORD_TRANSLATION(mixer_device, "Mixer Module", "Mischermodul", "Mixer Module", "Blandningsmodul", "Moduł mieszacza", "Miksermodul", "", "Karışım Cihazı", "Modulo Miscela", "Modul mixera") // TODO translate -MAKE_WORD_TRANSLATION(controller_device, "Controller Module", "Kontrollmodul", "Controller Module", "Styrmodul", "Moduł sterujący", "Styremodul", "", "Kontrol Ünitesi", "Modulo Controllo", "Modul ovládača") // TODO translate +MAKE_WORD_TRANSLATION(controller_device, "Controller Module", "Regelmodul", "Controller Module", "Styrmodul", "Moduł sterujący", "Styremodul", "", "Kontrol Ünitesi", "Modulo Controllo", "Modul ovládača") // TODO translate MAKE_WORD_TRANSLATION(switch_device, "Switch Module", "Schaltmodul", "Switch Module", "Relämodul", "Moduł przełączający", "Switch modul", "", "Anahtar", "Modulo Switch", "Spínací modul") // TODO translate MAKE_WORD_TRANSLATION(gateway_device, "Gateway Module", "Gateway-Modul", "Gateway Module", "Gateway", "Moduł IP", "Gateway", "", "Ağ Geçidi", "Modulo Gateway", "Modul brány") // TODO translate MAKE_WORD_TRANSLATION(alert_device, "Alert Module", "Alarmmodul", "Alert Module", "Larmmodul", "Moduł alarmowy", "Alarmmodul", "", "Alarm Cihazı", "Module Avviso", "Modul upozornení") // TODO translate @@ -54,7 +54,7 @@ MAKE_WORD_TRANSLATION(sensors_device, "Sensors", "Sensoren", "Sensoren", "Sensor MAKE_WORD_TRANSLATION(unknown_device, "Unknown", "Unbekannt", "Onbekend", "Okänt", "Nieznane urządzenie", "Ukjent", "Inconnu", "Bilinmeyen", "Sconosciuto", "Neznámy") MAKE_WORD_TRANSLATION(custom_device, "Custom", "Nutzerdefiniert", "Aangepast", "", "Niestandardowe", "", "", "Özel", "Personalizzato", "Vlastné") // TODO translate MAKE_WORD_TRANSLATION(custom_device_name, "Custom Entities", "Nutzer deklarierte Entitäten", "Gebruiker gedefineerd", "", "Encje zdefiniowane przez użytkownika", "", "", "Kullanıcı tarafından tanımlanmış varlıklar", "Entità definita da utente", "Používateľom definované entity") // TODO translate -MAKE_WORD_TRANSLATION(ventilation_device, "Ventilation", "Lüftung", "Ventilatie", "", "Wentylacja", "", "", "Havalandırma", "Ventilazione", "Vetranie") // TODO translate +MAKE_WORD_TRANSLATION(ventilation_device, "Ventilation", "Belüftung", "Ventilatie", "", "Wentylacja", "", "", "Havalandırma", "Ventilazione", "Vetranie") // TODO translate MAKE_WORD_TRANSLATION(water_device, "Water Module", "Wassermodul", "", "", "Moduł wodny", "", "", "", "", "Modul vody") // TODO translate MAKE_WORD_TRANSLATION(pool_device, "Pool Module", "Poolmodul", "", "", "Moduł basenu", "", "", "", "", "Modul bazéna") // TODO translate @@ -63,9 +63,9 @@ MAKE_WORD_TRANSLATION(info_cmd, "list all values (verbose)", "Liste aller Werte" MAKE_WORD_TRANSLATION(commands_cmd, "list all commands", "Liste aller Kommandos", "lijst van alle commando's", "", "wyświetl wszystkie komendy", "Viser alle kommandoer", "", "Tüm komutları listele", "elencaa tutti i comandi", "zobraziť všetky príkazy") // TODO translate MAKE_WORD_TRANSLATION(entities_cmd, "list all entities", "Liste aller Entitäten", "lijst van alle entiteiten", "", "wyświetl wszsytkie encje", "Viser alle enheter", "", "Tüm varlıkları listele", "elenca tutte le entità", "zobraziť všetky entity") // TODO translate MAKE_WORD_TRANSLATION(send_cmd, "send a telegram", "Sende EMS-Telegramm", "stuur een telegram", "", "wyślij telegram", "send et telegram", "", "Bir telegram gönder", "invia un telegramma", "poslať telegram") // TODO translate -MAKE_WORD_TRANSLATION(setiovalue_cmd, "set io value", "Setze Wertevorgabe", "instellen standaardwaarde", "", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io") // TODO translate +MAKE_WORD_TRANSLATION(setiovalue_cmd, "set io value", "Setze Werte E/A", "instellen standaardwaarde", "", "ustaw wartość", "sett en io verdi", "", "Giriş/Çıkış değerlerini ayarla", "imposta valore io", "nastaviť hodnotu io") // TODO translate MAKE_WORD_TRANSLATION(changeloglevel_cmd, "change log level", "Ändere Protokollebene", "aanpassen log niveau", "", "zmień poziom log-u", "endre loggnivå", "", "Kayıt seviyesini değiştir", "cambia livello registrazione", "zmeniť úroveň protokolu") // TODO translate -MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Lese alle EMS-Werte neu", "Verversen alle EMS waardes", "", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS") // TODO translate +MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Aktualisiere alle EMS-Werte", "Verversen alle EMS waardes", "", "odśwież wszystkie wartości EMS", "oppfrisk alle EMS verdier", "", "Bütün EMS değerlerini yenile", "aggiornare tutti i valori EMS", "obnoviť všetky hodnoty EMS") // TODO translate MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP") // TODO translate MAKE_WORD_TRANSLATION(format_cmd, "factory reset EMS-ESP", "EMS-ESP auf Werkseinstellungen zurücksetzen", "", "", "", "", "", "", "", "továrenske nastavenie EMS-ESP") // TODO translate MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Beobachte eingehende Telegramme", "inkomende telegrammen bekijken", "", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "", "Gelen telegramları", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy") // TODO translate @@ -74,7 +74,7 @@ MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige Systeminformat MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplanelemente", "activeer tijdschema item", "", "aktywuj wybrany harmonogram", "", "", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánovania") // TODO translate MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate -MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Schicke einen kalten Schuss Wasser", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate +MAKE_WORD_TRANSLATION(coldshot_cmd, "send a cold shot of water", "Zugabe einer Menge kalten Wassers", "", "", "uruchom tryśnięcie zimnej wody", "", "", "soğuk su gönder", "", "pošlite studenú dávku vody") // TODO translate MAKE_WORD_TRANSLATION(allvalues_cmd, "output all values in system", "Alle Werte im System ausgeben", "", "", "wyświetl wszystkie wartości", "", "", "", "", "vypísať všetky hodnoty") // TODO translate MAKE_WORD_TRANSLATION(message_cmd, "send a message", "Eine Nachricht senden", "", "", "", "", "", "", "", "poslať správu") // TODO translate MAKE_WORD_TRANSLATION(values_cmd, "list all values", "Liste alle Werte auf", "", "", "", "", "", "", "", "vypísať všetky hodnoty") // TODO translate @@ -348,7 +348,7 @@ MAKE_TRANSLATION(burnStarts, "burnstarts", "burner starts", "Brennerstarts", "Aa MAKE_TRANSLATION(burnWorkMin, "burnworkmin", "total burner operating time", "Brennerlaufzeit", "Totale branderlooptijd", "Värmepanna aktiva timmar", "łączny czas pracy palnika", "brennersteg tid i min", "durée de fonctionnement totale du brûleur", "toplam kazan çalışma süresi", "tempo totale di funzionamento del bruciatore", "celkový prevádzkový čas horáka") MAKE_TRANSLATION(burn2WorkMin, "burn2workmin", "burner stage 2 operating time", "Brennerlaufzeit Stufe 2", "Totale looptijd brander fase 2", "Värmepanna steg 2 aktiva timmar", "łączny czas pracy palnika 2 stopnia", "brennersteg2 tid i min", "durée de fonctionnement totale du brûleur état 2", "2. seviye toplam kazan çalışma süresi", "tempo di funzionamento del bruciatore 2° stadio", "doba prevádzky 2. stupňa horáka") MAKE_TRANSLATION(heatWorkMin, "heatworkmin", "total heat operating time", "Heizungslaufzeit", "Totale looptijd verwarming", "Uppvärmning aktiva timmar", "łączny czas grzania", "varmetid i min", "durée de fonctionnement du chauffage", "toplam ısıtma çalışma süresi", "tempo totale di funzionamento in riscaldamento", "celkový prevádzkový čas kúrenia") -MAKE_TRANSLATION(heatStarts, "heatstarts", "burner starts heating", "Brennerstarts: Heizung", "Aantal brander starts verwarming", "Uppvärmning antal starter", "liczba uruchomień palnika na ogrzewanie", "antall oppvarmninger", "démarrages du chauffage", "kazan ısıtmaya başlıyor", "preriscaldamento bruciatore", "štarty horáka na kúrenie") +MAKE_TRANSLATION(heatStarts, "heatstarts", "burner starts heating", "Brennerstarts Heizung", "Aantal brander starts verwarming", "Uppvärmning antal starter", "liczba uruchomień palnika na ogrzewanie", "antall oppvarmninger", "démarrages du chauffage", "kazan ısıtmaya başlıyor", "preriscaldamento bruciatore", "štarty horáka na kúrenie") MAKE_TRANSLATION(UBAuptime, "ubauptime", "total UBA operating time", "Anlagengesamtlaufzeit", "totale looptijd branderautomaat (UBA)", "Total Tid", "łączny czas pracy układu sterowania", "totaltid", "durée de fonctionnement totale de l'appareil (UBA)", "kazanın toplam işletme süresi", "Tempo di funzionamento totale del sistema", "Celkový čas chodu systému") MAKE_TRANSLATION(lastCode, "lastcode", "last error code", "Letzter Fehler", "Laatste foutcode", "Senaste Felkod", "ostatni błąd", "siste feilkode", "dernier code d'erreur", "son hata kodu", "ultimo codice errore", "posledný chybový kód") MAKE_TRANSLATION(serviceCode, "servicecode", "service code", "Statusmeldung", "Statuscode", "Servicekod", "kod serwisowy", "servicekode", "code de service", "servis kodu", "codice messaggio di stato", "servisný kód") @@ -369,31 +369,31 @@ MAKE_TRANSLATION(curveBase, "curvebase", "heatingcurve base", "Heizkurve Basis", MAKE_TRANSLATION(curveEnd, "curveend", "heatingcurve end", "Heizkurve Ende", "", "", "", "", "", "", "", "koniec vykurovacej krivky") // TODO translate // heatpump/compress specific -MAKE_TRANSLATION(upTimeTotal, "uptimetotal", "heatpump total uptime", "Gesamtbetriebszeit: Wärmepumpe", "", "", "łączny czas pracy pompy ciepła", "", "", "", "", "celková doba prevádzky tepelného čerpadla") // TODO translate -MAKE_TRANSLATION(upTimeControl, "uptimecontrol", "total operating time heat", "Gesamtbetriebszeit: Heizen", "Totale bedrijfstijd", "Total tid uppvärmning", "łączny czas generowania ciepła", "total driftstid", "durée totale de fonctionnement chauffage", "ısınma toplam işletme süresi", "Tempo di funzionamento totale riscaldamento", "celkový prevádzkový čas tepla") -MAKE_TRANSLATION(upTimeCompHeating, "uptimecompheating", "operating time compressor heating", "Betriebszeit: Kompressor heizen", "Bedrijfstijd compressor verwarmingsbedrijf", "Total tid kompressor uppvärmning", "łączny czas ogrzewania (sprężarka)", "totaltid kompressor", "durée de fonctionnement compresseur chauffage", "ısı pompası ısınma işletme süresi", "tempo di funzionamento del compressore riscaldamento", "prevádzková doba vykurovania kompresora") -MAKE_TRANSLATION(upTimeCompCooling, "uptimecompcooling", "operating time compressor cooling", "Betriebszeit: Kompressor kühlen", "Bedrijfstijd compressor koelbedrijf", "Total tid kompressor kyla", "łączny czas chłodzenia (sprężarka)", "Total tid kompressor kjøling", "durée de fonctionnement compresseur refroidissement", "ısı pompası soğuma işletme süresi", "tempo di funzionamento del compressore raffreddamento", "doba prevádzky chladenia kompresora") -MAKE_TRANSLATION(upTimeCompWw, "uptimecomp", "operating time compressor", "Betriebszeit: Kompressor", "Bedrijfstijd compressor", "Total tid kompressor", "łączny czas grzania c.w.u. (sprężarka)", "Total tid kompressor", "durée de fonctionnement compresseur", "ısı pompası sıcak kullanım suyu işletme süresi", "tempo di funzionamento del compressore", "prevádzková doba kompresora") -MAKE_TRANSLATION(upTimeCompPool, "uptimecomppool", "operating time compressor pool", "Betriebszeit: Kompressor Pool", "Bedrijfstijd compressor voor zwembadbedrijf", "Total tid kompressor pool", "łączny czas podgrzewania basenu (sprężarka)", "Total tid kompressor basseng", "durée de fonctionnement compresseur piscine", "ısı pompası havuz işletme süresi", "tempo di funzionamento del compressore piscina", "prevádzková doba kompresorového bazéna") +MAKE_TRANSLATION(upTimeTotal, "uptimetotal", "heatpump total uptime", "Gesamtbetriebszeit Wärmepumpe", "", "", "łączny czas pracy pompy ciepła", "", "", "", "", "celková doba prevádzky tepelného čerpadla") // TODO translate +MAKE_TRANSLATION(upTimeControl, "uptimecontrol", "total operating time heat", "Gesamtbetriebszeit Heizen", "Totale bedrijfstijd", "Total tid uppvärmning", "łączny czas generowania ciepła", "total driftstid", "durée totale de fonctionnement chauffage", "ısınma toplam işletme süresi", "Tempo di funzionamento totale riscaldamento", "celkový prevádzkový čas tepla") +MAKE_TRANSLATION(upTimeCompHeating, "uptimecompheating", "operating time compressor heating", "Betriebszeit Kompressor heizen", "Bedrijfstijd compressor verwarmingsbedrijf", "Total tid kompressor uppvärmning", "łączny czas ogrzewania (sprężarka)", "totaltid kompressor", "durée de fonctionnement compresseur chauffage", "ısı pompası ısınma işletme süresi", "tempo di funzionamento del compressore riscaldamento", "prevádzková doba vykurovania kompresora") +MAKE_TRANSLATION(upTimeCompCooling, "uptimecompcooling", "operating time compressor cooling", "Betriebszeit Kompressor kühlen", "Bedrijfstijd compressor koelbedrijf", "Total tid kompressor kyla", "łączny czas chłodzenia (sprężarka)", "Total tid kompressor kjøling", "durée de fonctionnement compresseur refroidissement", "ısı pompası soğuma işletme süresi", "tempo di funzionamento del compressore raffreddamento", "doba prevádzky chladenia kompresora") +MAKE_TRANSLATION(upTimeCompWw, "uptimecomp", "operating time compressor", "Betriebszeit Kompressor", "Bedrijfstijd compressor", "Total tid kompressor", "łączny czas grzania c.w.u. (sprężarka)", "Total tid kompressor", "durée de fonctionnement compresseur", "ısı pompası sıcak kullanım suyu işletme süresi", "tempo di funzionamento del compressore", "prevádzková doba kompresora") +MAKE_TRANSLATION(upTimeCompPool, "uptimecomppool", "operating time compressor pool", "Betriebszeit Kompressor Pool", "Bedrijfstijd compressor voor zwembadbedrijf", "Total tid kompressor pool", "łączny czas podgrzewania basenu (sprężarka)", "Total tid kompressor basseng", "durée de fonctionnement compresseur piscine", "ısı pompası havuz işletme süresi", "tempo di funzionamento del compressore piscina", "prevádzková doba kompresorového bazéna") MAKE_TRANSLATION(totalCompStarts, "totalcompstarts", "total compressor control starts", "Gesamtkompressorstarts ", "Totaal compressorstarts", "Kompressorstarter Totalt", "liczba załączeń sprężarki", "kompressorstarter totalt", "nombre démarrages total contrôle compresseur", "ısı pompası kontrolü toplam başlatma", "avvii totali del compressore", "spustí sa celkové riadenie kompresora") MAKE_TRANSLATION(heatingStarts, "heatingstarts", "heating control starts", "Heizungsregelungstarts", "Starts verwarmingsbedrijf", "Kompressorstarter Uppvärmning", "liczba załączeń ogrzewania", "kompressorstarter oppvarming", "démarrages contrôle chauffage", "ısıtma kontrolü toplam başlatma", "avvii riscaldamento", "ovládanie vykurovania sa spustí") MAKE_TRANSLATION(coolingStarts, "coolingstarts", "cooling control starts", "Kühlregelungstarts", "Starts koelbedrijf", "Kompressorstarter Kyla", "liczba załączeń chłodzenia", "kompressorstarter kjøling", "démarrages contrôle refroidissement", "soğutma kontrolü toplam başlatma", "avvii raffreddamento", "ovládanie chladenia sa spustí") MAKE_TRANSLATION(poolStarts, "poolstarts", "pool control starts", "Poolsteuerungstarts", "Starts zwembadbedrijf", "Kompressorstarter Pool", "liczba załączeń podgrzewania basenu", "kompressorstarter basseng", "démarrages contrôle piscine", "havuz kontrolü toplam başlatma", "avvio controllato piscina", "riadenie bazéna sa spustí") MAKE_TRANSLATION(nrgConsTotal, "nrgconstotal", "total energy consumption", "Gesamtenergieverbrauch", "Energieverbrauch gesamt", "Energiförbrukning totalt", "energia pobrana (sumarycznie)", "energiforbruk totalt", "consommation totale énergie", "toplam enerji tüketimi", "totale energia consumata", "celková spotreba energie") -MAKE_TRANSLATION(nrgConsCompTotal, "nrgconscomptotal", "total energy consumption compressor", "Gesamtenergieverbrauch: Kompressor", "Energieverbruik compressor totaal", "Energiförbrukning kompressor", "energia pobrana przez sprężarkę", "energiforbruk kompressor", "consommation totale énergie compresseur", "ısı pompası toplam enerji tüketimi", "totale energia consumata compressore", "kompresor s celkovou spotrebou energie") -MAKE_TRANSLATION(nrgConsCompHeating, "nrgconscompheating", "energy consumption compressor heating", "Energieverbrauch: Kompressor heizen", "Energieverbruik compressor verwarmingsbedrijf", "Energiförbrukning uppvärmning", "energia pobrana przez sprężarkę na ogrzewanie", "energiforbruk oppvarming", "consommation énergie compresseur chauffage", "ısı pompası ısıtma toplam enerji tüketimi", "consumo energia compressore riscaldamento", "spotreba energie vykurovanie kompresorom") -MAKE_TRANSLATION(nrgConsCompWw, "nrgconscomp", "energy consumption compressor", "Energieverbrauch: Kompressor", "Energieverbruik compressor", "Energiförbrukning", "energia pobrana przez sprężarkę na c.w.u.", "energiforbruk", "consommation énergie compresseur", "ısı pompası sıcak kullanım suyu toplam enerji tüketimi", "consumo energia compressore", "kompresor spotreby energie") -MAKE_TRANSLATION(nrgConsCompCooling, "nrgconscompcooling", "energy consumption compressor cooling", "Energieverbrauch: Kompressor kühlen", "Energieverbruik compressor koelbedrijf", "Energiförbrukning kyla", "energia pobrana przez sprężarkę na chłodzenie", "energiforbruk kjøling", "consommation énergie compresseur refroidissement", "ısı pompası soğutma toplam enerji tüketimi", "consumo energia compressore raffreddamento", "spotreba energie kompresorové chladenie") -MAKE_TRANSLATION(nrgConsCompPool, "nrgconscomppool", "energy consumption compressor pool", "Energieverbrauch: Kompressor Pool", "Energiebedrijf compressor zwembadbedrijf", "Energiförbrukning pool", "energia pobrana przez sprężarkę na podgrzewanie basenu", "energiforbruk basseng", "consommation énergie compresseur piscine", "ısı pompası havuz toplam enerji tüketimi", "consumo energia compressore piscina", "spotreba energie kompresorový bazén") +MAKE_TRANSLATION(nrgConsCompTotal, "nrgconscomptotal", "total energy consumption compressor", "Gesamtenergieverbrauch Kompressor", "Energieverbruik compressor totaal", "Energiförbrukning kompressor", "energia pobrana przez sprężarkę", "energiforbruk kompressor", "consommation totale énergie compresseur", "ısı pompası toplam enerji tüketimi", "totale energia consumata compressore", "kompresor s celkovou spotrebou energie") +MAKE_TRANSLATION(nrgConsCompHeating, "nrgconscompheating", "energy consumption compressor heating", "Energieverbrauch Kompressor heizen", "Energieverbruik compressor verwarmingsbedrijf", "Energiförbrukning uppvärmning", "energia pobrana przez sprężarkę na ogrzewanie", "energiforbruk oppvarming", "consommation énergie compresseur chauffage", "ısı pompası ısıtma toplam enerji tüketimi", "consumo energia compressore riscaldamento", "spotreba energie vykurovanie kompresorom") +MAKE_TRANSLATION(nrgConsCompWw, "nrgconscomp", "energy consumption compressor", "Energieverbrauch Kompressor", "Energieverbruik compressor", "Energiförbrukning", "energia pobrana przez sprężarkę na c.w.u.", "energiforbruk", "consommation énergie compresseur", "ısı pompası sıcak kullanım suyu toplam enerji tüketimi", "consumo energia compressore", "kompresor spotreby energie") +MAKE_TRANSLATION(nrgConsCompCooling, "nrgconscompcooling", "energy consumption compressor cooling", "Energieverbrauch Kompressor kühlen", "Energieverbruik compressor koelbedrijf", "Energiförbrukning kyla", "energia pobrana przez sprężarkę na chłodzenie", "energiforbruk kjøling", "consommation énergie compresseur refroidissement", "ısı pompası soğutma toplam enerji tüketimi", "consumo energia compressore raffreddamento", "spotreba energie kompresorové chladenie") +MAKE_TRANSLATION(nrgConsCompPool, "nrgconscomppool", "energy consumption compressor pool", "Energieverbrauch Kompressor Pool", "Energiebedrijf compressor zwembadbedrijf", "Energiförbrukning pool", "energia pobrana przez sprężarkę na podgrzewanie basenu", "energiforbruk basseng", "consommation énergie compresseur piscine", "ısı pompası havuz toplam enerji tüketimi", "consumo energia compressore piscina", "spotreba energie kompresorový bazén") MAKE_TRANSLATION(nrgSuppTotal, "nrgsupptotal", "total energy supplied", "gesamte Energieabgabe", "Totaal opgewekte energie", "Genererad energi", "energia oddana (sumarycznie)", "tilført energi", "énergie totale fournie", "sağlanan toplam enerji", "totale energia fornita", "celková dodaná energia") MAKE_TRANSLATION(nrgSuppHeating, "nrgsuppheating", "total energy supplied heating", "gesamte Energieabgabe heizen", "Opgewekte energie verwarmingsbedrijf", "Genererad energi Uppvärmning", "energia oddana na ogrzewanie", "tilført energi oppvarming", "énergie totale fournie chauffage", "ısıtma sağlanan toplam enerji", "energia totale fornita - riscaldamento", "celková dodaná energia na vykurovanie") MAKE_TRANSLATION(nrgSuppWw, "nrgsupp", "total energy warm supplied", "gesamte Energieabgabe Wärme", "Opgewekte energie", "Genererad energi", "energia oddana na c.w.u.", "tilført energi", "énergie chaude totale fournie", "sıcak kullanım suyu sağlanan toplam enerji", "totale energia calorica fornita", "celková dodaná teplá energia") MAKE_TRANSLATION(nrgSuppCooling, "nrgsuppcooling", "total energy supplied cooling", "gesamte Energieabgabe kühlen", "Opgewekte energie koelbedrijf", "Genererad energi Kyla", "energia oddana na chłodzenie", "Tillført energi kjøling", "énergie totale fournie refroidissement", "soğutma sağlanan toplam enerji", "energia totale fornita - raffreddamento", "chladenie s celkovou dodanou energiou") MAKE_TRANSLATION(nrgSuppPool, "nrgsupppool", "total energy supplied pool", "gesamte Energieabgabe Pool", "Opgewekte energie zwembadbedrijf", "Genererad energi Pool", "energia oddana na podgrzewanie basenu", "tilført energi basseng", "énergie totale fournie piscine", "havuz sağlanan toplam enerji", "totale di energia fornita- piscina", "celkový bazén dodanej energie") -MAKE_TRANSLATION(auxElecHeatNrgConsTotal, "auxelecheatnrgconstotal", "total aux elec. heater energy consumption", "Energieverbrauch: el. Zusatzheizung", "Totaal energieverbruik electrisch verwarmingselement", "Energiförbrukning Eltillkott", "energia pobrana przez grzałki", "energiforbruk varmekolbe", "consommation totale énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı toplam enerji tüketimi", "consumo energetico riscaldamento elettrico supplementare", "celková spotreba energie prídavného elektrického ohrievača") -MAKE_TRANSLATION(auxElecHeatNrgConsHeating, "auxelecheatnrgconsheating", "aux elec. heater energy consumption heating", "Energieverbrauch: el. Zusatzheizung Heizen", "Energieverbruik electrisch verwarmingselement voor verwarmingsbedrijf", "Energiförbrukning Eltillskott Uppvärmning", "energia pobrana przez grzałki na ogrzewanie", "energiforbruk varmekolbe oppvarming", "consommation énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı ısınma toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario", "pomocný elektrický ohrievač spotreba energie vykurovanie") -MAKE_TRANSLATION(auxElecHeatNrgConsWw, "auxelecheatnrgcons", "aux elec. heater energy consumption", "Energieverbrauch: el. Zusatzheizung", "Energieverbruik electrisch verwarmingselement voor", "Energiförbrukning Eltillskott", "energia pobrana przez grzałki na c.w.u.", "energiförbruk varmekolbe", "consommation énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı sıcak kullanım suyu toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario", "spotreba energie pomocného elektrického ohrievača") -MAKE_TRANSLATION(auxElecHeatNrgConsPool, "auxelecheatnrgconspool", "aux elec. heater energy consumption pool", "Energieverbrauch: el. Zusatzheizung Pool", "Energieverbruik electrisch verwarmingselement voor zwembadbedrijf", "Energiförbrukning Eltillskott Pool", "energia pobrana przez grzałki na podgrzewanie basenu", "energiforbruk el. tilleggsvarme basseng", "consommation énergie electrique auxiliaire chauffage piscine", "ilave elektrikli ısıtıcı havuz toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario piscina", "bazén spotreby energie pomocného elektrického ohrievača") +MAKE_TRANSLATION(auxElecHeatNrgConsTotal, "auxelecheatnrgconstotal", "total aux elec. heater energy consumption", "Energieverbrauch el. Zusatzheizung", "Totaal energieverbruik electrisch verwarmingselement", "Energiförbrukning Eltillkott", "energia pobrana przez grzałki", "energiforbruk varmekolbe", "consommation totale énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı toplam enerji tüketimi", "consumo energetico riscaldamento elettrico supplementare", "celková spotreba energie prídavného elektrického ohrievača") +MAKE_TRANSLATION(auxElecHeatNrgConsHeating, "auxelecheatnrgconsheating", "aux elec. heater energy consumption heating", "Energieverbrauch el. Zusatzheizung Heizen", "Energieverbruik electrisch verwarmingselement voor verwarmingsbedrijf", "Energiförbrukning Eltillskott Uppvärmning", "energia pobrana przez grzałki na ogrzewanie", "energiforbruk varmekolbe oppvarming", "consommation énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı ısınma toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario", "pomocný elektrický ohrievač spotreba energie vykurovanie") +MAKE_TRANSLATION(auxElecHeatNrgConsWw, "auxelecheatnrgcons", "aux elec. heater energy consumption", "Energieverbrauch el. Zusatzheizung", "Energieverbruik electrisch verwarmingselement voor", "Energiförbrukning Eltillskott", "energia pobrana przez grzałki na c.w.u.", "energiförbruk varmekolbe", "consommation énergie electrique auxiliaire chauffage", "ilave elektrikli ısıtıcı sıcak kullanım suyu toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario", "spotreba energie pomocného elektrického ohrievača") +MAKE_TRANSLATION(auxElecHeatNrgConsPool, "auxelecheatnrgconspool", "aux elec. heater energy consumption pool", "Energieverbrauch el. Zusatzheizung Pool", "Energieverbruik electrisch verwarmingselement voor zwembadbedrijf", "Energiförbrukning Eltillskott Pool", "energia pobrana przez grzałki na podgrzewanie basenu", "energiforbruk el. tilleggsvarme basseng", "consommation énergie electrique auxiliaire chauffage piscine", "ilave elektrikli ısıtıcı havuz toplam enerji tüketimi", "consumo di energia riscaldamento elettrico ausiliario piscina", "bazén spotreby energie pomocného elektrického ohrievača") MAKE_TRANSLATION(hpCompOn, "hpcompon", "hp compressor", "WP Kompressor", "WP compressor", "VP Kompressor", "sprężarka pompy ciepła", "vp kompressor", "compresseur pompe à chaleur", "hp ısı pompası", "compressore pompa calore", "hp kompresor") MAKE_TRANSLATION(coolingOn, "coolingon", "cooling on", "Kühlung an", "koelbedrijf", "Kyla", "chłodzenie włączone", "kjøling", "refroidissement", "soğutma", "", "chladenie") // TODO translate @@ -426,17 +426,17 @@ MAKE_TRANSLATION(hpPh1, "hpph1", "high pressure side temperature (PH1)", "Hochdr MAKE_TRANSLATION(hpTa4, "hpta4", "drain pan temp (TA4)", "Kondensatorwanne (TA4)", "Temperatuur condensorafvoerbak (TA4)", " (TA4)", "temperatura ociekacza (TA4)", "kondens temperatur (TA4)", " (TA4)", "tahliye sıcaklığı (TA4)", "temperatura condensatore (TA4)", "teplota vypúšťacej misky (TA4)") // TODO translate MAKE_TRANSLATION(hpTw1, "hptw1", "reservoir temp (TW1)", "DHW Reservoir (TW1)", "(TW1)", "(TW1)", "temperatura zbiornika (TW1)", "(TW1)", "(TW1)", "(TW1)", "(TW1)", "teplota zásobníka (TW1)") // TODO translate -MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status: Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1") -MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status: Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2") -MAKE_TRANSLATION(hpInput3, "hpin3", "input 3 state", "Status: Eingang 3", "Status input 3", "Status Ingång 3", "stan wejścia 3", "status inggang 3", "état entrée 3", "giriş 3 durumu", "stato ingresso 3", "stav vstupu 3") -MAKE_TRANSLATION(hpInput4, "hpin4", "input 4 state", "Status: Eingang 4", "Status input 4", "Status Ingång 4", "stan wejścia 4", "status inggang 4", "état entrée 4", "giriş 4 durumu", "stato ingresso 4", "stav vstupu 4") -MAKE_TRANSLATION(hpIn1Opt, "hpin1opt", "input 1 options", "Einstellung: Eingang 1", "Instelling input 1", "Inställningar Ingång 1", "opcje wejścia 1", "innstillinger inngang 1", "options entrée 1", "giriş 1 seçenekleri", "impostazioni ingresso 1", "možnosti vstupu 1") -MAKE_TRANSLATION(hpIn2Opt, "hpin2opt", "input 2 options", "Einstellung: Eingang 2", "Instelling input 2", "Inställningar Ingång 2", "opcje wejścia 2", "innstillinger inngang 2", "options entrée 2", "giriş 2 seçenekleri", "impostazioni ingresso 2", "možnosti vstupu 2") -MAKE_TRANSLATION(hpIn3Opt, "hpin3opt", "input 3 options", "Einstellung: Eingang 3", "Instelling input 3", "Inställningar Ingång 3", "opcje wejścia 3", "innstillinger inngang 3", "options entrée 3", "giriş 3 seçenekleri", "impostazioni ingresso 3", "možnosti vstupu 3") -MAKE_TRANSLATION(hpIn4Opt, "hpin4opt", "input 4 options", "Einstellung: Eingang 4", "Instelling input 4", "Inställningar Ingång 4", "opcje wejścia 4", "innstillinger inngang 4", "options entrée 4", "giriş 4 seçenekleri", "impostazioni ingresso 4", "možnosti vstupu 4") -MAKE_TRANSLATION(maxHeatComp, "maxheatcomp", "heat limit compressor", "Heizstab: Limit mit Kompressor", "heat limit compressor", "heat limit compressor", "ograniczenie mocy sprężarki", "max varmegrense kompressor", "limite chaleur compresseur", "ısı pompası ısıtma sınırı", "limite riscaldamento compressore", "tepelný limit kompresora") -MAKE_TRANSLATION(maxHeatHeat, "maxheatheat", "heat limit heating", "Heizstab: Limit Leistung", "heat limit heating", "heat limit heating", "ograniczenie mocy w trybie ogrzewania", "maks varmegrense oppvarming", "limite chaleur chauffage", "ısınma ısıtma sınırı", "limite calore riscaldamento", "vyhrievanie limitu tepla") -MAKE_TRANSLATION(maxHeatDhw, "maxheat", "heat limit", "Heizstab: Limit für WW", "heat limit", "heat limit", "ograniczenie mocy w trybie c.w.u.", "varmegrense", "limite chaleur", "sıcak kullanım suyu ısınma sınırı", "limite calore", "tepelný limit") +MAKE_TRANSLATION(hpInput1, "hpin1", "input 1 state", "Status Eingang 1", "Status input 1", "Status Ingång 1", "stan wejścia 1", "status inggang 1", "état entrée 1", "giriş 1 durumu", "stato ingresso 1", "stav vstupu 1") +MAKE_TRANSLATION(hpInput2, "hpin2", "input 2 state", "Status Eingang 2", "Status input 2", "Status Ingång 2", "stan wejścia 2", "status inggang 2", "état entrée 2", "giriş 2 durumu", "stato ingresso 2", "stav vstupu 2") +MAKE_TRANSLATION(hpInput3, "hpin3", "input 3 state", "Status Eingang 3", "Status input 3", "Status Ingång 3", "stan wejścia 3", "status inggang 3", "état entrée 3", "giriş 3 durumu", "stato ingresso 3", "stav vstupu 3") +MAKE_TRANSLATION(hpInput4, "hpin4", "input 4 state", "Status Eingang 4", "Status input 4", "Status Ingång 4", "stan wejścia 4", "status inggang 4", "état entrée 4", "giriş 4 durumu", "stato ingresso 4", "stav vstupu 4") +MAKE_TRANSLATION(hpIn1Opt, "hpin1opt", "input 1 options", "Einstellung Eingang 1", "Instelling input 1", "Inställningar Ingång 1", "opcje wejścia 1", "innstillinger inngang 1", "options entrée 1", "giriş 1 seçenekleri", "impostazioni ingresso 1", "možnosti vstupu 1") +MAKE_TRANSLATION(hpIn2Opt, "hpin2opt", "input 2 options", "Einstellung Eingang 2", "Instelling input 2", "Inställningar Ingång 2", "opcje wejścia 2", "innstillinger inngang 2", "options entrée 2", "giriş 2 seçenekleri", "impostazioni ingresso 2", "možnosti vstupu 2") +MAKE_TRANSLATION(hpIn3Opt, "hpin3opt", "input 3 options", "Einstellung Eingang 3", "Instelling input 3", "Inställningar Ingång 3", "opcje wejścia 3", "innstillinger inngang 3", "options entrée 3", "giriş 3 seçenekleri", "impostazioni ingresso 3", "možnosti vstupu 3") +MAKE_TRANSLATION(hpIn4Opt, "hpin4opt", "input 4 options", "Einstellung Eingang 4", "Instelling input 4", "Inställningar Ingång 4", "opcje wejścia 4", "innstillinger inngang 4", "options entrée 4", "giriş 4 seçenekleri", "impostazioni ingresso 4", "možnosti vstupu 4") +MAKE_TRANSLATION(maxHeatComp, "maxheatcomp", "heat limit compressor", "Heizstab Limit mit Kompressor", "heat limit compressor", "heat limit compressor", "ograniczenie mocy sprężarki", "max varmegrense kompressor", "limite chaleur compresseur", "ısı pompası ısıtma sınırı", "limite riscaldamento compressore", "tepelný limit kompresora") +MAKE_TRANSLATION(maxHeatHeat, "maxheatheat", "heat limit heating", "Heizstab Limit Leistung", "heat limit heating", "heat limit heating", "ograniczenie mocy w trybie ogrzewania", "maks varmegrense oppvarming", "limite chaleur chauffage", "ısınma ısıtma sınırı", "limite calore riscaldamento", "vyhrievanie limitu tepla") +MAKE_TRANSLATION(maxHeatDhw, "maxheat", "heat limit", "Heizstab Limit für WW", "heat limit", "heat limit", "ograniczenie mocy w trybie c.w.u.", "varmegrense", "limite chaleur", "sıcak kullanım suyu ısınma sınırı", "limite calore", "tepelný limit") MAKE_TRANSLATION(auxHeaterOff, "auxheateroff", "disable aux heater", "Zusatzheizer deaktivieren", "Bijverwarming uitsc", "Blockera eltillskott", "wyłącz dogrzewacz", "deaktiver tilleggsvarme", "Désactiver chauff. d'app", "ilave ısıtıcıyı kapat", "disattivare i riscaldatori addizionali", "vypnúť pomocný ohrievač") MAKE_TRANSLATION(auxHeaterStatus, "auxheaterstatus", "aux heater status", "Zusatzheizerstatus", "Bijverwarming", "Eltillskott Status", "status dogrzewacza", "status el. tillegsvarme", "Chauffage auxiliaire", "ilave ısıtıcı durumu", "stato riscaldatori addizionali", "stav pomocného ohrievača") @@ -444,11 +444,11 @@ MAKE_TRANSLATION(auxHeaterOnly, "auxheateronly", "aux heater only", "nur Zusatzh MAKE_TRANSLATION(auxHeaterDelay, "auxheaterdelay", "aux heater on delay", "Zusatzheizer verzögert ein", "Bijverw. vertraagd aan", "Eltillskottfördröjning på", "opóźnienie włączenia dogrzewacza", "Tilleggsvarmer forsinket på", "Chauff app tempo marche", "ilave ısıtıcı beklemede", "ritardo riscaldatori addizionali", "oneskorenie prídavného ohrievača") MAKE_TRANSLATION(silentMode, "silentmode", "silent mode", "Silentmodus", "Stiller gebruik", "Tyst läge", "tryb cichy", "stille modus", "Fct silencieux", "sessiz mod", "modalità silenziosa", "tichý režim") MAKE_TRANSLATION(minTempSilent, "mintempsilent", "min outside temp for silent mode", "Minimale Außentemperatur Silentmodus", "Stiller gebruik min. buitentemp", "Tyst läge min temp", "minimalna temperatura zewnętrzna dla trybu cichego", "atille modus min temp", "Fct silencieux: Temp. extérieure min.", "sessiz mod için min. dış ortam sıcaklığı", "modalità silenziosa temperatura esterna minima", "min. vonkajšia teplota pre tichý režim") -MAKE_TRANSLATION(tempParMode, "tempparmode", "outside temp parallel mode", "Heizstab: Parallelbetrieb", "Buitentemp. parallelbedr", "Parallelläge Utomhustemp.", "maksymalna temperatura zewnętrzna dla dogrzewacza", "", "Temp. ext. fct parallèle", "paralel mod dış ortam sıcaklığı", "modalità parallela temperatura esterna", "paralelný režim mimo teploty") // TODO translate +MAKE_TRANSLATION(tempParMode, "tempparmode", "outside temp parallel mode", "Heizstab Parallelbetrieb", "Buitentemp. parallelbedr", "Parallelläge Utomhustemp.", "maksymalna temperatura zewnętrzna dla dogrzewacza", "", "Temp. ext. fct parallèle", "paralel mod dış ortam sıcaklığı", "modalità parallela temperatura esterna", "paralelný režim mimo teploty") // TODO translate MAKE_TRANSLATION(auxHeatMixValve, "auxheatmix", "aux heater mixing valve", "Mischventil Zusatzheizer", "Bijverwarming menger", "Eltilskott Blandarventil", "mieszacz dogrzewacza", "eltilskudd blandeventil", "Chauffage auxiliaire mélangeur", "ilave ısıtıcı karışım vanası", "miscela riscaldatori addizionali", "zmiešavací ventil pomocného ohrievača") -MAKE_TRANSLATION(hpHystHeat, "hphystheat", "on/off hyst heat", "Schalthysterese: Heizen", "Aan/uit-hysteresis in verw. bedrijf", "Hstereses Uppvärm.", "histereza wł./wył. ogrzewania", "På/av hysterese Oppvar.", "Hystérésis Marche en mode chauffage", "ısıtma gecikmesi", "isteresi di commutazione riscaldamento", "zapnutie/vypnutie hyst ohrevu") -MAKE_TRANSLATION(hpHystCool, "hphystcool", "on/off hyst cool", "Schalthysterese: Kühlen", "Aan/uit-hysteresis in koelbedrijf", "Hystereses Kyla", "histereza wł./wył. chłodzenia", "hystrese kjøling", "Hystérésis Marche en mode refroidissement", "soğutma gecikmesi", "isteresi di commutazione raffreddamento", "zapnutie/vypnutie hyst chladenia") -MAKE_TRANSLATION(hpHystPool, "hphystpool", "on/off hyst pool", "Schalthysterese: Pool", "an/uit-hysteresis in zwembadbedri", "Hystereses Pool", "histereza wł./wył. podgrzewania basenu", "hystrese basseng", "Hystérésis Marche en mode piscine", "havuz gecikmesi", "isteresi di commutazione piscina", "zapnutie/vypnutie hyst bazénu") +MAKE_TRANSLATION(hpHystHeat, "hphystheat", "on/off hyst heat", "Schalthysterese Heizen", "Aan/uit-hysteresis in verw. bedrijf", "Hstereses Uppvärm.", "histereza wł./wył. ogrzewania", "På/av hysterese Oppvar.", "Hystérésis Marche en mode chauffage", "ısıtma gecikmesi", "isteresi di commutazione riscaldamento", "zapnutie/vypnutie hyst ohrevu") +MAKE_TRANSLATION(hpHystCool, "hphystcool", "on/off hyst cool", "Schalthysterese Kühlen", "Aan/uit-hysteresis in koelbedrijf", "Hystereses Kyla", "histereza wł./wył. chłodzenia", "hystrese kjøling", "Hystérésis Marche en mode refroidissement", "soğutma gecikmesi", "isteresi di commutazione raffreddamento", "zapnutie/vypnutie hyst chladenia") +MAKE_TRANSLATION(hpHystPool, "hphystpool", "on/off hyst pool", "Schalthysterese Pool", "an/uit-hysteresis in zwembadbedri", "Hystereses Pool", "histereza wł./wył. podgrzewania basenu", "hystrese basseng", "Hystérésis Marche en mode piscine", "havuz gecikmesi", "isteresi di commutazione piscina", "zapnutie/vypnutie hyst bazénu") MAKE_TRANSLATION(tempDiffHeat, "tempdiffheat", "temp diff TC3/TC0 heat", "Temp.diff. TC3/TC0 Heizen", "Temp.vers. TC3/TC0 verw", "Delta(T) TC3/TC0 Uppvärm.", "różnica temperatur TC3/TC0 w trakcie ogrzewania", "temp. diff. TC3/TC0 oppvarm", "Delta T TC3/TC0 Chauff", "TC3-TC0 ısıtma sıcaklık farkı", "Delta T riscaldamento TC3/TC0", "teplotný rozdiel TC3/TC0 tepla") MAKE_TRANSLATION(tempDiffCool, "tempdiffcool", "temp diff TC3/TC0 cool", "Temp.diff. TC3/TC0 Kühlen", "Temp.vers. TC3/TC0 koel.", "Delta(T) TC3/TC0 Kyla", "różnica temperatur TC3/TC0 w trakcie chłodzenia", "temp. diff. TC3/TC0 kjøling", "Delta T TC3/TC0 Refroid.", "TC3-TC0 soğutma sıcaklık farkı", "Delta T raffreddamento TC3/TC0", "teplotný rozdiel TC3/TC0 chladenie") MAKE_TRANSLATION(silentFrom, "silentfrom", "silent mode from", "Silentmodus Start", "Start stille modus", "", "początek trybu cichego", "stillemodus starter", "", "sessiz mod başlangıcı", "avvio della modalità silenziosa", "tichý režim od") // TODO translate @@ -487,8 +487,8 @@ MAKE_TRANSLATION(boost, "boost", "boost mode", "Boost-Modus", "", "", "tryb wzmo MAKE_TRANSLATION(boosttime, "boosttime", "boost time", "Boost-Dauer", "", "", "czas trwania wzmocnienia", "", "", "", "", "čas trvania posilnenia") // TODO translate MAKE_TRANSLATION(hpPumpMode, "hppumpmode", "primary heatpump mode", "primärer Wärmepumpenmodus", "", "", "tryb pracy głównej pompy ciepła", "", "", "", "", "režim primárneho tepelného čerpadla") // TODO translate MAKE_TRANSLATION(instantstart, "instantstart", "instant start", "Sofortstart", "", "", "natychmiastowy start", "", "", "", "", "okamžité spustenie") // TODO translate -MAKE_TRANSLATION(heatondelay, "heatondelay", "heat-on delay", "Heizeinschaltverzögerung", "", "", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie zapnutia kúreni") // TODO translate -MAKE_TRANSLATION(heatoffdelay, "heatoffdelay", "heat-off delay", "Heizausschaltverzögerung", "", "", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie vypnutia kúrenia") // TODO translate +MAKE_TRANSLATION(heatondelay, "heatondelay", "heat-on delay", "Einschaltverzögerung Heizen", "", "", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie zapnutia kúreni") // TODO translate +MAKE_TRANSLATION(heatoffdelay, "heatoffdelay", "heat-off delay", "Ausschaltverzögerung Heizen", "", "", "opóźnienie włączania ogrzewania", "", "", "", "", "Oneskorenie vypnutia kúrenia") // TODO translate MAKE_TRANSLATION(hpSetDiffPress, "hpsetdiffpress", "set differental pressure", "Pumpensolldruck", "", "", "różnica ciśnień", "", "", "", "", "nastaviť diferenčný tlak") // TODO translate MAKE_TRANSLATION(hpFan, "fan", "fan", "Lüfter", "", "", "wentylator", "", "", "", "", "ventilátor") // TODO translate MAKE_TRANSLATION(hpShutdown, "shutdown", "shutdown", "Abschalten", "", "", "wyłączenie", "", "", "", "", "vypnutie") // TODO translate @@ -497,21 +497,21 @@ MAKE_TRANSLATION(hpShutdown, "shutdown", "shutdown", "Abschalten", "", "", "wył MAKE_TRANSLATION(hybridStrategy, "hybridstrategy", "hybrid control strategy", "Hybrid-Steuerungsstrategie", "Hybride strategie", "Hybrid kontrollstrategi", "strategia sterowania hybrydowego", "hybrid kontrollstrategi", "stratégie contrôle hybride", "hibrit kontrol stratejisi", "strategia comtrollo ibrido", "hybridná stratégia riadenia") MAKE_TRANSLATION(switchOverTemp, "switchovertemp", "outside switchover temperature", "Außentemperatur für Umschaltung", "Schakeltemperatuur buitentemperatuur", "Utomhus Omställningstemperatur", "zewnętrzna temperatura przełączania", "utendørstemp styring", "basculement par température extérieure", "geçiş için dış sıcaklık", "temperatura esterna per commutazione", "vonkajšia prepínacia teplota") MAKE_TRANSLATION(energyCostRatio, "energycostratio", "energy cost ratio", "Energie-/Kostenverhältnis", "Energiekostenratio", "Energi/Kostnads-förhållande", "współczynnik energia/koszt", "energi/kostnads forhold", "ratio coût énergie", "enerji maliyet oranı", "rapporto energia/costo", "pomer nákladov na energiu") -MAKE_TRANSLATION(fossileFactor, "fossilefactor", "fossile energy factor", "Energiefaktor: Fossil", "Energiefactor fossiele brandstof", "Energifaktor fossilenergi", "udział energii z paliw kopalnych", "energifaktor fossilenergi", "facteur énergie fossile", "fosil yakıt faktörü", "fattore energia fossile", "faktor fosílnej energie") -MAKE_TRANSLATION(electricFactor, "electricfactor", "electric energy factor", "Energiefaktor: elektrisch", "Energiefactor electrisch", "Elektrisk energifaktor", "udział energii elektrycznej", "elektrisk energifaktor", "facteur énergie électrique", "elektrik enerjisi faktörü", "fattore energia elettrica", "faktor elektrickej energie") +MAKE_TRANSLATION(fossileFactor, "fossilefactor", "fossile energy factor", "Energiefaktor Fossil", "Energiefactor fossiele brandstof", "Energifaktor fossilenergi", "udział energii z paliw kopalnych", "energifaktor fossilenergi", "facteur énergie fossile", "fosil yakıt faktörü", "fattore energia fossile", "faktor fosílnej energie") +MAKE_TRANSLATION(electricFactor, "electricfactor", "electric energy factor", "Energiefaktor elektrisch", "Energiefactor electrisch", "Elektrisk energifaktor", "udział energii elektrycznej", "elektrisk energifaktor", "facteur énergie électrique", "elektrik enerjisi faktörü", "fattore energia elettrica", "faktor elektrickej energie") MAKE_TRANSLATION(delayBoiler, "delayboiler", "delay boiler support", "Verzögerungsoption", "Vertragingsoptie", "Fördröjningsoption", "opcja opóźnienia", "Fördörjningsoption", "option retardement chaudière", "kazan desteğini ötele", "opzione ritardo caldaia","oneskorená podpora kotla") MAKE_TRANSLATION(tempDiffBoiler, "tempdiffboiler", "temp diff boiler support", "Temperaturdifferenzoption", "Verschiltemperatuuroptie", "Temperaturskillnadsoption", "opcja różnicy temperatur", "temperatursforskjell kjele", "option différence température", "sıcaklık farkı kazan desteği", "opzione differenza temperatura", "možnosť rozdielu teplôt") MAKE_TRANSLATION(lowNoiseMode, "lownoisemode", "low noise mode", "Geräuscharmer Betrieb", "Stil bedrijf", "Tyst läge", "tryb cichy", "stillemodus", "mode faible bruit", "düşük ses modu", "modalità a basso rumore", "režim nízkej hlučnosti") MAKE_TRANSLATION(lowNoiseStart, "lownoisestart", "low noise starttime", "Start geräuscharmer Betrieb", "Start stil bedrijf", "Tyst läge starttid", "początek trybu cichego", "stille modu starttid", "heure démarrage faible bruit", "düşük ses başlangıç", "ora di avvio a basso rumore", "nízka hlučnosť spustenia") MAKE_TRANSLATION(lowNoiseStop, "lownoisestop", "low noise stoptime", "Stopp geräuscharmer Betrieb", "Stop stil bedrijf", "Tyst läge stopptid", "koniec trybu cichego", "stille modus stopptid", "heure arrêt faible bruit", "düşük ses bitiş", "ora di arresto funzionamento silenzioso", "doba zastavenia s nízkou hlučnosťou") -MAKE_TRANSLATION(energyPriceGas, "energypricegas", "energy price gas", "Energiepreis: Gas", "Energieprijs gas", "Gaspris", "cena energii z gazu", "energipris gass", "prix énergie gaz", "gaz enerjisi fiyatı", "prezzo energia gas", "cena energie plyn") -MAKE_TRANSLATION(energyPriceEl, "energypriceel", "energy price electric", "Energiepreis: Eletrizität", "energieprijs electriciteit", "Elpris", "cena energii elektrycznej", "strømpris", "prix énergie électrique", "elektrik enerjisi fiyatı", "prezzo energia elettrica", "cena elektrickej energie") +MAKE_TRANSLATION(energyPriceGas, "energypricegas", "energy price gas", "Energiepreis Gas", "Energieprijs gas", "Gaspris", "cena energii z gazu", "energipris gass", "prix énergie gaz", "gaz enerjisi fiyatı", "prezzo energia gas", "cena energie plyn") +MAKE_TRANSLATION(energyPriceEl, "energypriceel", "energy price electric", "Energiepreis Eletrizität", "energieprijs electriciteit", "Elpris", "cena energii elektrycznej", "strømpris", "prix énergie électrique", "elektrik enerjisi fiyatı", "prezzo energia elettrica", "cena elektrickej energie") MAKE_TRANSLATION(energyPricePV, "energyfeedpv", "feed in PV", "PV-Einspeisevergütung", "PV teruglevertarief", "PV Energi", "cena energii PV", "strømpris PV", "alimentation PV", "giren güneş enerjisi", "energia fotovoltaico", "Výkupná cena FV") MAKE_TRANSLATION(hybridDHW, "hybriddhw", "hybrid DHW", "Hybrid-Warmwasser", "Hybride ww", "Hybridläge varmvatten", "hybrydowa c.w.u.", "hybridmodus varmtvann", "ecs hybride", "hibrit SKS", "ACS ibrida", "hybridná TÚV") MAKE_TRANSLATION(airPurgeMode, "airpurgemode", "air purge mode", "Luftspülung", "Luchtzuivering", "Luftreningsläge", "tryb oczyszczania powietrza", "luftsrensningsmodus", "mode purge air", "hava temizleme modu", "modalita spurgo aria", "režim čistenia vzduchu") MAKE_TRANSLATION(heatPumpOutput, "heatpumpoutput", "heatpump output", "WP-Leistung", "WP output", "Värmepumpseffekt", "moc wyjściowa pompy ciepła", "varmepumpeeffekt", "sortie pompe à chaleur", "ısı pompası çıkışı", "prestazione pompa calore", "Výkon tepelného čerpadla") MAKE_TRANSLATION(coolingCircuit, "coolingcircuit", "cooling circuit", "Kühlkreislauf", "Koelcircuit", "Kylkrets", "obwód chłodzący", "kjølekrets", "circuit refroidissement", "soğutma devresi", "circuito raffreddante", "chladiaci okruh") -MAKE_TRANSLATION(compStartMod, "compstartmod", "compressor start modulation", "Kompressorstartleistung", "Beginvermogen compressor", "Kompressor startmodulering", "początkowa modulacja sprężarki", "kompressor startmodulering", "modulation démarrage compresseur", "kazan başlangıç modülasyonu", "avvio modulazione compressore", "modulácia štartu kompresora") +MAKE_TRANSLATION(compStartMod, "compstartmod", "compressor start modulation", "Kompressorstartmodulation", "Beginvermogen compressor", "Kompressor startmodulering", "początkowa modulacja sprężarki", "kompressor startmodulering", "modulation démarrage compresseur", "kazan başlangıç modülasyonu", "avvio modulazione compressore", "modulácia štartu kompresora") MAKE_TRANSLATION(heatDrainPan, "heatdrainpan", "heat drain pan", "Wärmeausgleichsgefäß", "Vereffeningsvat", "Uppvärm. dränering", "zbiornik wyrównawczy ciepła", "oppvarming drenering", "bac récupération chaleur", "ısı tahliye tablası", "serbatoio scarico condensa", "odkvapkávacia nádoba na teplo") MAKE_TRANSLATION(heatCable, "heatcable", "heating cable", "Heizband", "heating cable", "värmekabel", "przewód grzejny", "varmekabel", "câble chauffant", "ısıtma kablosu", "cavo riscaldante", "vykurovací kábel") @@ -553,19 +553,19 @@ MAKE_TRANSLATION(releaseWait, "releasewait", "boiler release wait time", "Wartez // energy MAKE_TRANSLATION(nrgTotal, "nrgtotal", "total energy", "Gesamtenergie", "", "", "całkowita energia", "", "", "", "", "celková energia") // TODO translate -MAKE_TRANSLATION(nrgHeat, "nrgheat", "energy heating", "Energie: Heizen", "", "", "energia na ogrzewanie", "", "", "ısıtma enerjisi", "energia vykurovania", "energetické vykurovanie") // TODO translate -MAKE_TRANSLATION(nrgCool, "nrgcool", "energy cooling", "Energie: Kühlen", "", "", "", "", "", "", "", "energia chladenia") // TODO translate +MAKE_TRANSLATION(nrgHeat, "nrgheat", "energy heating", "Energie Heizen", "", "", "energia na ogrzewanie", "", "", "ısıtma enerjisi", "energia vykurovania", "energetické vykurovanie") // TODO translate +MAKE_TRANSLATION(nrgCool, "nrgcool", "energy cooling", "Energie Kühlen", "", "", "", "", "", "", "", "energia chladenia") // TODO translate MAKE_TRANSLATION(nrgWw, "nrg", "energy", "Energie", "", "", "energia", "", "", "sıcak kullanım suyu enerjisi", "", "energia") // TODO translate -MAKE_TRANSLATION(nrgHeat2, "nrgheat2", "energy heating 2", "Energie: Heizen 2", "", "", "energia na ogrzewanie 2", "", "", "ısıtma enerjisi 2", "", "energia vykurovania 2") // TODO translate +MAKE_TRANSLATION(nrgHeat2, "nrgheat2", "energy heating 2", "Energie Heizen 2", "", "", "energia na ogrzewanie 2", "", "", "ısıtma enerjisi 2", "", "energia vykurovania 2") // TODO translate MAKE_TRANSLATION(nrgWw2, "nrg2", "energy 2", "Energie 2", "", "", "energia 2", "", "", "sıcak kullanım suyu enerjisi 2", "", "energia 2") // TODO translate MAKE_TRANSLATION(nomPower, "nompower", "nominal Power", "Brennerleistung", "", "", "moc nominalna", "", "", "nominal güç", "", "nominálny výkon") // TODO translate MAKE_TRANSLATION(meterTotal, "metertotal", "meter total", "Gesamtmessung", "", "", "licznik całkowity", "", "", "", "", "počítadlo celkom") // TODO translate -MAKE_TRANSLATION(meterComp, "metercomp", "meter compressor", "Messung: Kompressor", "", "", "licznik sprężarki", "", "", "", "", "počítadlo kompresor") // TODO translate -MAKE_TRANSLATION(meterEHeat, "metereheat", "meter e-heater", "Messung: E-Heizer", "", "", "licznik dogrzewacza", "", "", "", "", "počítadlo e-ohrievača") // TODO translate -MAKE_TRANSLATION(meterHeat, "meterheat", "meter heating", "Messung: Heizen", "", "", "licznik ogrzewania", "", "", "", "", "počítadlo kúrenia") // TODO translate -MAKE_TRANSLATION(meterCool, "metercool", "meter cooling", "Messung: Kühlen", "", "", "", "", "", "", "", "počítadlo chladenia") // TODO translate +MAKE_TRANSLATION(meterComp, "metercomp", "meter compressor", "Messung Kompressor", "", "", "licznik sprężarki", "", "", "", "", "počítadlo kompresor") // TODO translate +MAKE_TRANSLATION(meterEHeat, "metereheat", "meter e-heater", "Messung E-Heizer", "", "", "licznik dogrzewacza", "", "", "", "", "počítadlo e-ohrievača") // TODO translate +MAKE_TRANSLATION(meterHeat, "meterheat", "meter heating", "Messung Heizen", "", "", "licznik ogrzewania", "", "", "", "", "počítadlo kúrenia") // TODO translate +MAKE_TRANSLATION(meterCool, "metercool", "meter cooling", "Messung Kühlen", "", "", "", "", "", "", "", "počítadlo chladenia") // TODO translate MAKE_TRANSLATION(meterWw, "meter", "meter", "Messung", "", "", "licznik", "", "", "", "", "počítadlo") // TODO translate -MAKE_TRANSLATION(gasMeterHeat, "gasmeterheat", "gas meter heating", "Gaszähler: Heizen", "", "", "licznik gazu na ogrzewanie", "", "", "", "", "počítadlo plynu kúrenia") // TODO translate +MAKE_TRANSLATION(gasMeterHeat, "gasmeterheat", "gas meter heating", "Gaszähler Heizen", "", "", "licznik gazu na ogrzewanie", "", "", "", "", "počítadlo plynu kúrenia") // TODO translate MAKE_TRANSLATION(gasMeterWw, "gasmeter", "gas meter", "Gaszähler", "", "", "licznik gazu", "", "", "", "", "počítadlo plynu") // TODO translate // HIU @@ -586,7 +586,7 @@ MAKE_TRANSLATION(wwSetTemp, "settemp", "set temperature", "Solltemperatur", "Str MAKE_TRANSLATION(wwType, "type", "type", "Typ", "type", "Typ", "typ", "type", "type", "tip", "tipo", "typ") MAKE_TRANSLATION(wwComfort, "comfort", "comfort", "Komfort", "Comfort", "Komfort", "komfort", "komfort", "confort", "konfor", "Comfort", "komfort") MAKE_TRANSLATION(wwComfort1, "comfort1", "comfort mode", "Komfort-Modus", "Comfort modus", "Komfortläge", "tryb komfortu", "komfort modus", "mode confort", "konfor modu", "modalità comfort", "komfortný režim") -MAKE_TRANSLATION(wwFlowTempOffset, "flowtempoffset", "flow temperature offset", "Vorlauftemperaturanhebung", "Aanvoertemperatuur offset", "Flödestemperatur förskjutning", "korekta temperatury wypływu", "turtemperaturforskyvning", "offset température flux", "akış sıcaklığı artışı", "aumento della temperatura di ritorno", "Posun teploty prívodu") +MAKE_TRANSLATION(wwFlowTempOffset, "flowtempoffset", "flow temperature offset", "Anhebung Vorlauftemperatur", "Aanvoertemperatuur offset", "Flödestemperatur förskjutning", "korekta temperatury wypływu", "turtemperaturforskyvning", "offset température flux", "akış sıcaklığı artışı", "aumento della temperatura di ritorno", "Posun teploty prívodu") MAKE_TRANSLATION(wwMaxPower, "maxpower", "max power", "max. Leistung", "Maximaal vermogen", "Max. Effekt", "moc. maksymalna", "maks. effekt", "puissance max.", "maksimum güç", "potenza massima", "maximálny výkon") MAKE_TRANSLATION(wwCircPump, "circpump", "circulation pump available", "Zirkulationspumpe vorhanden", "Circulatiepomp aanwezig", "Cirkulationspump tillgänglig", "pompa cyrkulacji zainstalowana", "sirkulasjonspumpe tilgjengelig", "pompe circulation disponible", "sikülasyon pompası müsait", "pompa circolazione disponibile", "dostupné obehové čerpadlo") MAKE_TRANSLATION(wwChargeType, "chargetype", "charging type", "Speicherladungstyp", "Buffer laadtype", "Laddningstyp", "sposób grzania zasobnika", "varmetype", "type chargement", "şarj tipi", "tipo caricamento", "typ nabíjania") @@ -617,14 +617,14 @@ MAKE_TRANSLATION(wwProgMode, "progmode", "program", "Programmmodus", "Programma" MAKE_TRANSLATION(wwCircProg, "circprog", "circulation program", "Zirkulationsprogramm", "Circulatieprogramma", "Cirkulationsprogram", "program cyrkulacji c.w.u.", "sirkulationsprogram", "programme circulation", "sirkülasyon programı", "programma circolazione", "obehový program") MAKE_TRANSLATION(wwMaxTemp, "maxtemp", "maximum temperature", "maximale Temperatur", "maximale temperatuur", "maximal Temperatur", "temperatura maksymalna", "maksimal temperatur", "température max", "maksimum sıcaklık", "temperatura massima", "maximálna teplota") MAKE_TRANSLATION(wwOneTimeKey, "onetimekey", "one time key function", "Einmalladungstaste", "Knop voor eenmalig laden buffer", "Engångsfunktion", "przycisk jednorazowego ogrzania", "engangsknapp varme", "fonction touche unique", "tek seferlik doldurma fonksiyonu", "pulsante funzione singola", "jednorazová kľúčová funkcia") -MAKE_TRANSLATION(wwSolarTemp, "solartemp", "solar boiler temperature", "Solarboilertemperatur", "Zonneboiler temperatuur", "Solpanel Temp", "temperatura zasobnika solarnego", "solpaneltemp", "température chaudière solaire", "güneş enerjisi kazan sıcaklığı", "temperatura pannello solare", "teplota solárneho kotla") +MAKE_TRANSLATION(wwSolarTemp, "solartemp", "solar boiler temperature", "Solarkesseltemperatur", "Zonneboiler temperatuur", "Solpanel Temp", "temperatura zasobnika solarnego", "solpaneltemp", "température chaudière solaire", "güneş enerjisi kazan sıcaklığı", "temperatura pannello solare", "teplota solárneho kotla") // mqtt values / commands MAKE_TRANSLATION(switchtime, "switchtime", "program switchtime", "Programmschaltzeit", "Programma schakeltijd", "Program Bytestid", "program czasowy", "programbyttetid", "heure commutation programme", "program değiştirme süresi", "ora commutazione programmata", "čas prepnutia programu") MAKE_TRANSLATION(switchtime1, "switchtime1", "own1 program switchtime", "Programmschaltzeit 1", "Schakeltijd programma 1", "Program 1 Bytestid", "program przełączania 1", "byttetidprogram 1", "heure de commutation programme 1", "program1 değiştirme süresi", "ora commutazione programma 1", "vlastný 1 program prepnutia") MAKE_TRANSLATION(switchtime2, "switchtime2", "own2 program switchtime", "Programmschaltzeit 2", "Schakeltijd programma 2", "Program 2 Bytestid", "program przełączania 2", "byttetid program 2", "heure de changement programme 2", "program1 değiştirme süresi", "ora commutazione programma 2", "vlastný 2 program prepnutia") -MAKE_TRANSLATION(wwswitchtime, "switchtimeWW", "program switchtime warm water", "Programmschaltzeit: Warmwasser", "Warm water programma schakeltijd", "Varmvattenprogram Bytestid", "program czasowy", "byttetid varmtvannsprogram", "heure commutation programme", "sıcak kullanıom suyu program değiştirme süresi", "Tempo di commutazione del programma", "čas prepnutia programu") -MAKE_TRANSLATION(wwcircswitchtime, "circswitchtime", "circulation program switchtime", "Zirculationsprogramm: Schaltzeit", "Schakeltijd circulatieprogramma", "Cirkulationsprogram Bytestid", "program cyrkulacji", "byttetid sirkulasjonsprogram", "heure commutation programme circulation", "sirkülasyon program değiştirme süresi", "ora commutazione programma circolazione", "čas prepnutia cirkulačného programu") +MAKE_TRANSLATION(wwswitchtime, "switchtimeWW", "program switchtime warm water", "Programmschaltzeit Warmwasser", "Warm water programma schakeltijd", "Varmvattenprogram Bytestid", "program czasowy", "byttetid varmtvannsprogram", "heure commutation programme", "sıcak kullanıom suyu program değiştirme süresi", "Tempo di commutazione del programma", "čas prepnutia programu") +MAKE_TRANSLATION(wwcircswitchtime, "circswitchtime", "circulation program switchtime", "Zirculationsprogramm Schaltzeit", "Schakeltijd circulatieprogramma", "Cirkulationsprogram Bytestid", "program cyrkulacji", "byttetid sirkulasjonsprogram", "heure commutation programme circulation", "sirkülasyon program değiştirme süresi", "ora commutazione programma circolazione", "čas prepnutia cirkulačného programu") MAKE_TRANSLATION(dateTime, "datetime", "date/time", "Datum/Zeit", "Datum/Tijd", "Datum/Tid", "data i godzina", "dato/tid", "date/heure", "zaman/saat", "Data/Ora", "dátum/čas") MAKE_TRANSLATION(errorCode, "errorcode", "error code", "Fehlercode", "Foutmeldingscode", "Felkod", "kod błędu", "feikode", "code erreur", "hata kodu", "codice errore", "error kód") MAKE_TRANSLATION(ibaMainDisplay, "display", "display", "Anzeige", "Display", "Display", "wyświetlacz", "skjerm", "affichage", "ekran", "Display", "display") @@ -647,8 +647,8 @@ MAKE_TRANSLATION(preheating, "preheating", "preheating in the clock program", "V MAKE_TRANSLATION(offtemp, "offtemp", "temperature when mode is off", "Temperatur bei AUS", "Temperatuur bij UIT", "Temperatur Avslagen", "temperatura w trybie \"wył.\"", "temperatur avslått", "température lorsque mode désactivé", "mod kapalı iken sıcaklık", "temperatura quando la modalità è disattivata", "teplota, keď je režim vypnutý") MAKE_TRANSLATION(mixingvalves, "mixingvalves", "mixing valves", "Mischventile", "Mengkleppen", "Blandningsventiler", "zawory mieszające", "blandeventiler", "vannes mélange", "karışım vanaları", "valvole miscela", "zmiešavacie ventily") MAKE_TRANSLATION(pvEnableWw, "pvenabledhw", "enable raise dhw", "aktiviere WW-Anhebung", "Verhoging WW activeren", "", "podwyższenie c.w.u. z PV", "aktivere hevet temperatur bereder", "", "sıcak kullanım suyu yükseltmeyi etkinleştir", "abilitare aumento ACS", "povoliť zvýšenie TÚV") // TODO translate -MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Heizanhebung mit PV", "Verwarmen met PV activeren", "", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV") // TODO translate -MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Kühlabsenkung mit PV", "Verlagen koeling met PV activeren", "", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV") // TODO translate +MAKE_TRANSLATION(pvRaiseHeat, "pvraiseheat", "raise heating with PV", "Anhebung Heizen mit PV", "Verwarmen met PV activeren", "", "podwyższenie grzania z PV", "heve varmen med solpanel", "", "ısıtmayı G.E. İle yükselt", "Aumentare il riscaldamento con il solare", "zvýšiť kúrenie s FV") // TODO translate +MAKE_TRANSLATION(pvLowerCool, "pvlowercool", "lower cooling with PV", "Absenkung Kühlen mit PV", "Verlagen koeling met PV activeren", "", "obniżenie chłodzenia z PV", "nedre kjøling solpanel", "", "soğutmayı G.E. İle düşür", "Riduzione del raffreddamento con il solare", "nižšie chladenie s PV") // TODO translate // thermostat dhw MAKE_TRANSLATION(wwMode, "mode", "operating mode", "Betriebsart", "Modus", "Läge", "tryb pracy", "modus", "mode", "mod", "modalità", "režim") @@ -706,7 +706,7 @@ MAKE_TRANSLATION(party, "party", "party time", "Partyzeit", "Partytijd", "Partyt MAKE_TRANSLATION(holidaytemp, "holidaytemp", "holiday temperature", "Urlaubstemperatur", "Vakantietemperatuur", "Helgtemperatur", "temperatura w trybie urlopowym", "ferietemperatur", "température vacances", "tatil sıcaklığı", "temperatura festiva", "prázdninová teplota") MAKE_TRANSLATION(summermode, "summermode", "summer mode", "Sommerbetrieb", "Zomerbedrijf", "Sommarläge", "aktualny tryb lato/zima", "sommermodus", "mode été", "yaz modu", "funzionamento estivo", "letný režim") MAKE_TRANSLATION(holidaymode, "holidaymode", "holiday mode", "Urlaubsbetrieb", "Vakantiebedrijf", "Helgläge", "tryb urlopowy", "feriemodus", "mode vacances", "tatil modu", "modalita vacanze", "dovolenkový režim") -MAKE_TRANSLATION(flowtempoffset, "flowtempoffset", "flow temperature offset for mixer", "Vorlauftemperaturanhebung", "Mixer aanvoertemperatuur offset", "Temperaturkorrigering Flödestemp. Blandningsventil", "korekta temperatury przepływu dla miksera", "temperaturkorrigering av blandingsventil", "décalage température de bascule pour mélangeur", "karıştırıcı için akış sıcaklığı farkı", "aumento della temperatura di ritorno", "Posun teploty prívodu pre zmiešavač") +MAKE_TRANSLATION(flowtempoffset, "flowtempoffset", "flow temperature offset for mixer", "Anhebung Vorlauftemperatur", "Mixer aanvoertemperatuur offset", "Temperaturkorrigering Flödestemp. Blandningsventil", "korekta temperatury przepływu dla miksera", "temperaturkorrigering av blandingsventil", "décalage température de bascule pour mélangeur", "karıştırıcı için akış sıcaklığı farkı", "aumento della temperatura di ritorno", "Posun teploty prívodu pre zmiešavač") MAKE_TRANSLATION(reducemode, "reducemode", "reduce mode", "Absenkmodus", "Gereduceerde modus", "Reducerat Läge", "tryb zredukowany/obniżony", "redusert modus", "mode réduction", "düşürme modu", "modalità assente", "znížený režim") MAKE_TRANSLATION(noreducetemp, "noreducetemp", "no reduce below temperature", "Durchheizen unter", "Reduceermodus onderbreken onder", "Inaktivera reducering under", "bez redukcji poniżej temperatury", "inaktiver redusert nedre temp", "pas de réduction en dessous température", "bu sıcaklığın altına düşürme", "non ridurre temperatura sotto", "žiadne zníženie teploty pod teplotu") MAKE_TRANSLATION(reducetemp, "reducetemp", "off/reduce switch temperature", "Absenkmodus unter", "Onderste afschakeltemperatuur", "Avslag/Reducera under", "tryb zredukowany poniżej temperatury", "nedre avstengningstemperatur", "arrêt/réduction température bascule", "sıcaklık kapama/düşürme modu", "interruttore riduzione temperatura", "vypnúť/znížiť teplotu spínača") @@ -765,8 +765,8 @@ MAKE_TRANSLATION(hydrTemp, "hydrTemp", "hydraulic header temperature", "Verteile // solar MAKE_TRANSLATION(cylMiddleTemp, "cylmiddletemp", "cylinder middle temperature (TS3)", "Speichertemperatur Mitte (TS3)", "Zonneboilertemperatuur midden (TS3)", "Cylindertemperatur Mitten (TS3)", "temperatura w środku zasobnika (TS3)", "beredertemperatur i midten (TS3)", "température moyenne cylindre (TS3)", "orta depolama sıcaklığı (TS3)", "temperatura di conservazione media accumulo (TS3)", "stredná teplota valca (TS3)") -MAKE_TRANSLATION(retHeatAssist, "retheatassist", "return temperature heat assistance (TS4)", "Rücklaufanhebungstemp. (TS4)", "Retourtemperatuur verwarmingsassistentie (TS4)", "Returtemperatur värmestöd (TS4)", "temperatura powrotu wspomagania grzania (TS4)", "returtemperatur varmestøtte (TS4)", "température retour de assistance thermique (TS4)", "geri dönüş sıcaklığı artışı (TS4)", "temperatura ritorno scambiatore (TS4)", "pomoc pri teplote spiatočky (TS4)") -MAKE_TRANSLATION(ts8, "ts8", "return temperature heat assistance (TS8)", "Rücklaufanhebungstemp. (TS8)", "Retourtemperatuur verwarmingsassistentie (TS8)", "Returtemperatur värmestöd (TS8)", "temperatura powrotu wspomagania grzania (TS8)", "returtemperatur varmestøtte (TS8)", "température retour de assistance thermique (TS8)", "geri dönüş sıcaklığı artışı (TS8)", "temperatura ritorno scambiatore (TS8)", "pomoc pri teplote spiatočky (TS8)") +MAKE_TRANSLATION(retHeatAssist, "retheatassist", "return temperature heat assistance (TS4)", "Anhebung Rücklauftemp. (TS4)", "Retourtemperatuur verwarmingsassistentie (TS4)", "Returtemperatur värmestöd (TS4)", "temperatura powrotu wspomagania grzania (TS4)", "returtemperatur varmestøtte (TS4)", "température retour de assistance thermique (TS4)", "geri dönüş sıcaklığı artışı (TS4)", "temperatura ritorno scambiatore (TS4)", "pomoc pri teplote spiatočky (TS4)") +MAKE_TRANSLATION(ts8, "ts8", "return temperature heat assistance (TS8)", "Anhebung Rücklauftemp. (TS8)", "Retourtemperatuur verwarmingsassistentie (TS8)", "Returtemperatur värmestöd (TS8)", "temperatura powrotu wspomagania grzania (TS8)", "returtemperatur varmestøtte (TS8)", "température retour de assistance thermique (TS8)", "geri dönüş sıcaklığı artışı (TS8)", "temperatura ritorno scambiatore (TS8)", "pomoc pri teplote spiatočky (TS8)") MAKE_TRANSLATION(m1Valve, "heatassistvalve", "heat assistance valve (M1)", "Ventil Heizungsunterstützung (M1)", "Klep verwarmingsassistentie (M1)", "Uppvärmningsstöd Ventil (M1)", "zawór wspomagania grzania (M1)", "varmehjelpsventil (M1)", "vanne assistance thermique (M1)", "ısıtma yardım vanası (M1)", "valvola scambiatore (M1)", "tepelný asistenčný ventil (M1)") MAKE_TRANSLATION(m1Power, "heatassistpower", "heat assistance valve power (M1)", "Ventilleistung Heizungsunterstützung (M1)", "Vermogen klep verwarmingsassistentie (M1)", "Uppvärmningsstöd Ventil Effekt (M1)", "moc zaworu wspomagania grzania (M1)", "varmehjelpsventileffekt (M1)", "puissance vanne assistance thermique (M1)", "ısıtma yardım vanası gücü (M1)", "potenza valvola scambiatore (M1)", "výkon ventilu tepelného asistenta (M1)") MAKE_TRANSLATION(pumpMinMod, "pumpminmod", "minimum pump modulation", "minimale Pumpenmodulation", "Minimale pompmodulatie", "Min Pumpmodulering", "minimalna modulacja pompy", "minimum pumpmodulering", "modulation minimale pompe", "minimum pompa modülasyonu", "modulazione minima pompa", "minimálna modulácia čerpadla") @@ -800,7 +800,7 @@ MAKE_TRANSLATION(pump2WorkTime, "pump2worktime", "pump 2 working time", "Laufzei MAKE_TRANSLATION(m1WorkTime, "m1worktime", "differential control working time", "Differenzregelung Arbeitszeit", "Verschilregeling arbeidstijd", "Differentialreglering Drifttid", "czas pracy regulacji różnicowej", "differentialreguleringssrifttid", "durée fonctionnement contrôle différentiel", "çalışma saatlerinin farklı düzenlenmesi", "controllo differenziale durata funzionamento", "pracovný čas diferenciálnej kontroly") MAKE_TRANSLATION(energyLastHour, "energylasthour", "energy last hour", "Energie letzte Std", "Energie laatste uur", "Energi Senaste Timmen", "energia w ciągu ostatniej godziny", "energi siste time", "énergie dernière heure", "son saat enerji", "Eenergia ultima ora", "energia za poslednú hodinu") MAKE_TRANSLATION(energyTotal, "energytotal", "total energy", "Gesamtenergie", "Totale energie", "Total Energi", "energia całkowita", "total energi", "énergie totale", "toplam enerji", "energia totale", "celková energia") -MAKE_TRANSLATION(energyToday, "energytoday", "total energy today", "Energie: heute", "Energie vandaag", "Total Energi Idag", "energia całkowita dzisiaj", "total energi i dag", "énergie totale aujourd'hui", "bugün toplam enerji", "totale energia giornaliera", "celková energia dnes") +MAKE_TRANSLATION(energyToday, "energytoday", "total energy today", "Energie heute", "Energie vandaag", "Total Energi Idag", "energia całkowita dzisiaj", "total energi i dag", "énergie totale aujourd'hui", "bugün toplam enerji", "totale energia giornaliera", "celková energia dnes") // solar dhw MAKE_TRANSLATION(wwColdTemp, "coldtemp", "cold water", "Kaltwasser", "", "", "zimna woda", "", "", "", "", "studená voda") // TODO translate @@ -856,9 +856,9 @@ MAKE_TRANSLATION(collector2Area, "collector2area", "collector 2 area", "Kollekto MAKE_TRANSLATION(collector2Type, "collector2type", "collector 2 type", "Kollektortyp 2", "Type collector 2", "Kollektor 2 Typ", "typ kolektora 2", "kollektor 2 type", "type collecteur 2", "kollektör 2 tip", "tipo collettore 2", "kolektor 2 typ") // telegram 0x0363 heatCounter -MAKE_TRANSLATION(heatCntFlowTemp, "heatcntflowtemp", "heat counter flow temperature", "Wärmezähler: Vorlauftemperatur", "Aanvoertemperatuur warmteenergiemeter", "Värmeräknare Flödestemperatur", "temperatura zasilania ciepłomierza", "varmeenergimåler turtemperatur", "température flux compteur chaleur", "ısı sayacı akış sıcaklığı", "Temperatura di mandata del contatore di calore", "teplota prúdu počítadla tepla") -MAKE_TRANSLATION(heatCntRetTemp, "heatcntrettemp", "heat counter return temperature", "Wärmezähler: Rücklauftemperatur", "Retourtemperatuur warmteenergiemeter", "Värmeräknare Returtemperatur", "temperatura powrotu ciepłomierza", "varmeenergimåler returtemperatur", "température retour compteur chaleur", "ısı sayacı dönüş sıcaklığı", "Temperatura di ritorno del contatore di calore", "teplota spiatočky počítadla tepla") -MAKE_TRANSLATION(heatCnt, "heatcnt", "heat counter impulses", "Wärmezähler: Impulse", "Warmteenergiemeter pulsen", "Värmeräknare Impuls", "liczba impulsów ciepłomierza", "varmemåler impuls", "impulsions compteur chaleur", "ısı sayacı atış adedi", "contacalore a impulsi", "Impulzy počítadla tepla") +MAKE_TRANSLATION(heatCntFlowTemp, "heatcntflowtemp", "heat counter flow temperature", "Wärmezähler Vorlauftemperatur", "Aanvoertemperatuur warmteenergiemeter", "Värmeräknare Flödestemperatur", "temperatura zasilania ciepłomierza", "varmeenergimåler turtemperatur", "température flux compteur chaleur", "ısı sayacı akış sıcaklığı", "Temperatura di mandata del contatore di calore", "teplota prúdu počítadla tepla") +MAKE_TRANSLATION(heatCntRetTemp, "heatcntrettemp", "heat counter return temperature", "Wärmezähler Rücklauftemperatur", "Retourtemperatuur warmteenergiemeter", "Värmeräknare Returtemperatur", "temperatura powrotu ciepłomierza", "varmeenergimåler returtemperatur", "température retour compteur chaleur", "ısı sayacı dönüş sıcaklığı", "Temperatura di ritorno del contatore di calore", "teplota spiatočky počítadla tepla") +MAKE_TRANSLATION(heatCnt, "heatcnt", "heat counter impulses", "Wärmezähler Impulse", "Warmteenergiemeter pulsen", "Värmeräknare Impuls", "liczba impulsów ciepłomierza", "varmemåler impuls", "impulsions compteur chaleur", "ısı sayacı atış adedi", "contacalore a impulsi", "Impulzy počítadla tepla") MAKE_TRANSLATION(swapFlowTemp, "swapflowtemp", "swap flow temperature (TS14)", "Austausch Vorlauftemperatur (TS14)", "Aanvoertemperatuur verwisselaar (TS14)", "Växlingstemperatur Flöde (TS14)", "temperatura zasilania wymiennika", "veksler turledningstemperatur (TS14)", "température flux échangeur (TS14)", "değişim akış sıcaklığı(TS14)", "Scambiare la temperatura di mandata (TS14)", "swap flow temperature (TS14)") MAKE_TRANSLATION(swapRetTemp, "swaprettemp", "swap return temperature (TS15)", "Austausch Rücklauftemperatur (TS15)", "Retourtemperatuur verwisselaar (TS15)", "Växlingstemperatur Returflöde (TS15)", "temperatura powrotu wymiennika", "veksler returledningstemperatur (TS15)", "température retour échangeur (TS15)", "değişim dönüş sıcaklığı(TS15)", "Scambiare la temperatura di ritorno (TS15)", "výmena teploty spiatočky (TS15)")