From 38f00946dab246c7e52f74395e16e512bdbed03e Mon Sep 17 00:00:00 2001 From: proddy Date: Sun, 26 Jul 2020 16:03:06 +0200 Subject: [PATCH] show device info on Web --- .../src/project/EMSESPDevicesController.tsx | 2 +- interface/src/project/EMSESPDevicesForm.tsx | 115 +++++++++++++++--- interface/src/project/EMSESPtypes.ts | 11 ++ media/web_devices.PNG | Bin 42136 -> 59196 bytes src/EMSESPDevicesService.cpp | 40 +++++- src/EMSESPDevicesService.h | 19 +-- src/devices/boiler.cpp | 18 +++ src/devices/boiler.h | 1 + src/devices/connect.cpp | 3 + src/devices/connect.h | 1 + src/devices/controller.cpp | 3 + src/devices/controller.h | 1 + src/devices/gateway.cpp | 3 + src/devices/gateway.h | 1 + src/devices/heatpump.cpp | 3 + src/devices/heatpump.h | 1 + src/devices/mixing.cpp | 3 + src/devices/mixing.h | 1 + src/devices/solar.cpp | 3 + src/devices/solar.h | 1 + src/devices/switch.cpp | 3 + src/devices/switch.h | 1 + src/devices/thermostat.cpp | 46 ++++++- src/devices/thermostat.h | 1 + src/emsdevice.cpp | 13 +- src/emsdevice.h | 47 ++++++- src/emsesp.cpp | 26 +++- src/emsesp.h | 14 ++- src/emsfactory.h | 1 + 29 files changed, 339 insertions(+), 43 deletions(-) diff --git a/interface/src/project/EMSESPDevicesController.tsx b/interface/src/project/EMSESPDevicesController.tsx index 52945963a..dfcb5bf1c 100644 --- a/interface/src/project/EMSESPDevicesController.tsx +++ b/interface/src/project/EMSESPDevicesController.tsx @@ -5,7 +5,7 @@ import { ENDPOINT_ROOT } from '../api'; import EMSESPDevicesForm from './EMSESPDevicesForm'; import { EMSESPDevices } from './EMSESPtypes'; -export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + "emsespDevices"; +export const EMSESP_DEVICES_ENDPOINT = ENDPOINT_ROOT + "allDevices"; type EMSESPDevicesControllerProps = RestControllerProps; diff --git a/interface/src/project/EMSESPDevicesForm.tsx b/interface/src/project/EMSESPDevicesForm.tsx index 41baa437d..2f6c2b83a 100644 --- a/interface/src/project/EMSESPDevicesForm.tsx +++ b/interface/src/project/EMSESPDevicesForm.tsx @@ -24,10 +24,11 @@ import { FormButton, } from "../components"; -import { EMSESPDevices, Device } from "./EMSESPtypes"; +import { EMSESPDevices, EMSESPDeviceData, Device } from "./EMSESPtypes"; import { ENDPOINT_ROOT } from '../api'; export const SCANDEVICES_ENDPOINT = ENDPOINT_ROOT + "scanDevices"; +export const DEVICE_DATA_ENDPOINT = ENDPOINT_ROOT + "deviceData"; const StyledTableCell = withStyles((theme: Theme) => createStyles({ @@ -54,6 +55,7 @@ function compareDevices(a: Device, b: Device) { interface EMSESPDevicesFormState { confirmScanDevices: boolean; processing: boolean; + deviceData?: EMSESPDeviceData; } type EMSESPDevicesFormProps = RestFormProps & AuthenticatedContextProps & WithWidthProps; @@ -65,15 +67,19 @@ class EMSESPDevicesForm extends Component { + noDevices = () => { return (this.props.data.devices.length === 0); }; + noDeviceData = () => { + return (this.state.deviceData?.deviceData.length === 0); + }; + createTableItems() { const { width, data } = this.props; return ( - {!this.noData() && ( + {!this.noDevices() && ( @@ -87,7 +93,9 @@ class EMSESPDevicesForm extends Component {data.devices.sort(compareDevices).map(device => ( - + this.handleRowClick(device.id)} + > {device.type} @@ -111,7 +119,7 @@ class EMSESPDevicesForm extends Component
)} - {this.noData() && + {this.noDevices() && ( @@ -156,26 +164,105 @@ class EMSESPDevicesForm extends Component { this.setState({ processing: true }); - redirectingAuthorizedFetch(SCANDEVICES_ENDPOINT, { method: 'POST' }) - .then(response => { - if (response.status === 200) { - this.props.enqueueSnackbar("Device scan is starting...", { variant: 'info' }); - this.setState({ processing: false, confirmScanDevices: false }); - } else { - throw Error("Invalid status code: " + response.status); - } - }) + redirectingAuthorizedFetch(SCANDEVICES_ENDPOINT).then(response => { + if (response.status === 200) { + this.props.enqueueSnackbar("Device scan is starting...", { variant: 'info' }); + this.setState({ processing: false, confirmScanDevices: false }); + } else { + throw Error("Invalid status code: " + response.status); + } + }) .catch(error => { this.props.enqueueSnackbar(error.message || "Problem with scan", { variant: 'error' }); this.setState({ processing: false, confirmScanDevices: false }); }); } + handleRowClick = (id: any) => { + this.setState({ deviceData: undefined }); + redirectingAuthorizedFetch(DEVICE_DATA_ENDPOINT, { + method: 'POST', + body: JSON.stringify({ id: id }), + headers: { + 'Content-Type': 'application/json' + } + }).then(response => { + if (response.status === 200) { + return response.json(); + // this.setState({ errorMessage: undefined }, this.props.loadData); + } + throw Error("Unexpected response code: " + response.status); + }).then(json => { + this.setState({ deviceData: json }); + }).catch(error => { + this.props.enqueueSnackbar(error.message || "Problem getting device data", { variant: 'error' }); + this.setState({ deviceData: undefined }); + }); + } + + renderDeviceData() { + const { deviceData } = this.state; + const { width } = this.props; + + if (this.noDevices()) { + return ( +

+ ) + } + + if (!deviceData) { + return ( + +

+ Click on a device to show it's values +
+ ); + } + + if ((deviceData.deviceData || []).length === 0) { + return ( +

+ ); + } + + return ( + +

+ + + {deviceData.deviceName} + + + + + + + + + {deviceData.deviceData.map(deviceData => ( + + + {deviceData.name} + + + {deviceData.value} + + + ))} + +
+
+ + ); + + } + render() { return (

{this.createTableItems()} + {this.renderDeviceData()}

diff --git a/interface/src/project/EMSESPtypes.ts b/interface/src/project/EMSESPtypes.ts index 91fed67ee..2e510ab4e 100644 --- a/interface/src/project/EMSESPtypes.ts +++ b/interface/src/project/EMSESPtypes.ts @@ -24,6 +24,7 @@ export interface EMSESPStatus { } export interface Device { + id: number; type: string; brand: string; name: string; @@ -36,3 +37,13 @@ export interface EMSESPDevices { devices: Device[]; } +export interface DeviceData { + name: string; + value: string; +} + +export interface EMSESPDeviceData { + deviceName: string; + deviceData: DeviceData[]; +} + diff --git a/media/web_devices.PNG b/media/web_devices.PNG index 6849689677e5a29af55baa6aa648f55b2154b81c..4a9796a7b94b916b0a65187e8cf95993377a1df9 100644 GIT binary patch literal 59196 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%0DJ*N(^nvH0v8bD;B@_ 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 I>zopr0J!dQ2mk;8 literal 42136 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 gEy=ezc%8s{0tr=TYZh7LFW2U>e!ZvX%Q diff --git a/src/EMSESPDevicesService.cpp b/src/EMSESPDevicesService.cpp index 1ce990286..585b2b4c8 100644 --- a/src/EMSESPDevicesService.cpp +++ b/src/EMSESPDevicesService.cpp @@ -4,22 +4,37 @@ namespace emsesp { -EMSESPDevicesService::EMSESPDevicesService(AsyncWebServer * server, SecurityManager * securityManager) { +EMSESPDevicesService::EMSESPDevicesService(AsyncWebServer * server, SecurityManager * securityManager) + : _timeHandler(DEVICE_DATA_SERVICE_PATH, + securityManager->wrapCallback(std::bind(&EMSESPDevicesService::device_data, this, _1, _2), AuthenticationPredicates::IS_AUTHENTICATED)) { + // body server->on(EMSESP_DEVICES_SERVICE_PATH, HTTP_GET, - securityManager->wrapRequest(std::bind(&EMSESPDevicesService::emsespDevicesService, this, std::placeholders::_1), - AuthenticationPredicates::IS_AUTHENTICATED)); + securityManager->wrapRequest(std::bind(&EMSESPDevicesService::all_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED)); + + server->on(SCAN_DEVICES_SERVICE_PATH, + HTTP_GET, + securityManager->wrapRequest(std::bind(&EMSESPDevicesService::scan_devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED)); + + _timeHandler.setMethod(HTTP_POST); + _timeHandler.setMaxContentLength(256); + server->addHandler(&_timeHandler); } -void EMSESPDevicesService::emsespDevicesService(AsyncWebServerRequest * request) { +void EMSESPDevicesService::scan_devices(AsyncWebServerRequest * request) { + EMSESP::send_read_request(EMSdevice::EMS_TYPE_UBADevices, EMSdevice::EMS_DEVICE_ID_BOILER); + request->send(200); +} + +void EMSESPDevicesService::all_devices(AsyncWebServerRequest * request) { AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_EMSESP_STATUS_SIZE); JsonObject root = response->getRoot(); JsonArray devices = root.createNestedArray("devices"); - for (const auto & emsdevice : EMSESP::emsdevices) { if (emsdevice) { JsonObject deviceRoot = devices.createNestedObject(); + deviceRoot["id"] = emsdevice->unique_id(); deviceRoot["type"] = emsdevice->device_type_name(); deviceRoot["brand"] = emsdevice->brand_to_string(); deviceRoot["name"] = emsdevice->name(); @@ -28,8 +43,23 @@ void EMSESPDevicesService::emsespDevicesService(AsyncWebServerRequest * request) deviceRoot["version"] = emsdevice->version(); } } + response->setLength(); request->send(response); } +void EMSESPDevicesService::device_data(AsyncWebServerRequest * request, JsonVariant & json) { + if (json.is()) { + uint8_t id = json["id"]; // get id from selected table row + + AsyncJsonResponse * response = new AsyncJsonResponse(false, 1024); + EMSESP::device_info(id, (JsonObject &)response->getRoot()); + response->setLength(); + request->send(response); + } else { + AsyncWebServerResponse * response = request->beginResponse(200); + request->send(response); + } +} + } // namespace emsesp \ No newline at end of file diff --git a/src/EMSESPDevicesService.h b/src/EMSESPDevicesService.h index 02f7187f1..db242984e 100644 --- a/src/EMSESPDevicesService.h +++ b/src/EMSESPDevicesService.h @@ -6,23 +6,26 @@ #include #include -// #include -// #include -// #include - -#include "version.h" - #define MAX_EMSESP_STATUS_SIZE 1024 -#define EMSESP_DEVICES_SERVICE_PATH "/rest/emsespDevices" + +#define EMSESP_DEVICES_SERVICE_PATH "/rest/allDevices" +#define SCAN_DEVICES_SERVICE_PATH "/rest/scanDevices" +#define DEVICE_DATA_SERVICE_PATH "/rest/deviceData" namespace emsesp { +using namespace std::placeholders; // for `_1` + class EMSESPDevicesService { public: EMSESPDevicesService(AsyncWebServer * server, SecurityManager * securityManager); private: - void emsespDevicesService(AsyncWebServerRequest * request); + void all_devices(AsyncWebServerRequest * request); + void scan_devices(AsyncWebServerRequest * request); + + AsyncCallbackJsonWebHandler _timeHandler; + void device_data(AsyncWebServerRequest * request, JsonVariant & json); }; } // namespace emsesp diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 44b72d7ba..637c60bba 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -166,6 +166,24 @@ void Boiler::boiler_cmd_wwtemp(const char * message) { } } +void Boiler::device_info(JsonArray & root) { + JsonObject dataElement; + + dataElement = root.createNestedObject(); + dataElement["name"] = F("Hot tap water"); + dataElement["value"] = tap_water_active_ ? F("running") : F("off"); + + dataElement = root.createNestedObject(); + dataElement["name"] = F("Central heating"); + dataElement["value"] = heating_active_ ? F("active") : F("off"); + + render_value_json(root, "", F("Selected flow temperature"), selFlowTemp_, F_(degrees)); + render_value_json(root, "", F("Current flow temperature"), curFlowTemp_, F_(degrees), 10); + render_value_json(root, "", F("Warm Water selected temperature"), wWSelTemp_, F_(degrees)); + render_value_json(root, "", F("Warm Water set temperature"), wWSetTmp_, F_(degrees)); + render_value_json(root, "", F("Warm Water current temperature (intern)"), wWCurTmp_, F_(degrees), 10); +} + // publish values via MQTT void Boiler::publish_values() { const size_t capacity = JSON_OBJECT_SIZE(47); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/ diff --git a/src/devices/boiler.h b/src/devices/boiler.h index 41f7e8160..60e4170e1 100644 --- a/src/devices/boiler.h +++ b/src/devices/boiler.h @@ -40,6 +40,7 @@ class Boiler : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/connect.cpp b/src/devices/connect.cpp index 07fb346c7..d8da0d612 100644 --- a/src/devices/connect.cpp +++ b/src/devices/connect.cpp @@ -34,6 +34,9 @@ Connect::Connect(uint8_t device_type, uint8_t device_id, uint8_t product_id, con // register_mqtt_topic("topic", std::bind(&Connect::cmd, this, _1)); } +void Connect::device_info(JsonArray & root) { +} + void Connect::add_context_menu() { } diff --git a/src/devices/connect.h b/src/devices/connect.h index 37bf8a7e9..51956ef5a 100644 --- a/src/devices/connect.h +++ b/src/devices/connect.h @@ -37,6 +37,7 @@ class Connect : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/controller.cpp b/src/devices/controller.cpp index c7d5727e9..a6796ce8b 100644 --- a/src/devices/controller.cpp +++ b/src/devices/controller.cpp @@ -39,6 +39,9 @@ Controller::Controller(uint8_t device_type, uint8_t device_id, uint8_t product_i void Controller::add_context_menu() { } +void Controller::device_info(JsonArray & root) { +} + // display all values into the shell console void Controller::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header diff --git a/src/devices/controller.h b/src/devices/controller.h index 36866a8f7..d905b3864 100644 --- a/src/devices/controller.h +++ b/src/devices/controller.h @@ -37,6 +37,7 @@ class Controller : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/gateway.cpp b/src/devices/gateway.cpp index 101791f1d..aa8bec0bf 100644 --- a/src/devices/gateway.cpp +++ b/src/devices/gateway.cpp @@ -39,6 +39,9 @@ Gateway::Gateway(uint8_t device_type, uint8_t device_id, uint8_t product_id, con void Gateway::add_context_menu() { } +void Gateway::device_info(JsonArray & root) { +} + // display all values into the shell console void Gateway::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header diff --git a/src/devices/gateway.h b/src/devices/gateway.h index e27eff894..d38dbb32e 100644 --- a/src/devices/gateway.h +++ b/src/devices/gateway.h @@ -37,6 +37,7 @@ class Gateway : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/heatpump.cpp b/src/devices/heatpump.cpp index fec97a61d..14b8e74ea 100644 --- a/src/devices/heatpump.cpp +++ b/src/devices/heatpump.cpp @@ -50,6 +50,9 @@ Heatpump::Heatpump(uint8_t device_type, uint8_t device_id, uint8_t product_id, c void Heatpump::add_context_menu() { } +void Heatpump::device_info(JsonArray & root) { +} + // display all values into the shell console void Heatpump::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header diff --git a/src/devices/heatpump.h b/src/devices/heatpump.h index dda5acd3c..a23921698 100644 --- a/src/devices/heatpump.h +++ b/src/devices/heatpump.h @@ -37,6 +37,7 @@ class Heatpump : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/mixing.cpp b/src/devices/mixing.cpp index 52938aff7..c4ebe6ced 100644 --- a/src/devices/mixing.cpp +++ b/src/devices/mixing.cpp @@ -57,6 +57,9 @@ Mixing::Mixing(uint8_t device_type, uint8_t device_id, uint8_t product_id, const void Mixing::add_context_menu() { } +void Mixing::device_info(JsonArray & root) { +} + // check to see if values have been updated bool Mixing::updated_values() { return false; diff --git a/src/devices/mixing.h b/src/devices/mixing.h index ed1e8ce39..d1c6b09b9 100644 --- a/src/devices/mixing.h +++ b/src/devices/mixing.h @@ -37,6 +37,7 @@ class Mixing : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/solar.cpp b/src/devices/solar.cpp index feb2987c0..d3e9e0c09 100644 --- a/src/devices/solar.cpp +++ b/src/devices/solar.cpp @@ -58,6 +58,9 @@ Solar::Solar(uint8_t device_type, uint8_t device_id, uint8_t product_id, const s void Solar::add_context_menu() { } +void Solar::device_info(JsonArray & root) { +} + // display all values into the shell console void Solar::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header diff --git a/src/devices/solar.h b/src/devices/solar.h index 5a1be5e5b..55b3e398a 100644 --- a/src/devices/solar.h +++ b/src/devices/solar.h @@ -37,6 +37,7 @@ class Solar : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/switch.cpp b/src/devices/switch.cpp index f86858fff..c7a160260 100644 --- a/src/devices/switch.cpp +++ b/src/devices/switch.cpp @@ -39,6 +39,9 @@ Switch::Switch(uint8_t device_type, uint8_t device_id, uint8_t product_id, const void Switch::add_context_menu() { } +void Switch::device_info(JsonArray & root) { +} + // display all values into the shell console void Switch::show_values(uuid::console::Shell & shell) { EMSdevice::show_values(shell); // always call this to show header diff --git a/src/devices/switch.h b/src/devices/switch.h index cf74014eb..44d9844d6 100644 --- a/src/devices/switch.h +++ b/src/devices/switch.h @@ -37,6 +37,7 @@ class Switch : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 9c52e0760..2978bab35 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -169,6 +169,50 @@ void Thermostat::init_mqtt() { register_mqtt_topic("thermostat_cmd_mode", std::bind(&Thermostat::thermostat_cmd_mode, this, _1)); } +// prepare data for Web UI +void Thermostat::device_info(JsonArray & root) { + JsonObject dataElement; + + uint8_t flags = (this->flags() & 0x0F); // specific thermostat characteristics, strip the option bits + + for (const auto & hc : heating_circuits_) { + if (!Helpers::hasValue(hc->setpoint_roomTemp)) { + break; // skip this HC + } + + // different thermostat types store their temperature values differently + uint8_t format_setpoint, format_curr; + switch (flags) { + case EMS_DEVICE_FLAG_EASY: + format_setpoint = 100; // *100 + format_curr = 100; // *100 + break; + case EMS_DEVICE_FLAG_JUNKERS: + format_setpoint = 10; // *10 + format_curr = 10; // *10 + break; + default: // RC30, RC35 etc... + format_setpoint = 2; // *2 + format_curr = 10; // *10 + break; + } + + // create prefix with heating circuit number + std::string hc_str(5, '\0'); + snprintf_P(&hc_str[0], hc_str.capacity() + 1, PSTR("hc%d: "), hc->hc_num()); + + render_value_json(root, hc_str, F("Current room temperature"), hc->curr_roomTemp, F_(degrees), format_curr); + render_value_json(root, hc_str, F("Setpoint room temperature"), hc->setpoint_roomTemp, F_(degrees), format_setpoint); + if (Helpers::hasValue(hc->mode)) { + dataElement = root.createNestedObject(); + std::string mode_str(15, '\0'); + snprintf_P(&mode_str[0], mode_str.capacity() + 1, PSTR("%sMode"), hc_str.c_str()); + dataElement["name"] = mode_str; + dataElement["value"] = mode_tostring(hc->get_mode(flags)); + } + } +} + // only add the menu for the master thermostat void Thermostat::add_context_menu() { if (device_id() != EMSESP::actual_master_thermostat()) { @@ -1024,8 +1068,6 @@ void Thermostat::show_values(uuid::console::Shell & shell) { } } - // std::sort(heating_circuits_.begin(), heating_circuits_.end()); // sort based on hc number. This has moved to the heating_circuit() function - for (const auto & hc : heating_circuits_) { if (!Helpers::hasValue(hc->setpoint_roomTemp)) { break; // skip this HC diff --git a/src/devices/thermostat.h b/src/devices/thermostat.h index 8f2ea0c76..ee019b87b 100644 --- a/src/devices/thermostat.h +++ b/src/devices/thermostat.h @@ -94,6 +94,7 @@ class Thermostat : public EMSdevice { virtual void show_values(uuid::console::Shell & shell); virtual void publish_values(); + virtual void device_info(JsonArray & root); virtual bool updated_values(); virtual void add_context_menu(); diff --git a/src/emsdevice.cpp b/src/emsdevice.cpp index 16341f8ad..2185b17df 100644 --- a/src/emsdevice.cpp +++ b/src/emsdevice.cpp @@ -127,7 +127,7 @@ uint8_t EMSdevice::decode_brand(uint8_t value) { } } -// print human friendly description of the EMS device +// returns string of a human friendly description of the EMS device std::string EMSdevice::to_string() const { std::string str(160, '\0'); @@ -153,6 +153,17 @@ std::string EMSdevice::to_string() const { return str; } +// returns out brand + device name +std::string EMSdevice::to_string_short() const { + std::string str(160, '\0'); + if (brand_ == Brand::NO_BRAND) { + snprintf_P(&str[0], str.capacity() + 1, PSTR("%s: %s"), device_type_name().c_str(), name_.c_str()); + } else { + snprintf_P(&str[0], str.capacity() + 1, PSTR("%s: %s %s"), device_type_name().c_str(), brand_to_string().c_str(), name_.c_str()); + } + return str; +} + // prints the header for the section void EMSdevice::show_values(uuid::console::Shell & shell) { shell.printfln(F("%s: %s"), device_type_name().c_str(), to_string().c_str()); diff --git a/src/emsdevice.h b/src/emsdevice.h index 5030e1108..2abc3bc42 100644 --- a/src/emsdevice.h +++ b/src/emsdevice.h @@ -102,12 +102,22 @@ class EMSdevice { return name_; } + inline uint8_t unique_id() const { + return unique_id_; + } + + inline void unique_id(uint8_t unique_id) { + unique_id_ = unique_id; + } + std::string brand_to_string() const; static uint8_t decode_brand(uint8_t value); std::string to_string() const; - void show_telegram_handlers(uuid::console::Shell & shell); - void show_mqtt_handlers(uuid::console::Shell & shell); + std::string to_string_short() const; + + void show_telegram_handlers(uuid::console::Shell & shell); + void show_mqtt_handlers(uuid::console::Shell & shell); using process_function_p = std::function)>; void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, process_function_p cb); @@ -126,6 +136,7 @@ class EMSdevice { virtual void publish_values() = 0; virtual bool updated_values() = 0; virtual void add_context_menu() = 0; + virtual void device_info(JsonArray & root) = 0; std::string telegram_type_name(std::shared_ptr telegram); @@ -165,6 +176,37 @@ class EMSdevice { } } + // takes a value from an ems device and creates a nested json (name, value) + // which can be passed to the web UI + template + static void render_value_json(JsonArray & json, + const std::string & prefix, + const __FlashStringHelper * name, + Value & value, + const __FlashStringHelper * suffix, + const uint8_t format = 0) { + char buffer[15]; + if (Helpers::render_value(buffer, value, format) == nullptr) { + return; + } + + JsonObject dataElement = json.createNestedObject(); + + // copy flash into std::strings to ensure arduinojson can reference them without a copy + + if (suffix != nullptr) { + std::string text(20, '\0'); + snprintf_P(&text[0], text.capacity() + 1, PSTR("%s%s"), buffer, uuid::read_flash_string(suffix).c_str()); + dataElement["value"] = text; + } else { + dataElement["value"] = buffer; + } + + std::string text2(100, '\0'); + snprintf_P(&text2[0], text2.capacity() + 1, PSTR("%s%s"), prefix.c_str(), uuid::read_flash_string(name).c_str()); + dataElement["name"] = text2; + } + static void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const __FlashStringHelper * value); static void print_value(uuid::console::Shell & shell, uint8_t padding, const __FlashStringHelper * name, const char * value); @@ -229,6 +271,7 @@ class EMSdevice { static constexpr uint8_t EMS_DEVICE_FLAG_JUNKERS_2 = (1 << 6); // 6th bit set if older models private: + uint8_t unique_id_; uint8_t device_type_ = DeviceType::UNKNOWN; uint8_t device_id_ = 0; uint8_t product_id_ = 0; diff --git a/src/emsesp.cpp b/src/emsesp.cpp index a927dc573..b6e2b6e72 100644 --- a/src/emsesp.cpp +++ b/src/emsesp.cpp @@ -39,9 +39,8 @@ ESP8266React EMSESP::esp8266React(&webServer, &dummyFS); EMSESPSettingsService EMSESP::emsespSettingsService = EMSESPSettingsService(&webServer, &dummyFS, EMSESP::esp8266React.getSecurityManager()); #endif -EMSESPStatusService EMSESP::emsespStatusService = EMSESPStatusService(&webServer, EMSESP::esp8266React.getSecurityManager()); -EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager()); -EMSESPScanDevicesService EMSESP::emsespScanDevicesService = EMSESPScanDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager()); +EMSESPStatusService EMSESP::emsespStatusService = EMSESPStatusService(&webServer, EMSESP::esp8266React.getSecurityManager()); +EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager()); std::vector> EMSESP::emsdevices; // array of all the detected EMS devices std::vector EMSESP::device_library_; // libary of all our known EMS devices so far @@ -63,6 +62,7 @@ uint16_t EMSESP::watch_id_ = WATCH_ID_NONE; / uint8_t EMSESP::watch_ = 0; // trace off bool EMSESP::tap_water_active_ = false; // for when Boiler states we having running warm water. used in Shower() uint32_t EMSESP::last_fetch_ = 0; +uint8_t EMSESP::unique_id_count_ = 0; // for a specific EMS device go and request data values // or if device_id is 0 it will fetch from all our known and active devices @@ -474,6 +474,20 @@ bool EMSESP::process_telegram(std::shared_ptr telegram) { return found; } +// calls the device handler's function to populate a json doc with device info +void EMSESP::device_info(const uint8_t unique_id, JsonObject & root) { + for (const auto & emsdevice : emsdevices) { + if (emsdevice) { + if (emsdevice->unique_id() == unique_id) { + root["deviceName"] = emsdevice->to_string_short(); // can;t use c_str() because of scope + JsonArray data = root.createNestedArray("deviceData"); + emsdevice->device_info(data); + return; + } + } + } +} + // return true if we have this device already registered bool EMSESP::device_exists(const uint8_t device_id) { for (const auto & emsdevice : emsdevices) { @@ -513,6 +527,9 @@ void EMSESP::show_devices(uuid::console::Shell & shell) { // shell.printf(F("[factory ID: %d] "), device_class.first); for (const auto & emsdevice : emsdevices) { if ((emsdevice) && (emsdevice->device_type() == device_class.first)) { +#if defined(EMSESP_DEBUG) + shell.printf(F("[id=%d] "), emsdevice->unique_id()); +#endif shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str()); if ((emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT) && (emsdevice->device_id() == actual_master_thermostat())) { shell.printf(F(" ** master device **")); @@ -584,6 +601,7 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, std:: } else { emsdevices.push_back( EMSFactory::add(device_p->device_type, device_id, device_p->product_id, version, uuid::read_flash_string(device_p->name), device_p->flags, brand)); + emsdevices.back()->unique_id(++unique_id_count_); LOG_DEBUG(F("Adding new device with device ID 0x%02X with product ID %d and version %s"), device_id, product_id, version.c_str()); // go and fetch its data, fetch_device_values(device_id); @@ -745,11 +763,11 @@ void EMSESP::loop() { } system_.loop(); // does LED and checks system health, and syslog service - mqtt_.loop(); // starts mqtt, and sends out anything in the queue rxservice_.loop(); // process what ever is in the rx queue txservice_.loop(); // check that the Tx is all ok shower_.loop(); // check for shower on/off sensors_.loop(); // this will also send out via MQTT + mqtt_.loop(); // sends out anything in the queue via MQTT console_.loop(); // telnet/serial console // force a query on the EMS devices to fetch latest data at a set interval (1 min) diff --git a/src/emsesp.h b/src/emsesp.h index 9829c002a..28d62c860 100644 --- a/src/emsesp.h +++ b/src/emsesp.h @@ -37,7 +37,6 @@ #include "EMSESPStatusService.h" #include "EMSESPDevicesService.h" #include "EMSESPSettingsService.h" -#include "EMSESPScanDevicesService.h" #include "emsdevice.h" #include "emsfactory.h" @@ -82,6 +81,8 @@ class EMSESP { static void send_raw_telegram(const char * data); static bool device_exists(const uint8_t device_id); + static void device_info(const uint8_t unique_id, JsonObject & root); + static uint8_t count_devices(const uint8_t device_type); static uint8_t actual_master_thermostat(); @@ -146,11 +147,10 @@ class EMSESP { static TxService txservice_; // web controllers - static ESP8266React esp8266React; - static EMSESPSettingsService emsespSettingsService; - static EMSESPStatusService emsespStatusService; - static EMSESPDevicesService emsespDevicesService; - static EMSESPScanDevicesService emsespScanDevicesService; + static ESP8266React esp8266React; + static EMSESPSettingsService emsespSettingsService; + static EMSESPStatusService emsespStatusService; + static EMSESPDevicesService emsespDevicesService; static uuid::log::Logger logger() { return logger_; @@ -182,6 +182,8 @@ class EMSESP { static uint16_t watch_id_; static uint8_t watch_; static bool tap_water_active_; + + static uint8_t unique_id_count_; }; } // namespace emsesp diff --git a/src/emsfactory.h b/src/emsfactory.h index ede08d8fe..50b2d0afe 100644 --- a/src/emsfactory.h +++ b/src/emsfactory.h @@ -89,6 +89,7 @@ class ConcreteEMSFactory : EMSFactory { ConcreteEMSFactory(const uint8_t device_type) { EMSFactory::registerFactory(device_type, this); } + auto construct(uint8_t device_type, uint8_t device_id, uint8_t product_id, std::string version, std::string name, uint8_t flags, uint8_t brand) const -> EMSdevice * { return new DerivedClass(device_type, device_id, product_id, version, name, flags, brand);