From 191edffe3c52425a0344bc4d3c65cefc051d69a6 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 13 Sep 2024 10:03:11 +0200 Subject: [PATCH] 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(), { + const { send: sendExportData } = useRequest((type: string) => exportData(type), { 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(), { - 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