diff --git a/interface/package.json b/interface/package.json index 5da5cc5b6..49f86eb8f 100644 --- a/interface/package.json +++ b/interface/package.json @@ -20,17 +20,17 @@ }, "dependencies": { "@alova/adapter-xhr": "^1.0.0", - "@emotion/react": "^11.11.0", + "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.13.4", "@table-library/react-table-library": "4.1.4", "@types/lodash-es": "^4.17.7", "@types/node": "^20.2.5", - "@types/react": "^18.2.8", + "@types/react": "^18.2.9", "@types/react-dom": "^18.2.4", "@types/react-router-dom": "^5.3.3", - "alova": "^2.5.5", + "alova": "^2.6.0", "async-validator": "^4.2.5", "axios": "^1.4.0", "history": "^5.3.0", @@ -40,7 +40,7 @@ "react-dom": "latest", "react-dropzone": "^14.2.3", "react-icons": "^4.9.0", - "react-router-dom": "^6.11.2", + "react-router-dom": "^6.12.0", "react-toastify": "^9.1.3", "sockette": "^2.0.6", "typesafe-i18n": "^5.24.3", diff --git a/interface/src/api/endpoints.ts b/interface/src/api/endpoints.ts index 684d9934d..229e00a27 100644 --- a/interface/src/api/endpoints.ts +++ b/interface/src/api/endpoints.ts @@ -33,7 +33,7 @@ export const alovaInstance = createAlova({ }, responded: { - onSuccess: async (response, method) => { + onSuccess: async (response) => { if (response.status === 400) { throw new Error('Invalid command'); } diff --git a/interface/src/project/api.ts b/interface/src/project/api.ts index 445e0e61f..289f73fb0 100644 --- a/interface/src/project/api.ts +++ b/interface/src/project/api.ts @@ -51,6 +51,10 @@ export function writeSettings(settings: Settings): AxiosPromise { export function getBoardProfile(boardProfile: BoardProfileName): AxiosPromise { return AXIOS.post('/boardProfile', boardProfile); } +// TODO change to GET +export function readDeviceEntities(unique_id: UniqueID): AxiosPromise { + return AXIOS_BIN.post('/deviceEntities', unique_id); +} export function readStatus(): AxiosPromise { return AXIOS.get('/status'); @@ -68,11 +72,6 @@ export function readSensorData(): AxiosPromise { return AXIOS.get('/sensorData'); } -// TODO change to GET -export function readDeviceEntities(unique_id: UniqueID): AxiosPromise { - return AXIOS_BIN.post('/deviceEntities', unique_id); -} - export function writeCustomEntities(customEntities: CustomEntities): AxiosPromise { return AXIOS.post('/customEntities', customEntities); } diff --git a/interface/src/utils/endpoints.ts b/interface/src/utils/endpoints.ts index 3570797c5..98b9c55ac 100644 --- a/interface/src/utils/endpoints.ts +++ b/interface/src/utils/endpoints.ts @@ -1,3 +1,4 @@ +// TODO can be removed! export const extractErrorMessage = (error: any, defaultMessage: string) => { if (error.request) { return defaultMessage + ' (' + error.request.status + ': ' + error.request.statusText + ')'; diff --git a/interface/yarn.lock b/interface/yarn.lock index 8e337fd77..02add5f85 100644 --- a/interface/yarn.lock +++ b/interface/yarn.lock @@ -340,9 +340,9 @@ __metadata: languageName: node linkType: hard -"@emotion/react@npm:^11.11.0": - version: 11.11.0 - resolution: "@emotion/react@npm:11.11.0" +"@emotion/react@npm:^11.11.1": + version: 11.11.1 + resolution: "@emotion/react@npm:11.11.1" dependencies: "@babel/runtime": ^7.18.3 "@emotion/babel-plugin": ^11.11.0 @@ -357,7 +357,7 @@ __metadata: peerDependenciesMeta: "@types/react": optional: true - checksum: c287fdef680c6cc95c021d2ccd48891052cd97edfe371ef0c0a9aa78f1cb764587c80a50e9f22eb943f522258dc4d7b80c4778c45331720e330e338db32f8a95 + checksum: 1aea4d735b537fbfbeda828bbf929488a7e1b5b7d131f14aeede8737e92bb3b611e15fec353e97f85aed7a65a1c86a695a04ba6e9be905231beef6bd624cb705 languageName: node linkType: hard @@ -961,10 +961,10 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.6.2": - version: 1.6.2 - resolution: "@remix-run/router@npm:1.6.2" - checksum: 73da6884e53873e4290abb3978373cafc3f351994273b0663eda5e12c81cb427fc6fe4df1924569d9a214f701d0106cf37122455951e0239d7e6fa35071df558 +"@remix-run/router@npm:1.6.3": + version: 1.6.3 + resolution: "@remix-run/router@npm:1.6.3" + checksum: d419fab24288123d8564a051c4a0e8cf46fb0f8fb7285701a819efb7f30b67785d0b63d21900a781485dea2d27271d78f2c56cb8b4b3fdb2ad72b61483989bd3 languageName: node linkType: hard @@ -1368,14 +1368,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.2.8": - version: 18.2.8 - resolution: "@types/react@npm:18.2.8" +"@types/react@npm:^18.2.9": + version: 18.2.9 + resolution: "@types/react@npm:18.2.9" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 4ed72e0cb9974f7002ebdd27bdb55beb7e715f18e1f537748f3a64ddd5b11ac25f61287d146feb4e2dd876eb615c49eead8cae65d75d5a4584572c00ab2093c5 + checksum: 5935a8cb8efc2804dbb0f85989970f654fb4117274b6d2836baa58d5e9dbfc09fd9d60e1f23a8d0fca70ad75e9f0e074790947899be40525cbe62f7ac58adcc6 languageName: node linkType: hard @@ -1530,20 +1530,20 @@ __metadata: resolution: "EMS-ESP@workspace:." dependencies: "@alova/adapter-xhr": ^1.0.0 - "@emotion/react": ^11.11.0 + "@emotion/react": ^11.11.1 "@emotion/styled": ^11.11.0 "@mui/icons-material": ^5.11.16 "@mui/material": ^5.13.4 "@table-library/react-table-library": 4.1.4 "@types/lodash-es": ^4.17.7 "@types/node": ^20.2.5 - "@types/react": ^18.2.8 + "@types/react": ^18.2.9 "@types/react-dom": ^18.2.4 "@types/react-router-dom": ^5.3.3 "@typescript-eslint/eslint-plugin": ^5.59.9 "@typescript-eslint/parser": ^5.59.9 "@vitejs/plugin-react-swc": ^3.3.2 - alova: ^2.5.5 + alova: ^2.6.0 async-validator: ^4.2.5 axios: ^1.4.0 eslint: ^8.42.0 @@ -1567,7 +1567,7 @@ __metadata: react-dom: latest react-dropzone: ^14.2.3 react-icons: ^4.9.0 - react-router-dom: ^6.11.2 + react-router-dom: ^6.12.0 react-toastify: ^9.1.3 rollup-plugin-visualizer: ^5.9.0 sockette: ^2.0.6 @@ -1647,10 +1647,10 @@ __metadata: languageName: node linkType: hard -"alova@npm:^2.5.5": - version: 2.5.5 - resolution: "alova@npm:2.5.5" - checksum: 028c24678fd91a5e2350b6c9c930475dd650fb766efad4d3dd8cd15d1ca85b2424e0857ba41d8f6eb2ad60999424269d8488b4aec66a4f74c98efd3378f21427 +"alova@npm:^2.6.0": + version: 2.6.0 + resolution: "alova@npm:2.6.0" + checksum: a99dd001f094cccbc6166c5cc56ed8d417434f9edf05aa5176992a3a3735600a3b626b41b50dd867b8a86b3edf44cfbd576568349af937626a7023f9b839226b languageName: node linkType: hard @@ -4807,27 +4807,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.11.2": - version: 6.11.2 - resolution: "react-router-dom@npm:6.11.2" +"react-router-dom@npm:^6.12.0": + version: 6.12.0 + resolution: "react-router-dom@npm:6.12.0" dependencies: - "@remix-run/router": 1.6.2 - react-router: 6.11.2 + "@remix-run/router": 1.6.3 + react-router: 6.12.0 peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: be7433bc290e56c0dd3e1008d53a76cc9866bf460980658501880876420086f11810ec3355a3abcd79ac537d6a1351eda009fade841c266456d0e8df60967b76 + checksum: 910b23ae3555e7baff97038c478b8fa65d5b54856c74e789c529850c002850a961329b692a8f1f4643100f46075918d2b55cbf3c7f87f85588387148010600f5 languageName: node linkType: hard -"react-router@npm:6.11.2": - version: 6.11.2 - resolution: "react-router@npm:6.11.2" +"react-router@npm:6.12.0": + version: 6.12.0 + resolution: "react-router@npm:6.12.0" dependencies: - "@remix-run/router": 1.6.2 + "@remix-run/router": 1.6.3 peerDependencies: react: ">=16.8" - checksum: a437606078d6096a6dfa322adf80d00ce153f20cd470ad888088c8da99f44477b963425c53f5461a540b909fc274154292ed80d636482dcdc58a423915ca1433 + checksum: b7cee04f5edbf48f1aa0303107514a3a9dc2b6f94a7a753fbf4eb8dde1d3eb67940204ff0b8b907c5b09f69c716dd958a6187346b1c35ccf19162d74e77d99af languageName: node linkType: hard diff --git a/mock-api/server.js b/mock-api/server.js index 97f209dd5..72159d075 100644 --- a/mock-api/server.js +++ b/mock-api/server.js @@ -396,6 +396,7 @@ const emsesp_coredata = { tn: 'Boiler', b: 'Nefit', n: 'GBx72/Trendline/Cerapur/Greenstar Si/27i', + // n: 'Enviline/Compress 6000AW/Hybrid 3000-7000iAW/SupraEco/Geo 5xx/WLW196i/WSW196i', d: 8, p: 123, v: '06.01' diff --git a/src/web/WebDataService.cpp b/src/web/WebDataService.cpp index 6fd4637d5..c44241a33 100644 --- a/src/web/WebDataService.cpp +++ b/src/web/WebDataService.cpp @@ -32,6 +32,12 @@ WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securi AuthenticationPredicates::IS_ADMIN)) , _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH, securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) { + // TODO Get for /deviceData + server->on(DEVICE_DATA_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&WebDataService::device_data2, this, _1), AuthenticationPredicates::IS_AUTHENTICATED)); + + server->on(CORE_DATA_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED)); @@ -88,7 +94,6 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { obj["d"] = emsdevice->device_id(); // deviceid obj["p"] = emsdevice->product_id(); // productid obj["v"] = emsdevice->version(); // version - // obj["e"] = emsdevice->count_entities(); // number of entities (device values) } } @@ -103,7 +108,6 @@ void WebDataService::core_data(AsyncWebServerRequest * request) { obj["d"] = 0; // deviceid obj["p"] = 0; // productid obj["v"] = 0; // version - // obj["e"] = EMSESP::webEntityService.count_entities(); // number of entities (device values) } root["connected"] = EMSESP::bus_status() != 2; @@ -169,6 +173,63 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) { request->send(response); } +// The unique_id is the unique record ID from the Web table to identify which device to load +// Compresses the JSON using MsgPack https://msgpack.org/index.html +void WebDataService::device_data2(AsyncWebServerRequest * request) { + uint8_t id; + if (request->hasParam(F_(id))) { + // TODO get id + id = Helpers::atoint(request->getParam(F_(id))->value().c_str()); + + size_t buffer = EMSESP_JSON_SIZE_XXXXLARGE; + auto * response = new MsgpackAsyncJsonResponse(false, buffer); + + // check size + while (!response->getSize()) { + delete response; + buffer -= 1024; + response = new MsgpackAsyncJsonResponse(false, buffer); + } + + for (const auto & emsdevice : EMSESP::emsdevices) { + if (emsdevice->unique_id() == id) { + // wait max 2.5 sec for updated data (post_send_delay is 2 sec) + for (uint16_t i = 0; i < (emsesp::TxService::POST_SEND_DELAY + 500) && EMSESP::wait_validate(); i++) { + delay(1); + } + EMSESP::wait_validate(0); // reset in case of timeout +#ifndef EMSESP_STANDALONE + JsonObject output = response->getRoot(); + emsdevice->generate_values_web(output); +#endif + +#if defined(EMSESP_DEBUG) + size_t length = response->setLength(); + EMSESP::logger().debug("Dashboard buffer used: %d", length); +#else + response->setLength(); +#endif + request->send(response); + return; + } + } + +#ifndef EMSESP_STANDALONE + if (id == 99) { + JsonObject output = response->getRoot(); + EMSESP::webEntityService.generate_value_web(output); + response->setLength(); + request->send(response); + return; + } +#endif + } + + // invalid + AsyncWebServerResponse * response = request->beginResponse(400); + request->send(response); +} + // The unique_id is the unique record ID from the Web table to identify which device to load // Compresses the JSON using MsgPack https://msgpack.org/index.html void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & json) { @@ -218,7 +279,6 @@ void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & request->send(response); } - // takes a command and its data value from a specific EMS Device, from the Web // assumes the service has been checked for admin authentication void WebDataService::write_device_value(AsyncWebServerRequest * request, JsonVariant & json) { diff --git a/src/web/WebDataService.h b/src/web/WebDataService.h index c064ab6ea..3c7439483 100644 --- a/src/web/WebDataService.h +++ b/src/web/WebDataService.h @@ -45,8 +45,15 @@ class WebDataService { void core_data(AsyncWebServerRequest * request); void sensor_data(AsyncWebServerRequest * request); + // TODO make it a Get + void device_data2(AsyncWebServerRequest * request); + + // POST + // TODO probably can be removed void device_data(AsyncWebServerRequest * request, JsonVariant & json); + + void write_device_value(AsyncWebServerRequest * request, JsonVariant & json); void write_temperature_sensor(AsyncWebServerRequest * request, JsonVariant & json); void write_analog_sensor(AsyncWebServerRequest * request, JsonVariant & json);