mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-07 00:09:51 +03:00
refactor commands to its own class, implement rest API #506
This commit is contained in:
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- support for uploading compressed firmware binaries
|
- support for uploading compressed firmware binaries
|
||||||
- add wWType to MQTT publish
|
- add wWType to MQTT publish
|
||||||
- option to set the MQTT retain flag
|
- option to set the MQTT retain flag
|
||||||
|
- HTTP REST API, e.g. http://ems-esp/api?device=boiler&cmd=wwtemp&data=20&id=1
|
||||||
|
- `show commands` command
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- fix wwontime readback
|
- fix wwontime readback
|
||||||
@@ -21,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
- renamed wWCircPumpType to wWChargeType
|
- renamed wWCircPumpType to wWChargeType
|
||||||
- Installation doc moved to wiki
|
- Installation doc moved to wiki
|
||||||
|
- Removed the _cmd from the MQTT topic names
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
-
|
-
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ class DummySettings {
|
|||||||
String jwtSecret = "ems-esp";
|
String jwtSecret = "ems-esp";
|
||||||
String ssid = "ems-esp";
|
String ssid = "ems-esp";
|
||||||
String password = "ems-esp";
|
String password = "ems-esp";
|
||||||
|
String localIP;
|
||||||
|
String gatewayIP;
|
||||||
|
String subnetMask;
|
||||||
|
String staticIPConfig;
|
||||||
|
String dnsIP1;
|
||||||
|
String dnsIP2;
|
||||||
uint16_t publish_time_boiler;
|
uint16_t publish_time_boiler;
|
||||||
uint16_t publish_time_thermostat;
|
uint16_t publish_time_thermostat;
|
||||||
uint16_t publish_time_solar;
|
uint16_t publish_time_solar;
|
||||||
@@ -105,4 +111,11 @@ class EMSESPSettingsService {
|
|||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class JsonUtils {
|
||||||
|
public:
|
||||||
|
static void writeIP(JsonObject & root, const String & key, const String & ip) {
|
||||||
|
root[key] = ip;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,39 @@ class AsyncWebServerRequest;
|
|||||||
class AsyncWebServerResponse;
|
class AsyncWebServerResponse;
|
||||||
class AsyncJsonResponse;
|
class AsyncJsonResponse;
|
||||||
|
|
||||||
|
class AsyncWebParameter {
|
||||||
|
private:
|
||||||
|
String _name;
|
||||||
|
String _value;
|
||||||
|
size_t _size;
|
||||||
|
bool _isForm;
|
||||||
|
bool _isFile;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncWebParameter(const String & name, const String & value, bool form = false, bool file = false, size_t size = 0)
|
||||||
|
: _name(name)
|
||||||
|
, _value(value)
|
||||||
|
, _size(size)
|
||||||
|
, _isForm(form)
|
||||||
|
, _isFile(file) {
|
||||||
|
}
|
||||||
|
const String & name() const {
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
const String & value() const {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
bool isPost() const {
|
||||||
|
return _isForm;
|
||||||
|
}
|
||||||
|
bool isFile() const {
|
||||||
|
return _isFile;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_GET = 0b00000001,
|
HTTP_GET = 0b00000001,
|
||||||
HTTP_POST = 0b00000010,
|
HTTP_POST = 0b00000010,
|
||||||
@@ -54,9 +87,41 @@ class AsyncWebServerRequest {
|
|||||||
void send(AsyncWebServerResponse * response){};
|
void send(AsyncWebServerResponse * response){};
|
||||||
void send(AsyncJsonResponse * response){};
|
void send(AsyncJsonResponse * response){};
|
||||||
void send(int code, const String & contentType = String(), const String & content = String()){};
|
void send(int code, const String & contentType = String(), const String & content = String()){};
|
||||||
|
void send(int code, const String & contentType, const __FlashStringHelper *){};
|
||||||
|
|
||||||
|
bool hasParam(const String & name, bool post, bool file) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasParam(const char * name, bool post, bool file) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasParam(const __FlashStringHelper * data) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasParam(const __FlashStringHelper * data, bool post, bool file) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebParameter * getParam(const String & name, bool post, bool file) const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebParameter * getParam(const __FlashStringHelper * data, bool post, bool file) const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebParameter * getParam(const __FlashStringHelper * data) const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
AsyncWebParameter * getParam(size_t num) const {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse * beginResponse(int code, const String & contentType = String(), const String & content = String()) {
|
AsyncWebServerResponse * beginResponse(int code, const String & contentType = String(), const String & content = String()) {
|
||||||
// AsyncWebServerResponse *a = new AsyncWebServerResponse()
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,14 +33,13 @@ class String {
|
|||||||
return lhs;
|
return lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
bool isEmpty() {
|
bool isEmpty() {
|
||||||
return _str.empty();
|
return _str.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// long toInt() const {
|
long toInt() const {
|
||||||
// return std::stol(_str);
|
return std::stol(_str);
|
||||||
// }
|
}
|
||||||
|
|
||||||
bool equals(const char * s) {
|
bool equals(const char * s) {
|
||||||
return _str == s;
|
return _str == s;
|
||||||
|
|||||||
103
src/EMSESPAPIService.cpp
Normal file
103
src/EMSESPAPIService.cpp
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||||
|
* Copyright 2019 Paul Derbyshire
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "EMSESPAPIService.h"
|
||||||
|
#include "emsesp.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "emsdevice.h"
|
||||||
|
#include "system.h"
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
EMSESPAPIService::EMSESPAPIService(AsyncWebServer * server) {
|
||||||
|
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, std::bind(&EMSESPAPIService::emsespAPIService, this, std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://ems-esp/api?device=boiler&cmd=wwtemp&data=20&id=1
|
||||||
|
void EMSESPAPIService::emsespAPIService(AsyncWebServerRequest * request) {
|
||||||
|
// must have device and cmd parameters
|
||||||
|
if ((!request->hasParam(F_(device))) || (!request->hasParam(F_(cmd)))) {
|
||||||
|
request->send(400, "text/plain", F("invalid syntax"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get device
|
||||||
|
String device = request->getParam(F_(device))->value();
|
||||||
|
uint8_t device_type = EMSdevice::device_name_2_device_type(device.c_str());
|
||||||
|
if (device_type == emsesp::EMSdevice::DeviceType::UNKNOWN) {
|
||||||
|
request->send(400, "text/plain", F("invalid device"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get cmd, we know we have one
|
||||||
|
String cmd = request->getParam(F_(cmd))->value();
|
||||||
|
|
||||||
|
// first test for special service commands
|
||||||
|
// e.g. http://ems-esp/api?device=system&cmd=info
|
||||||
|
if (device.equals("system")) {
|
||||||
|
if (cmd.equals("info")) {
|
||||||
|
request->send(200, "text/plain", System::export_settings());
|
||||||
|
EMSESP::logger().info(F("Sent settings json to web UI"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// look up command in our list
|
||||||
|
if (!Command::find(device_type, cmd.c_str())) {
|
||||||
|
request->send(400, "text/plain", F("invalid cmd"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data;
|
||||||
|
if (request->hasParam(F_(data))) {
|
||||||
|
data = request->getParam(F_(data))->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
String id;
|
||||||
|
if (request->hasParam(F_(id))) {
|
||||||
|
id = request->getParam(F_(id))->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute the command
|
||||||
|
bool ok = false;
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
ok = Command::call_command(device_type, cmd.c_str(), nullptr, -1); // command only
|
||||||
|
} else if (id.isEmpty()) {
|
||||||
|
ok = Command::call_command(device_type, cmd.c_str(), data.c_str(), -1); // only ID
|
||||||
|
} else {
|
||||||
|
ok = Command::call_command(device_type, cmd.c_str(), data.c_str(), id.toInt()); // has cmd, data and id
|
||||||
|
}
|
||||||
|
|
||||||
|
// debug
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
|
std::string output(200, '\0');
|
||||||
|
snprintf_P(&output[0],
|
||||||
|
output.capacity() + 1,
|
||||||
|
PSTR("API: device=%s cmd=%s data=%s id=%s [%s]"),
|
||||||
|
device.c_str(),
|
||||||
|
cmd.c_str(),
|
||||||
|
data.c_str(),
|
||||||
|
id.c_str(),
|
||||||
|
ok ? F("OK") : F("Failed"));
|
||||||
|
EMSESP::logger().info(output.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
request->send(200, "text/plain", ok ? F("OK") : F("Failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
41
src/EMSESPAPIService.h
Normal file
41
src/EMSESPAPIService.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||||
|
* Copyright 2019 Paul Derbyshire
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMSESPAPIService_h
|
||||||
|
#define EMSESPAPIService_h
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <AsyncJson.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#define EMSESP_API_SERVICE_PATH "/api"
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
class EMSESPAPIService {
|
||||||
|
public:
|
||||||
|
EMSESPAPIService(AsyncWebServer * server);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void emsespAPIService(AsyncWebServerRequest * request);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include "EMSESPDevicesService.h"
|
#include "EMSESPDevicesService.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
#include "mqtt.h"
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -57,7 +56,7 @@ void EMSESPDevicesService::all_devices(AsyncWebServerRequest * request) {
|
|||||||
obj["type"] = emsdevice->device_type_name();
|
obj["type"] = emsdevice->device_type_name();
|
||||||
obj["brand"] = emsdevice->brand_to_string();
|
obj["brand"] = emsdevice->brand_to_string();
|
||||||
obj["name"] = emsdevice->name();
|
obj["name"] = emsdevice->name();
|
||||||
obj["deviceid"] = emsdevice->get_device_id();
|
obj["deviceid"] = emsdevice->device_id();
|
||||||
obj["productid"] = emsdevice->product_id();
|
obj["productid"] = emsdevice->product_id();
|
||||||
obj["version"] = emsdevice->version();
|
obj["version"] = emsdevice->version();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,6 @@
|
|||||||
|
|
||||||
#include "EMSESPStatusService.h"
|
#include "EMSESPStatusService.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
#include "mqtt.h"
|
|
||||||
#include "version.h"
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
|
|||||||
186
src/command.cpp
Normal file
186
src/command.cpp
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||||
|
* Copyright 2019 Paul Derbyshire
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "command.h"
|
||||||
|
#include "emsdevice.h"
|
||||||
|
#include "emsesp.h"
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
uuid::log::Logger Command::logger_{F_(command), uuid::log::Facility::DAEMON};
|
||||||
|
|
||||||
|
std::vector<Command::CmdFunction> Command::cmdfunctions_;
|
||||||
|
|
||||||
|
// calls a command, context is the device_type
|
||||||
|
// id may be used to represent a heating circuit for example
|
||||||
|
// returns false if error or not found
|
||||||
|
bool Command::call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
||||||
|
#ifdef EMSESP_DEBUG
|
||||||
|
if (id == -1) {
|
||||||
|
LOG_DEBUG(F("[DEBUG] Calling command %s, value %s, id is default"), cmd, value);
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(F("[DEBUG] Calling command %s, value %s, id is %d"), cmd, value, id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!cmdfunctions_.empty()) {
|
||||||
|
for (const auto & cf : cmdfunctions_) {
|
||||||
|
if (cf.device_type_ == device_type) {
|
||||||
|
const char * cf_cmd = uuid::read_flash_string(cf.cmd_).c_str();
|
||||||
|
if (strcmp(cf_cmd, cmd) == 0) {
|
||||||
|
return ((cf.cmdfunction_)(value, id)); // call function, data needs to be a string and can be null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a command to the list
|
||||||
|
void Command::add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb) {
|
||||||
|
cmdfunctions_.emplace_back(device_type, device_id, cmd, cb);
|
||||||
|
|
||||||
|
// see if we need to subscribe
|
||||||
|
Mqtt::register_command(device_type, device_id, cmd, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
// see if a command exists for that device type
|
||||||
|
bool Command::find(const uint8_t device_type, const char * cmd) {
|
||||||
|
for (const auto & cf : cmdfunctions_) {
|
||||||
|
if (strcmp(cmd, uuid::read_flash_string(cf.cmd_).c_str()) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
// output list of all commands to console for a specific DeviceType
|
||||||
|
void Command::show_commands(uuid::console::Shell & shell, uint8_t device_type) {
|
||||||
|
for (const auto & cf : Command::commands()) {
|
||||||
|
if (cf.device_type_ == device_type) {
|
||||||
|
shell.printf("%s ", uuid::read_flash_string(cf.cmd_).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
// determines the device_type from the shell context we're in
|
||||||
|
uint8_t Command::context_2_device_type(unsigned int context) {
|
||||||
|
if (context == ShellContext::MAIN) {
|
||||||
|
return EMSdevice::DeviceType::SERVICEKEY;
|
||||||
|
}
|
||||||
|
if (context == ShellContext::BOILER) {
|
||||||
|
return EMSdevice::DeviceType::BOILER;
|
||||||
|
}
|
||||||
|
if (context == ShellContext::MIXING) {
|
||||||
|
return EMSdevice::DeviceType::MIXING;
|
||||||
|
}
|
||||||
|
if (context == ShellContext::SOLAR) {
|
||||||
|
return EMSdevice::DeviceType::SOLAR;
|
||||||
|
}
|
||||||
|
if (context == ShellContext::SYSTEM) {
|
||||||
|
return EMSdevice::DeviceType::SERVICEKEY;
|
||||||
|
}
|
||||||
|
if (context == ShellContext::THERMOSTAT) {
|
||||||
|
return EMSdevice::DeviceType::THERMOSTAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EMSdevice::DeviceType::UNKNOWN; // unknown type
|
||||||
|
}
|
||||||
|
|
||||||
|
// show command per current context
|
||||||
|
void Command::show_commands(uuid::console::Shell & shell) {
|
||||||
|
show_commands(shell, context_2_device_type(shell.context()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// output list of all commands to console
|
||||||
|
void Command::show_all_commands(uuid::console::Shell & shell) {
|
||||||
|
// show system first
|
||||||
|
shell.printf("%s: ", EMSdevice::device_type_2_device_name(EMSdevice::DeviceType::SERVICEKEY).c_str());
|
||||||
|
show_commands(shell, EMSdevice::DeviceType::SERVICEKEY);
|
||||||
|
|
||||||
|
// do this in the order of factory classes to keep a consistent order when displaying
|
||||||
|
for (const auto & device_class : EMSFactory::device_handlers()) {
|
||||||
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
|
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
||||||
|
shell.printf("%s: ", EMSdevice::device_type_2_device_name(device_class.first).c_str());
|
||||||
|
show_commands(shell, device_class.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// given a context, automatically add the commands to the console
|
||||||
|
void Command::add_context_commands(unsigned int context) {
|
||||||
|
// if we're adding commands for a thermostat or mixing, then include an additional optional paramter called heating circuit
|
||||||
|
flash_string_vector params;
|
||||||
|
if ((context == ShellContext::THERMOSTAT) || (context == ShellContext::MIXING)) {
|
||||||
|
params = flash_string_vector{F_(cmd_optional), F_(data_optional), F_(hc_optional)};
|
||||||
|
} else if ((context == ShellContext::MAIN) || (context == ShellContext::SYSTEM)) {
|
||||||
|
params = flash_string_vector{F_(cmd_optional), F_(data_optional), F_(n_optional)};
|
||||||
|
} else {
|
||||||
|
params = flash_string_vector{F_(cmd_optional), F_(data_optional)};
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSESPShell::commands->add_command(
|
||||||
|
context,
|
||||||
|
CommandFlags::ADMIN,
|
||||||
|
flash_string_vector{F_(call)},
|
||||||
|
params,
|
||||||
|
[&](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
|
if (arguments.empty()) {
|
||||||
|
// list options
|
||||||
|
shell.print("Available commands: ");
|
||||||
|
show_commands(shell);
|
||||||
|
shell.println();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the device_type from the shell context
|
||||||
|
uint8_t device_type = context_2_device_type(shell.context());
|
||||||
|
|
||||||
|
const char * cmd = arguments[0].c_str();
|
||||||
|
if (arguments.size() == 1) {
|
||||||
|
// no value specified
|
||||||
|
(void)Command::call_command(device_type, cmd, nullptr, -1);
|
||||||
|
} else if (arguments.size() == 2) {
|
||||||
|
// has a value but no id
|
||||||
|
(void)Command::call_command(device_type, cmd, arguments.back().c_str(), -1);
|
||||||
|
} else {
|
||||||
|
// use value, which could be an id or hc
|
||||||
|
(void)Command::call_command(device_type, cmd, arguments[1].c_str(), atoi(arguments[2].c_str()));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
|
||||||
|
if (arguments.size() > 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<std::string> commands;
|
||||||
|
uint8_t device_type = context_2_device_type(shell.context());
|
||||||
|
for (const auto & cf : Command::commands()) {
|
||||||
|
if (cf.device_type_ == device_type) {
|
||||||
|
commands.emplace_back(uuid::read_flash_string(cf.cmd_));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return commands;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
77
src/command.h
Normal file
77
src/command.h
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* EMS-ESP - https://github.com/proddy/EMS-ESP
|
||||||
|
* Copyright 2019 Paul Derbyshire
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMSESP_COMMAND_H_
|
||||||
|
#define EMSESP_COMMAND_H_
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
#include <uuid/log.h>
|
||||||
|
|
||||||
|
using uuid::console::Shell;
|
||||||
|
|
||||||
|
namespace emsesp {
|
||||||
|
|
||||||
|
using cmdfunction_p = std::function<bool(const char * data, const int8_t id)>;
|
||||||
|
|
||||||
|
class Command {
|
||||||
|
public:
|
||||||
|
struct CmdFunction {
|
||||||
|
uint8_t device_type_; // DeviceType::
|
||||||
|
uint8_t device_id_;
|
||||||
|
const __FlashStringHelper * cmd_;
|
||||||
|
cmdfunction_p cmdfunction_;
|
||||||
|
|
||||||
|
CmdFunction(uint8_t device_type, uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cmdfunction)
|
||||||
|
: device_type_(device_type)
|
||||||
|
, device_id_(device_id)
|
||||||
|
, cmd_(cmd)
|
||||||
|
, cmdfunction_(cmdfunction) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<CmdFunction> commands() {
|
||||||
|
return cmdfunctions_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id);
|
||||||
|
static void add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb);
|
||||||
|
static void show_all_commands(uuid::console::Shell & shell);
|
||||||
|
static void show_commands(uuid::console::Shell & shell);
|
||||||
|
static void add_context_commands(unsigned int context);
|
||||||
|
static bool find(const uint8_t device_type, const char * cmd);
|
||||||
|
|
||||||
|
static std::vector<CmdFunction> cmdfunctions_; // list of commands
|
||||||
|
|
||||||
|
private:
|
||||||
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
|
static void show_commands(uuid::console::Shell & shell, uint8_t device_type);
|
||||||
|
static uint8_t context_2_device_type(unsigned int context);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace emsesp
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -149,6 +149,12 @@ void EMSESPShell::add_console_commands() {
|
|||||||
flash_string_vector{F_(show), F_(mqtt)},
|
flash_string_vector{F_(show), F_(mqtt)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Mqtt::show_mqtt(shell); });
|
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Mqtt::show_mqtt(shell); });
|
||||||
|
|
||||||
|
|
||||||
|
commands->add_command(ShellContext::MAIN,
|
||||||
|
CommandFlags::USER,
|
||||||
|
flash_string_vector{F_(show), F_(commands)},
|
||||||
|
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Command::show_all_commands(shell); });
|
||||||
|
|
||||||
commands->add_command(
|
commands->add_command(
|
||||||
ShellContext::MAIN,
|
ShellContext::MAIN,
|
||||||
CommandFlags::ADMIN,
|
CommandFlags::ADMIN,
|
||||||
@@ -457,6 +463,11 @@ void Console::load_standard_commands(unsigned int context) {
|
|||||||
shell.printfln(F("Filtering only telegrams that match a device ID or telegram type of 0x%02X"), watch_id);
|
shell.printfln(F("Filtering only telegrams that match a device ID or telegram type of 0x%02X"), watch_id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// load the commands (console & mqtt topics) for this specific context
|
||||||
|
Command::add_context_commands(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prompt, change per context
|
// prompt, change per context
|
||||||
|
|||||||
@@ -52,22 +52,22 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const
|
|||||||
register_telegram_type(0xE9, F("UBADHWStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBADHWStatus(t); });
|
register_telegram_type(0xE9, F("UBADHWStatus"), false, [&](std::shared_ptr<const Telegram> t) { process_UBADHWStatus(t); });
|
||||||
register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameterWWPlus(t); });
|
register_telegram_type(0xEA, F("UBAParameterWWPlus"), true, [&](std::shared_ptr<const Telegram> t) { process_UBAParameterWWPlus(t); });
|
||||||
|
|
||||||
// MQTT commands for boiler_cmd topic
|
// MQTT commands for boiler topic
|
||||||
register_mqtt_cmd(F("comfort"), [&](const char * value, const int8_t id) { set_warmwater_mode(value, id); });
|
register_mqtt_cmd(F("comfort"), [&](const char * value, const int8_t id) { return set_warmwater_mode(value, id); });
|
||||||
register_mqtt_cmd(F("wwactivated"), [&](const char * value, const int8_t id) { set_warmwater_activated(value, id); });
|
register_mqtt_cmd(F("wwactivated"), [&](const char * value, const int8_t id) { return set_warmwater_activated(value, id); });
|
||||||
register_mqtt_cmd(F("wwtapactivated"), [&](const char * value, const int8_t id) { set_tapwarmwater_activated(value, id); });
|
register_mqtt_cmd(F("wwtapactivated"), [&](const char * value, const int8_t id) { return set_tapwarmwater_activated(value, id); });
|
||||||
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { set_warmwater_onetime(value, id); });
|
register_mqtt_cmd(F("wwonetime"), [&](const char * value, const int8_t id) { return set_warmwater_onetime(value, id); });
|
||||||
register_mqtt_cmd(F("wwcirculation"), [&](const char * value, const int8_t id) { set_warmwater_circulation(value, id); });
|
register_mqtt_cmd(F("wwcirculation"), [&](const char * value, const int8_t id) { return set_warmwater_circulation(value, id); });
|
||||||
register_mqtt_cmd(F("flowtemp"), [&](const char * value, const int8_t id) { set_flow_temp(value, id); });
|
register_mqtt_cmd(F("flowtemp"), [&](const char * value, const int8_t id) { return set_flow_temp(value, id); });
|
||||||
register_mqtt_cmd(F("wwtemp"), [&](const char * value, const int8_t id) { set_warmwater_temp(value, id); });
|
register_mqtt_cmd(F("wwtemp"), [&](const char * value, const int8_t id) { return set_warmwater_temp(value, id); });
|
||||||
register_mqtt_cmd(F("heatingactivated"), [&](const char * value, const int8_t id) { set_heating_activated(value, id); });
|
register_mqtt_cmd(F("heatingactivated"), [&](const char * value, const int8_t id) { return set_heating_activated(value, id); });
|
||||||
register_mqtt_cmd(F("heatingtemp"), [&](const char * value, const int8_t id) { set_heating_temp(value, id); });
|
register_mqtt_cmd(F("heatingtemp"), [&](const char * value, const int8_t id) { return set_heating_temp(value, id); });
|
||||||
register_mqtt_cmd(F("burnmaxpower"), [&](const char * value, const int8_t id) { set_max_power(value, id); });
|
register_mqtt_cmd(F("burnmaxpower"), [&](const char * value, const int8_t id) { return set_max_power(value, id); });
|
||||||
register_mqtt_cmd(F("burnminpower"), [&](const char * value, const int8_t id) { set_min_power(value, id); });
|
register_mqtt_cmd(F("burnminpower"), [&](const char * value, const int8_t id) { return set_min_power(value, id); });
|
||||||
register_mqtt_cmd(F("boilhyston"), [&](const char * value, const int8_t id) { set_hyst_on(value, id); });
|
register_mqtt_cmd(F("boilhyston"), [&](const char * value, const int8_t id) { return set_hyst_on(value, id); });
|
||||||
register_mqtt_cmd(F("boilhystoff"), [&](const char * value, const int8_t id) { set_hyst_off(value, id); });
|
register_mqtt_cmd(F("boilhystoff"), [&](const char * value, const int8_t id) { return set_hyst_off(value, id); });
|
||||||
register_mqtt_cmd(F("burnperiod"), [&](const char * value, const int8_t id) { set_burn_period(value, id); });
|
register_mqtt_cmd(F("burnperiod"), [&](const char * value, const int8_t id) { return set_burn_period(value, id); });
|
||||||
register_mqtt_cmd(F("pumpdelay"), [&](const char * value, const int8_t id) { set_pump_delay(value, id); });
|
register_mqtt_cmd(F("pumpdelay"), [&](const char * value, const int8_t id) { return set_pump_delay(value, id); });
|
||||||
|
|
||||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
||||||
mqtt_format_ = settings.mqtt_format; // single, nested or ha
|
mqtt_format_ = settings.mqtt_format; // single, nested or ha
|
||||||
@@ -85,7 +85,6 @@ void Boiler::add_context_menu() {
|
|||||||
flash_string_vector{F_(boiler)},
|
flash_string_vector{F_(boiler)},
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
Boiler::console_commands(shell, ShellContext::BOILER);
|
Boiler::console_commands(shell, ShellContext::BOILER);
|
||||||
add_context_commands(ShellContext::BOILER);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,16 +764,11 @@ void Boiler::process_UBAMaintenanceData(std::shared_ptr<const Telegram> telegram
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Commands
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Set the warm water temperature 0x33
|
// Set the warm water temperature 0x33
|
||||||
void Boiler::set_warmwater_temp(const char * value, const int8_t id) {
|
bool Boiler::set_warmwater_temp(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler warm water temperature to %d C"), v);
|
LOG_INFO(F("Setting boiler warm water temperature to %d C"), v);
|
||||||
@@ -784,24 +778,28 @@ void Boiler::set_warmwater_temp(const char * value, const int8_t id) {
|
|||||||
write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW);
|
write_command(EMS_TYPE_UBAParameterWW, 2, v, EMS_TYPE_UBAParameterWW);
|
||||||
write_command(EMS_TYPE_UBAFlags, 3, v, EMS_TYPE_UBAParameterWW); // for i9000, see #397
|
write_command(EMS_TYPE_UBAFlags, 3, v, EMS_TYPE_UBAParameterWW); // for i9000, see #397
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// flow temp
|
// flow temp
|
||||||
void Boiler::set_flow_temp(const char * value, const int8_t id) {
|
bool Boiler::set_flow_temp(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler flow temperature to %d C"), v);
|
LOG_INFO(F("Setting boiler flow temperature to %d C"), v);
|
||||||
write_command(EMS_TYPE_UBASetPoints, 0, v, EMS_TYPE_UBASetPoints);
|
write_command(EMS_TYPE_UBASetPoints, 0, v, EMS_TYPE_UBASetPoints);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set min boiler output
|
// set min boiler output
|
||||||
void Boiler::set_heating_activated(const char * value, const int8_t id) {
|
bool Boiler::set_heating_activated(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (!Helpers::value2bool(value, v)) {
|
if (!Helpers::value2bool(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_INFO(F("Setting boiler heating "), v ? "on" : "off");
|
LOG_INFO(F("Setting boiler heating "), v ? "on" : "off");
|
||||||
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
||||||
@@ -809,41 +807,49 @@ void Boiler::set_heating_activated(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 0, v ? 0xFF : 0, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 0, v ? 0xFF : 0, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set heating maximum temperature
|
// set heating maximum temperature
|
||||||
void Boiler::set_heating_temp(const char * value, const int8_t id) {
|
bool Boiler::set_heating_temp(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler heating temperature to "), v);
|
LOG_INFO(F("Setting boiler heating temperature to "), v);
|
||||||
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
||||||
write_command(EMS_TYPE_UBAParametersPlus, 1, v, EMS_TYPE_UBAParametersPlus);
|
write_command(EMS_TYPE_UBAParametersPlus, 1, v, EMS_TYPE_UBAParametersPlus);
|
||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 1, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 1, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set min boiler output
|
// set min boiler output
|
||||||
void Boiler::set_min_power(const char * value, const int8_t id) {
|
bool Boiler::set_min_power(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler min power to "), v);
|
LOG_INFO(F("Setting boiler min power to "), v);
|
||||||
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
if (get_toggle_fetch(EMS_TYPE_UBAParametersPlus)) {
|
||||||
write_command(EMS_TYPE_UBAParametersPlus, 7, v, EMS_TYPE_UBAParametersPlus);
|
write_command(EMS_TYPE_UBAParametersPlus, 7, v, EMS_TYPE_UBAParametersPlus);
|
||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 3, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 3, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set max temp
|
// set max temp
|
||||||
void Boiler::set_max_power(const char * value, const int8_t id) {
|
bool Boiler::set_max_power(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler max power to %d C"), v);
|
LOG_INFO(F("Setting boiler max power to %d C"), v);
|
||||||
@@ -852,13 +858,15 @@ void Boiler::set_max_power(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 2, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 2, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set boiler on hysteresis
|
// set boiler on hysteresis
|
||||||
void Boiler::set_hyst_on(const char * value, const int8_t id) {
|
bool Boiler::set_hyst_on(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler hysteresis on to %d C"), v);
|
LOG_INFO(F("Setting boiler hysteresis on to %d C"), v);
|
||||||
@@ -867,13 +875,15 @@ void Boiler::set_hyst_on(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 5, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 5, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set boiler off hysteresis
|
// set boiler off hysteresis
|
||||||
void Boiler::set_hyst_off(const char * value, const int8_t id) {
|
bool Boiler::set_hyst_off(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler hysteresis off to %d C"), v);
|
LOG_INFO(F("Setting boiler hysteresis off to %d C"), v);
|
||||||
@@ -882,13 +892,15 @@ void Boiler::set_hyst_off(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 4, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 4, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set min burner period
|
// set min burner period
|
||||||
void Boiler::set_burn_period(const char * value, const int8_t id) {
|
bool Boiler::set_burn_period(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting burner min. period to %d min"), v);
|
LOG_INFO(F("Setting burner min. period to %d min"), v);
|
||||||
@@ -897,30 +909,36 @@ void Boiler::set_burn_period(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameters, 6, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 6, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set pump delay
|
// set pump delay
|
||||||
void Boiler::set_pump_delay(const char * value, const int8_t id) {
|
bool Boiler::set_pump_delay(const char * value, const int8_t id) {
|
||||||
int v = 0;
|
int v = 0;
|
||||||
if (!Helpers::value2number(value, v)) {
|
if (!Helpers::value2number(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_toggle_fetch(EMS_TYPE_UBAParameters)) {
|
if (get_toggle_fetch(EMS_TYPE_UBAParameters)) {
|
||||||
LOG_INFO(F("Setting boiler pump delay to %d min"), v);
|
LOG_INFO(F("Setting boiler pump delay to %d min"), v);
|
||||||
write_command(EMS_TYPE_UBAParameters, 8, v, EMS_TYPE_UBAParameters);
|
write_command(EMS_TYPE_UBAParameters, 8, v, EMS_TYPE_UBAParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note some boilers do not have this setting, than it's done by thermostat
|
// note some boilers do not have this setting, than it's done by thermostat
|
||||||
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) 1=hot, 2=eco, 3=intelligent
|
// on a RC35 it's by EMSESP::send_write_request(0x37, 0x10, 2, &set, 1, 0); (set is 1,2,3) 1=hot, 2=eco, 3=intelligent
|
||||||
void Boiler::set_warmwater_mode(const char * value, const int8_t id) {
|
bool Boiler::set_warmwater_mode(const char * value, const int8_t id) {
|
||||||
if (value == nullptr) {
|
if (value == nullptr) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_toggle_fetch(EMS_TYPE_UBAParameterWW)) {
|
if (!get_toggle_fetch(EMS_TYPE_UBAParameterWW)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t set;
|
uint8_t set;
|
||||||
if (strcmp(value, "hot") == 0) {
|
if (strcmp(value, "hot") == 0) {
|
||||||
LOG_INFO(F("Setting boiler warm water to Hot"));
|
LOG_INFO(F("Setting boiler warm water to Hot"));
|
||||||
@@ -932,16 +950,18 @@ void Boiler::set_warmwater_mode(const char * value, const int8_t id) {
|
|||||||
LOG_INFO(F("Setting boiler warm water to Intelligent"));
|
LOG_INFO(F("Setting boiler warm water to Intelligent"));
|
||||||
set = 0xEC;
|
set = 0xEC;
|
||||||
} else {
|
} else {
|
||||||
return; // do nothing
|
return false; // do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
write_command(EMS_TYPE_UBAParameterWW, 9, set, EMS_TYPE_UBAParameterWW);
|
write_command(EMS_TYPE_UBAParameterWW, 9, set, EMS_TYPE_UBAParameterWW);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn on/off warm water
|
// turn on/off warm water
|
||||||
void Boiler::set_warmwater_activated(const char * value, const int8_t id) {
|
bool Boiler::set_warmwater_activated(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (!Helpers::value2bool(value, v)) {
|
if (!Helpers::value2bool(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler warm water %s"), v ? "on" : "off");
|
LOG_INFO(F("Setting boiler warm water %s"), v ? "on" : "off");
|
||||||
@@ -953,19 +973,22 @@ void Boiler::set_warmwater_activated(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
n = (v ? 0xFF : 0x00); // 0xFF is on, 0x00 is off
|
n = (v ? 0xFF : 0x00); // 0xFF is on, 0x00 is off
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) {
|
if (get_toggle_fetch(EMS_TYPE_UBAParameterWWPlus)) {
|
||||||
write_command(EMS_TYPE_UBAParameterWWPlus, 1, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus);
|
write_command(EMS_TYPE_UBAParameterWWPlus, 1, v ? 1 : 0, EMS_TYPE_UBAParameterWWPlus);
|
||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAParameterWW, 1, n, EMS_TYPE_UBAParameterWW);
|
write_command(EMS_TYPE_UBAParameterWW, 1, n, EMS_TYPE_UBAParameterWW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate / De-activate the Warm Tap Water
|
// Activate / De-activate the Warm Tap Water
|
||||||
// Note: Using the type 0x1D to put the boiler into Test mode. This may be shown on the boiler with a flashing 'T'
|
// Note: Using the type 0x1D to put the boiler into Test mode. This may be shown on the boiler with a flashing 'T'
|
||||||
void Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) {
|
bool Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (!Helpers::value2bool(value, v)) {
|
if (!Helpers::value2bool(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting tap warm tap water %s"), v ? "on" : "off");
|
LOG_INFO(F("Setting tap warm tap water %s"), v ? "on" : "off");
|
||||||
@@ -990,15 +1013,17 @@ void Boiler::set_tapwarmwater_activated(const char * value, const int8_t id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write_command(EMS_TYPE_UBAFunctionTest, 0, message_data, sizeof(message_data), 0);
|
write_command(EMS_TYPE_UBAFunctionTest, 0, message_data, sizeof(message_data), 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate / De-activate One Time warm water 0x35
|
// Activate / De-activate One Time warm water 0x35
|
||||||
// true = on, false = off
|
// true = on, false = off
|
||||||
// See also https://github.com/proddy/EMS-ESP/issues/341#issuecomment-596245458 for Junkers
|
// See also https://github.com/proddy/EMS-ESP/issues/341#issuecomment-596245458 for Junkers
|
||||||
void Boiler::set_warmwater_onetime(const char * value, const int8_t id) {
|
bool Boiler::set_warmwater_onetime(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (!Helpers::value2bool(value, v)) {
|
if (!Helpers::value2bool(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler warm water OneTime loading %s"), v ? "on" : "off");
|
LOG_INFO(F("Setting boiler warm water OneTime loading %s"), v ? "on" : "off");
|
||||||
@@ -1007,14 +1032,16 @@ void Boiler::set_warmwater_onetime(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAFlags, 0, (v ? 0x22 : 0x02), 0x34);
|
write_command(EMS_TYPE_UBAFlags, 0, (v ? 0x22 : 0x02), 0x34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate / De-activate circulation of warm water 0x35
|
// Activate / De-activate circulation of warm water 0x35
|
||||||
// true = on, false = off
|
// true = on, false = off
|
||||||
void Boiler::set_warmwater_circulation(const char * value, const int8_t id) {
|
bool Boiler::set_warmwater_circulation(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (!Helpers::value2bool(value, v)) {
|
if (!Helpers::value2bool(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off");
|
LOG_INFO(F("Setting boiler warm water circulation %s"), v ? "on" : "off");
|
||||||
@@ -1023,6 +1050,8 @@ void Boiler::set_warmwater_circulation(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
write_command(EMS_TYPE_UBAFlags, 1, (v ? 0x22 : 0x02), 0x34);
|
write_command(EMS_TYPE_UBAFlags, 1, (v ? 0x22 : 0x02), 0x34);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add console commands
|
// add console commands
|
||||||
@@ -1034,7 +1063,7 @@ void Boiler::console_commands(Shell & shell, unsigned int context) {
|
|||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||||
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
||||||
EMSESP::set_read_id(type_id);
|
EMSESP::set_read_id(type_id);
|
||||||
EMSESP::send_read_request(type_id, get_device_id());
|
EMSESP::send_read_request(type_id, device_id());
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
EMSESPShell::commands->add_command(ShellContext::BOILER,
|
||||||
|
|||||||
@@ -167,21 +167,21 @@ class Boiler : public EMSdevice {
|
|||||||
void process_UBADHWStatus(std::shared_ptr<const Telegram> telegram);
|
void process_UBADHWStatus(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
// commands - none of these use the additional id parameter
|
// commands - none of these use the additional id parameter
|
||||||
void set_warmwater_mode(const char * value, const int8_t id);
|
bool set_warmwater_mode(const char * value, const int8_t id);
|
||||||
void set_warmwater_activated(const char * value, const int8_t id);
|
bool set_warmwater_activated(const char * value, const int8_t id);
|
||||||
void set_tapwarmwater_activated(const char * value, const int8_t id);
|
bool set_tapwarmwater_activated(const char * value, const int8_t id);
|
||||||
void set_warmwater_onetime(const char * value, const int8_t id);
|
bool set_warmwater_onetime(const char * value, const int8_t id);
|
||||||
void set_warmwater_circulation(const char * value, const int8_t id);
|
bool set_warmwater_circulation(const char * value, const int8_t id);
|
||||||
void set_warmwater_temp(const char * value, const int8_t id);
|
bool set_warmwater_temp(const char * value, const int8_t id);
|
||||||
void set_flow_temp(const char * value, const int8_t id);
|
bool set_flow_temp(const char * value, const int8_t id);
|
||||||
void set_heating_activated(const char * value, const int8_t id);
|
bool set_heating_activated(const char * value, const int8_t id);
|
||||||
void set_heating_temp(const char * value, const int8_t id);
|
bool set_heating_temp(const char * value, const int8_t id);
|
||||||
void set_min_power(const char * value, const int8_t id);
|
bool set_min_power(const char * value, const int8_t id);
|
||||||
void set_max_power(const char * value, const int8_t id);
|
bool set_max_power(const char * value, const int8_t id);
|
||||||
void set_hyst_on(const char * value, const int8_t id);
|
bool set_hyst_on(const char * value, const int8_t id);
|
||||||
void set_hyst_off(const char * value, const int8_t id);
|
bool set_hyst_off(const char * value, const int8_t id);
|
||||||
void set_burn_period(const char * value, const int8_t id);
|
bool set_burn_period(const char * value, const int8_t id);
|
||||||
void set_pump_delay(const char * value, const int8_t id);
|
bool set_pump_delay(const char * value, const int8_t id);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ void Mixing::publish_values() {
|
|||||||
|
|
||||||
char topic[30];
|
char topic[30];
|
||||||
strlcpy(topic, "mixing_data", 30);
|
strlcpy(topic, "mixing_data", 30);
|
||||||
strlcat(topic, Helpers::itoa(s, get_device_id() - 0x20 + 1), 30); // append hc to topic
|
strlcat(topic, Helpers::itoa(s, device_id() - 0x20 + 1), 30); // append hc to topic
|
||||||
Mqtt::publish(topic, doc);
|
Mqtt::publish(topic, doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ void Mixing::process_MMPLUSStatusMessage_WWC(std::shared_ptr<const Telegram> tel
|
|||||||
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
// A1 00 FF 00 00 0C 02 04 00 01 1D 00 82
|
||||||
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
void Mixing::process_IPMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
type_ = Type::HC;
|
type_ = Type::HC;
|
||||||
hc_ = get_device_id() - 0x20 + 1;
|
hc_ = device_id() - 0x20 + 1;
|
||||||
uint8_t ismixed = 0;
|
uint8_t ismixed = 0;
|
||||||
changed_ |= telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
changed_ |= telegram->read_value(ismixed, 0); // check if circuit is active, 0-off, 1-unmixed, 2-mixed
|
||||||
if (ismixed == 0) {
|
if (ismixed == 0) {
|
||||||
@@ -213,7 +213,7 @@ void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// the heating circuit is determine by which device_id it is, 0x20 - 0x23
|
// the heating circuit is determine by which device_id it is, 0x20 - 0x23
|
||||||
// 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module
|
// 0x21 is position 2. 0x20 is typically reserved for the WM10 switch module
|
||||||
// see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918
|
// see https://github.com/proddy/EMS-ESP/issues/270 and https://github.com/proddy/EMS-ESP/issues/386#issuecomment-629610918
|
||||||
hc_ = get_device_id() - 0x20 + 1;
|
hc_ = device_id() - 0x20 + 1;
|
||||||
changed_ |= telegram->read_value(flowTemp_, 1); // is * 10
|
changed_ |= telegram->read_value(flowTemp_, 1); // is * 10
|
||||||
changed_ |= telegram->read_value(pump_, 3);
|
changed_ |= telegram->read_value(pump_, 3);
|
||||||
changed_ |= telegram->read_value(flowSetTemp_, 0);
|
changed_ |= telegram->read_value(flowSetTemp_, 0);
|
||||||
@@ -226,7 +226,7 @@ void Mixing::process_MMStatusMessage(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// Mixing on a MM10 - 0xAA
|
// Mixing on a MM10 - 0xAA
|
||||||
// e.g. Thermostat -> Mixing Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
|
// e.g. Thermostat -> Mixing Module, type 0xAA, telegram: 10 21 AA 00 FF 0C 0A 11 0A 32 xx
|
||||||
void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
|
void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
hc_ = get_device_id() - 0x20 + 1;
|
hc_ = device_id() - 0x20 + 1;
|
||||||
// pos 0: active FF = on
|
// pos 0: active FF = on
|
||||||
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
|
// pos 1: valve runtime 0C = 120 sec in units of 10 sec
|
||||||
}
|
}
|
||||||
@@ -234,7 +234,7 @@ void Mixing::process_MMConfigMessage(std::shared_ptr<const Telegram> telegram) {
|
|||||||
// Mixing on a MM10 - 0xAC
|
// Mixing on a MM10 - 0xAC
|
||||||
// e.g. Thermostat -> Mixing Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
|
// e.g. Thermostat -> Mixing Module, type 0xAC, telegram: 10 21 AC 00 1E 64 01 AB
|
||||||
void Mixing::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
|
void Mixing::process_MMSetMessage(std::shared_ptr<const Telegram> telegram) {
|
||||||
hc_ = get_device_id() - 0x20 + 1;
|
hc_ = device_id() - 0x20 + 1;
|
||||||
// pos 0: flowtemp setpoint 1E = 30°C
|
// pos 0: flowtemp setpoint 1E = 30°C
|
||||||
// pos 1: position in %
|
// pos 1: position in %
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ void Thermostat::device_info_web(JsonArray & root) {
|
|||||||
// context menu "thermostat"
|
// context menu "thermostat"
|
||||||
void Thermostat::add_context_menu() {
|
void Thermostat::add_context_menu() {
|
||||||
// only add it once, to prevent conflicts when there are multiple thermostats
|
// only add it once, to prevent conflicts when there are multiple thermostats
|
||||||
if (this->get_device_id() != EMSESP::actual_master_thermostat()) {
|
if (this->device_id() != EMSESP::actual_master_thermostat()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,6 @@ void Thermostat::add_context_menu() {
|
|||||||
flash_string_vector{F_(thermostat)},
|
flash_string_vector{F_(thermostat)},
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[&](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
||||||
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
|
Thermostat::console_commands(shell, ShellContext::THERMOSTAT);
|
||||||
add_context_commands(ShellContext::THERMOSTAT);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +238,7 @@ void Thermostat::add_context_menu() {
|
|||||||
// we check if any of the thermostat values have changed and then republish if necessary
|
// we check if any of the thermostat values have changed and then republish if necessary
|
||||||
bool Thermostat::updated_values() {
|
bool Thermostat::updated_values() {
|
||||||
// only publish on the master thermostat
|
// only publish on the master thermostat
|
||||||
if (EMSESP::actual_master_thermostat() != this->get_device_id()) {
|
if (EMSESP::actual_master_thermostat() != this->device_id()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (changed_) {
|
if (changed_) {
|
||||||
@@ -252,7 +251,7 @@ bool Thermostat::updated_values() {
|
|||||||
// publish values via MQTT
|
// publish values via MQTT
|
||||||
void Thermostat::publish_values() {
|
void Thermostat::publish_values() {
|
||||||
// only publish on the master thermostat
|
// only publish on the master thermostat
|
||||||
if (EMSESP::actual_master_thermostat() != this->get_device_id()) {
|
if (EMSESP::actual_master_thermostat() != this->device_id()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1191,7 +1190,7 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
|
|||||||
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
[=](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) {
|
||||||
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
uint16_t type_id = Helpers::hextoint(arguments.front().c_str());
|
||||||
EMSESP::set_read_id(type_id);
|
EMSESP::set_read_id(type_id);
|
||||||
EMSESP::send_read_request(type_id, this->get_device_id());
|
EMSESP::send_read_request(type_id, this->device_id());
|
||||||
});
|
});
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
EMSESPShell::commands->add_command(ShellContext::THERMOSTAT,
|
||||||
@@ -1217,50 +1216,61 @@ void Thermostat::console_commands(Shell & shell, unsigned int context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Set minimum external temperature
|
// 0xA5 - Set minimum external temperature
|
||||||
void Thermostat::set_minexttemp(const char * value, const int8_t id) {
|
bool Thermostat::set_minexttemp(const char * value, const int8_t id) {
|
||||||
int mt = 0;
|
int mt = 0;
|
||||||
if (!Helpers::value2number(value, mt)) {
|
if (!Helpers::value2number(value, mt)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting min external temperature to %d"), mt);
|
LOG_INFO(F("Setting min external temperature to %d"), mt);
|
||||||
write_command(EMS_TYPE_IBASettings, 5, mt, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 5, mt, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Clock offset
|
// 0xA5 - Clock offset
|
||||||
void Thermostat::set_clockoffset(const char * value, const int8_t id) {
|
bool Thermostat::set_clockoffset(const char * value, const int8_t id) {
|
||||||
int co = 0;
|
int co = 0;
|
||||||
if (!Helpers::value2number(value, co)) {
|
if (!Helpers::value2number(value, co)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting clock offset to %d"), co);
|
LOG_INFO(F("Setting clock offset to %d"), co);
|
||||||
write_command(EMS_TYPE_IBASettings, 12, co, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 12, co, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Calibrate internal temperature
|
// 0xA5 - Calibrate internal temperature
|
||||||
void Thermostat::set_calinttemp(const char * value, const int8_t id) {
|
bool Thermostat::set_calinttemp(const char * value, const int8_t id) {
|
||||||
int ct = 0;
|
int ct = 0;
|
||||||
if (!Helpers::value2number(value, ct)) {
|
if (!Helpers::value2number(value, ct)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
// does this value need to be multiple by 10?
|
|
||||||
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
|
LOG_INFO(F("Calibrating internal temperature to %d.%d"), ct / 10, ct < 0 ? -ct % 10 : ct % 10);
|
||||||
write_command(EMS_TYPE_IBASettings, 2, ct, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 2, ct, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Set the display settings
|
// 0xA5 - Set the display settings
|
||||||
void Thermostat::set_display(const char * value, const int8_t id) {
|
bool Thermostat::set_display(const char * value, const int8_t id) {
|
||||||
int ds = 0;
|
int ds = 0;
|
||||||
if (!Helpers::value2number(value, ds)) {
|
if (!Helpers::value2number(value, ds)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting display to %d"), ds);
|
LOG_INFO(F("Setting display to %d"), ds);
|
||||||
write_command(EMS_TYPE_IBASettings, 0, ds, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 0, ds, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_remotetemp(const char * value, const int8_t id) {
|
bool Thermostat::set_remotetemp(const char * value, const int8_t id) {
|
||||||
float f = 0;
|
float f = 0;
|
||||||
if (!Helpers::value2float(value, f)) {
|
if (!Helpers::value2float(value, f)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
@@ -1270,13 +1280,15 @@ void Thermostat::set_remotetemp(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
Roomctrl::set_remotetemp(hc_num - 1, (int16_t)(f * 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 - Set the building settings
|
// 0xA5 - Set the building settings
|
||||||
void Thermostat::set_building(const char * value, const int8_t id) {
|
bool Thermostat::set_building(const char * value, const int8_t id) {
|
||||||
std::string bd(20, '\0');
|
std::string bd(20, '\0');
|
||||||
if (!Helpers::value2string(value, bd)) {
|
if (!Helpers::value2string(value, bd)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t bg = 0;
|
uint8_t bg = 0;
|
||||||
@@ -1287,28 +1299,33 @@ void Thermostat::set_building(const char * value, const int8_t id) {
|
|||||||
} else if (bd == "heavy") {
|
} else if (bd == "heavy") {
|
||||||
bg = 2;
|
bg = 2;
|
||||||
} else {
|
} else {
|
||||||
return; // invalid
|
return false; // invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting building to %d"), bg);
|
LOG_INFO(F("Setting building to %d"), bg);
|
||||||
write_command(EMS_TYPE_IBASettings, 6, bg, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 6, bg, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0xA5 Set the language settings
|
// 0xA5 Set the language settings
|
||||||
void Thermostat::set_language(const char * value, const int8_t id) {
|
bool Thermostat::set_language(const char * value, const int8_t id) {
|
||||||
int lg = 0;
|
int lg = 0;
|
||||||
if (!Helpers::value2number(value, lg)) {
|
if (!Helpers::value2number(value, lg)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting language to %d"), lg);
|
LOG_INFO(F("Setting language to %d"), lg);
|
||||||
write_command(EMS_TYPE_IBASettings, 1, lg, EMS_TYPE_IBASettings);
|
write_command(EMS_TYPE_IBASettings, 1, lg, EMS_TYPE_IBASettings);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
|
// Set the control-mode for hc 0-off, 1-RC20, 2-RC3x
|
||||||
void Thermostat::set_control(const char * value, const int8_t id) {
|
bool Thermostat::set_control(const char * value, const int8_t id) {
|
||||||
int ctrl = 0;
|
int ctrl = 0;
|
||||||
if (!Helpers::value2number(value, ctrl)) {
|
if (!Helpers::value2number(value, ctrl)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
@@ -1316,23 +1333,25 @@ void Thermostat::set_control(const char * value, const int8_t id) {
|
|||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num);
|
LOG_WARNING(F("Set control: Heating Circuit %d not found or activated"), hc_num);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl > 2) {
|
if (ctrl > 2) {
|
||||||
LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl);
|
LOG_WARNING(F("Set control: Invalid control mode: %d"), ctrl);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
|
LOG_INFO(F("Setting circuit-control for hc%d to %d"), hc_num, ctrl);
|
||||||
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
|
write_command(set_typeids[hc->hc_num() - 1], 26, ctrl);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the thermostat ww working mode, where mode is a string
|
// sets the thermostat ww working mode, where mode is a string
|
||||||
void Thermostat::set_wwmode(const char * value, const int8_t id) {
|
bool Thermostat::set_wwmode(const char * value, const int8_t id) {
|
||||||
std::string v(10, '\0');
|
std::string v(10, '\0');
|
||||||
if (!Helpers::value2string(value, v)) {
|
if (!Helpers::value2string(value, v)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t set = 0xFF; // some dummy value
|
uint8_t set = 0xFF; // some dummy value
|
||||||
@@ -1350,21 +1369,24 @@ void Thermostat::set_wwmode(const char * value, const int8_t id) {
|
|||||||
} else {
|
} else {
|
||||||
LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), v.c_str());
|
LOG_WARNING(F("Set thermostat warm water mode: Invalid mode: %s"), v.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the holiday as string dd.mm.yyyy-dd.mm.yyyy
|
// set the holiday as string dd.mm.yyyy-dd.mm.yyyy
|
||||||
void Thermostat::set_holiday(const char * value, const int8_t id) {
|
bool Thermostat::set_holiday(const char * value, const int8_t id) {
|
||||||
std::string hd(30, '\0');
|
std::string hd(30, '\0');
|
||||||
if (!Helpers::value2string(value, hd)) {
|
if (!Helpers::value2string(value, hd)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->get_device_id());
|
LOG_WARNING(F("Set holiday: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[6];
|
uint8_t data[6];
|
||||||
data[0] = (hd[0] - '0') * 10 + (hd[1] - '0');
|
data[0] = (hd[0] - '0') * 10 + (hd[1] - '0');
|
||||||
data[1] = (hd[3] - '0') * 10 + (hd[4] - '0');
|
data[1] = (hd[3] - '0') * 10 + (hd[4] - '0');
|
||||||
@@ -1375,49 +1397,56 @@ void Thermostat::set_holiday(const char * value, const int8_t id) {
|
|||||||
|
|
||||||
LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num());
|
LOG_INFO(F("Setting holiday for hc %d"), hc->hc_num());
|
||||||
write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0);
|
write_command(timer_typeids[hc->hc_num() - 1], 87, data, 6, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set pause in hours
|
// set pause in hours
|
||||||
void Thermostat::set_pause(const char * value, const int8_t id) {
|
bool Thermostat::set_pause(const char * value, const int8_t id) {
|
||||||
int hrs = 0;
|
int hrs = 0;
|
||||||
if (!Helpers::value2number(value, hrs)) {
|
if (!Helpers::value2number(value, hrs)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->get_device_id());
|
LOG_WARNING(F("Set pause: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num());
|
LOG_INFO(F("Setting pause: %d hours, hc: %d"), hrs, hc->hc_num());
|
||||||
write_command(timer_typeids[hc->hc_num() - 1], 85, hrs);
|
write_command(timer_typeids[hc->hc_num() - 1], 85, hrs);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set partymode in hours
|
// set partymode in hours
|
||||||
void Thermostat::set_party(const char * value, const int8_t id) {
|
bool Thermostat::set_party(const char * value, const int8_t id) {
|
||||||
int hrs = 0;
|
int hrs = 0;
|
||||||
if (!Helpers::value2number(value, hrs)) {
|
if (!Helpers::value2number(value, hrs)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->get_device_id());
|
LOG_WARNING(F("Set party: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num());
|
LOG_INFO(F("Setting party: %d hours, hc: %d"), hrs, hc->hc_num());
|
||||||
write_command(timer_typeids[hc->hc_num() - 1], 86, hrs);
|
write_command(timer_typeids[hc->hc_num() - 1], 86, hrs);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
|
// set date&time as string hh:mm:ss-dd.mm.yyyy-dw-dst or "NTP" for setting to internet-time
|
||||||
// dw - day of week (0..6), dst- summertime (0/1)
|
// dw - day of week (0..6), dst- summertime (0/1)
|
||||||
// id is ignored
|
// id is ignored
|
||||||
void Thermostat::set_datetime(const char * value, const int8_t id) {
|
bool Thermostat::set_datetime(const char * value, const int8_t id) {
|
||||||
std::string dt(30, '\0');
|
std::string dt(30, '\0');
|
||||||
if (!Helpers::value2string(value, dt)) {
|
if (!Helpers::value2string(value, dt)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t data[9];
|
uint8_t data[9];
|
||||||
@@ -1426,8 +1455,9 @@ void Thermostat::set_datetime(const char * value, const int8_t id) {
|
|||||||
tm * tm_ = localtime(&now);
|
tm * tm_ = localtime(&now);
|
||||||
if (tm_->tm_year < 110) { // no NTP time
|
if (tm_->tm_year < 110) { // no NTP time
|
||||||
LOG_WARNING(F("No NTP time. Cannot set RCtime"));
|
LOG_WARNING(F("No NTP time. Cannot set RCtime"));
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = tm_->tm_year - 100; // Bosch counts from 2000
|
data[0] = tm_->tm_year - 100; // Bosch counts from 2000
|
||||||
data[1] = tm_->tm_mon;
|
data[1] = tm_->tm_mon;
|
||||||
data[2] = tm_->tm_hour;
|
data[2] = tm_->tm_hour;
|
||||||
@@ -1449,53 +1479,65 @@ void Thermostat::set_datetime(const char * value, const int8_t id) {
|
|||||||
data[6] = (dt[20] - '0'); // day of week
|
data[6] = (dt[20] - '0'); // day of week
|
||||||
data[7] = (dt[22] - '0') + 2; // DST and flag
|
data[7] = (dt[22] - '0') + 2; // DST and flag
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(F("Setting date and time"));
|
LOG_INFO(F("Setting date and time"));
|
||||||
write_command(EMS_TYPE_time, 0, data, 8, EMS_TYPE_time);
|
write_command(EMS_TYPE_time, 0, data, 8, EMS_TYPE_time);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the thermostat working mode, where mode is a string
|
// sets the thermostat working mode, where mode is a string
|
||||||
// converts string mode to HeatingCircuit::Mode
|
// converts string mode to HeatingCircuit::Mode
|
||||||
void Thermostat::set_mode(const char * value, const int8_t id) {
|
bool Thermostat::set_mode(const char * value, const int8_t id) {
|
||||||
std::string mode(10, '\0');
|
std::string mode(10, '\0');
|
||||||
if (!Helpers::value2string(value, mode)) {
|
if (!Helpers::value2string(value, mode)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
|
|
||||||
if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) {
|
if (mode_tostring(HeatingCircuit::Mode::OFF) == mode) {
|
||||||
set_mode_n(HeatingCircuit::Mode::OFF, hc_num);
|
return set_mode_n(HeatingCircuit::Mode::OFF, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::MANUAL, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::DAY, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::NIGHT, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::HEAT, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::NOFROST, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::ECO, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::HOLIDAY, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
|
||||||
set_mode_n(HeatingCircuit::Mode::COMFORT, hc_num);
|
|
||||||
} else {
|
|
||||||
LOG_WARNING(F("Invalid mode %s. Cannot set"), mode.c_str());
|
|
||||||
}
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::MANUAL, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::AUTO, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::DAY, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::NIGHT, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::HEAT, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::NOFROST, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::ECO, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::HOLIDAY, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
||||||
|
return set_mode_n(HeatingCircuit::Mode::COMFORT, hc_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARNING(F("Invalid mode %s. Cannot set"), mode.c_str());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the thermostat working mode
|
// Set the thermostat working mode
|
||||||
// mode is HeatingCircuit::Mode
|
// mode is HeatingCircuit::Mode
|
||||||
void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
|
bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
|
||||||
// get hc based on number
|
// get hc based on number
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("set mode: Heating Circuit %d not found or activated"), hc_num);
|
LOG_WARNING(F("set mode: Heating Circuit %d not found or activated"), hc_num);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t set_mode_value, offset;
|
uint8_t set_mode_value, offset;
|
||||||
@@ -1578,47 +1620,61 @@ void Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
|
|||||||
// add the write command to the Tx queue
|
// add the write command to the Tx queue
|
||||||
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
||||||
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
|
write_command(set_typeids[hc->hc_num() - 1], offset, set_mode_value, validate_typeid);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the thermostat temp, where mode is a string
|
// sets the thermostat temp, where mode is a string
|
||||||
void Thermostat::set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num) {
|
bool Thermostat::set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num) {
|
||||||
if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
if (mode_tostring(HeatingCircuit::Mode::MANUAL) == mode) {
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::MANUAL, hc_num);
|
return set_temperature(temperature, HeatingCircuit::Mode::MANUAL, hc_num);
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::AUTO, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::DAY, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::NIGHT, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::COMFORT, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::HEAT, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::ECO, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::NOFROST, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::SUMMER) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::SUMMER, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::OFFSET) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::OFFSET, hc_num);
|
|
||||||
} else if (mode_tostring(HeatingCircuit::Mode::DESIGN) == mode) {
|
|
||||||
set_temperature(temperature, HeatingCircuit::Mode::DESIGN, hc_num);
|
|
||||||
} else {
|
|
||||||
LOG_WARNING(F("Invalid mode %s."), mode.c_str());
|
|
||||||
}
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::AUTO) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::AUTO, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::DAY) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::DAY, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::NIGHT) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::NIGHT, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::COMFORT) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::COMFORT, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::HEAT) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::HEAT, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::ECO) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::ECO, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::NOFROST) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::NOFROST, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::SUMMER) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::SUMMER, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::HOLIDAY) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::HOLIDAY, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::OFFSET) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::OFFSET, hc_num);
|
||||||
|
}
|
||||||
|
if (mode_tostring(HeatingCircuit::Mode::DESIGN) == mode) {
|
||||||
|
return set_temperature(temperature, HeatingCircuit::Mode::DESIGN, hc_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WARNING(F("Invalid mode %s."), mode.c_str());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the temperature of the thermostat
|
// Set the temperature of the thermostat
|
||||||
// the id passed into this function is the heating circuit number
|
// the id passed into this function is the heating circuit number
|
||||||
void Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) {
|
bool Thermostat::set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num) {
|
||||||
// get hc based on number
|
// get hc based on number
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
if (hc == nullptr) {
|
||||||
LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->get_device_id());
|
LOG_WARNING(F("Set temperature: Heating Circuit %d not found or activated for device ID 0x%02X"), hc_num, this->device_id());
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t model = this->model();
|
uint8_t model = this->model();
|
||||||
@@ -1790,75 +1846,80 @@ void Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
|||||||
// add the write command to the Tx queue. value is *2
|
// add the write command to the Tx queue. value is *2
|
||||||
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
||||||
write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
|
write_command(set_typeids[hc->hc_num() - 1], offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for HA specifically when receiving over MQTT
|
// for HA specifically when receiving over MQTT
|
||||||
void Thermostat::thermostat_cmd_temp(const char * message) {
|
bool Thermostat::thermostat_cmd_temp(const char * message) {
|
||||||
float f = strtof((char *)message, 0);
|
float f = strtof((char *)message, 0);
|
||||||
set_temperature(f, HeatingCircuit::Mode::AUTO, AUTO_HEATING_CIRCUIT);
|
return set_temperature(f, HeatingCircuit::Mode::AUTO, AUTO_HEATING_CIRCUIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// for HA specifically when receiving over MQTT
|
// for HA specifically when receiving over MQTT
|
||||||
// message payload holds the text name of the mode e.g. "auto"
|
// message payload holds the text name of the mode e.g. "auto"
|
||||||
void Thermostat::thermostat_cmd_mode(const char * message) {
|
bool Thermostat::thermostat_cmd_mode(const char * message) {
|
||||||
set_mode(message, AUTO_HEATING_CIRCUIT);
|
return set_mode(message, AUTO_HEATING_CIRCUIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_temperature_value(const char * value, const int8_t id, const uint8_t mode) {
|
bool Thermostat::set_temperature_value(const char * value, const int8_t id, const uint8_t mode) {
|
||||||
float f = 0;
|
float f = 0;
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
if (Helpers::value2float(value, f)) {
|
if (Helpers::value2float(value, f)) {
|
||||||
set_temperature(f, mode, hc_num);
|
return set_temperature(f, mode, hc_num);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_temp(const char * value, const int8_t id) {
|
bool Thermostat::set_temp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::AUTO);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::AUTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_nighttemp(const char * value, const int8_t id) {
|
bool Thermostat::set_nighttemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::NIGHT);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::NIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_daytemp(const char * value, const int8_t id) {
|
bool Thermostat::set_daytemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::DAY);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::DAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_comforttemp(const char * value, const int8_t id) {
|
bool Thermostat::set_comforttemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::COMFORT);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::COMFORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_nofrosttemp(const char * value, const int8_t id) {
|
bool Thermostat::set_nofrosttemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::NOFROST);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::NOFROST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_ecotemp(const char * value, const int8_t id) {
|
bool Thermostat::set_ecotemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::ECO);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::ECO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_heattemp(const char * value, const int8_t id) {
|
bool Thermostat::set_heattemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::HEAT);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::HEAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_summertemp(const char * value, const int8_t id) {
|
bool Thermostat::set_summertemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::SUMMER);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::SUMMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_designtemp(const char * value, const int8_t id) {
|
bool Thermostat::set_designtemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::DESIGN);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::DESIGN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_offsettemp(const char * value, const int8_t id) {
|
bool Thermostat::set_offsettemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::OFFSET);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_holidaytemp(const char * value, const int8_t id) {
|
bool Thermostat::set_holidaytemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::HOLIDAY);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::HOLIDAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thermostat::set_manualtemp(const char * value, const int8_t id) {
|
bool Thermostat::set_manualtemp(const char * value, const int8_t id) {
|
||||||
set_temperature_value(value, id, HeatingCircuit::Mode::MANUAL);
|
return set_temperature_value(value, id, HeatingCircuit::Mode::MANUAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// commands for MQTT and Console
|
// commands for MQTT and Console
|
||||||
@@ -1869,48 +1930,48 @@ void Thermostat::add_commands() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// common to all thermostats
|
// common to all thermostats
|
||||||
register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { set_wwmode(value, id); });
|
register_mqtt_cmd(F("wwmode"), [&](const char * value, const int8_t id) { return set_wwmode(value, id); });
|
||||||
register_mqtt_cmd(F("temp"), [&](const char * value, const int8_t id) { set_temp(value, id); });
|
register_mqtt_cmd(F("temp"), [&](const char * value, const int8_t id) { return set_temp(value, id); });
|
||||||
register_mqtt_cmd(F("mode"), [&](const char * value, const int8_t id) { set_mode(value, id); });
|
register_mqtt_cmd(F("mode"), [&](const char * value, const int8_t id) { return set_mode(value, id); });
|
||||||
|
|
||||||
uint8_t model = this->model();
|
uint8_t model = this->model();
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case EMS_DEVICE_FLAG_RC100:
|
case EMS_DEVICE_FLAG_RC100:
|
||||||
case EMS_DEVICE_FLAG_RC300:
|
case EMS_DEVICE_FLAG_RC300:
|
||||||
register_mqtt_cmd(F("manualtemp"), [&](const char * value, const int8_t id) { set_manualtemp(value, id); });
|
register_mqtt_cmd(F("manualtemp"), [&](const char * value, const int8_t id) { return set_manualtemp(value, id); });
|
||||||
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { set_ecotemp(value, id); });
|
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { return set_ecotemp(value, id); });
|
||||||
register_mqtt_cmd(F("comforttemp"), [&](const char * value, const int8_t id) { set_comforttemp(value, id); });
|
register_mqtt_cmd(F("comforttemp"), [&](const char * value, const int8_t id) { return set_comforttemp(value, id); });
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_RC20_2:
|
case EMS_DEVICE_FLAG_RC20_2:
|
||||||
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { set_nighttemp(value, id); });
|
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
|
||||||
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { set_daytemp(value, id); });
|
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); });
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_RC30_1: // only RC30_1
|
case EMS_DEVICE_FLAG_RC30_1: // only RC30_1
|
||||||
register_mqtt_cmd(F("clockoffset"), [&](const char * value, const int8_t id) { set_clockoffset(value, id); });
|
register_mqtt_cmd(F("clockoffset"), [&](const char * value, const int8_t id) { return set_clockoffset(value, id); });
|
||||||
register_mqtt_cmd(F("language"), [&](const char * value, const int8_t id) { set_language(value, id); });
|
register_mqtt_cmd(F("language"), [&](const char * value, const int8_t id) { return set_language(value, id); });
|
||||||
register_mqtt_cmd(F("display"), [&](const char * value, const int8_t id) { set_display(value, id); });
|
register_mqtt_cmd(F("display"), [&](const char * value, const int8_t id) { return set_display(value, id); });
|
||||||
case EMS_DEVICE_FLAG_RC35: // RC30 and RC35
|
case EMS_DEVICE_FLAG_RC35: // RC30 and RC35
|
||||||
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { set_nighttemp(value, id); });
|
register_mqtt_cmd(F("nighttemp"), [&](const char * value, const int8_t id) { return set_nighttemp(value, id); });
|
||||||
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { set_daytemp(value, id); });
|
register_mqtt_cmd(F("daytemp"), [&](const char * value, const int8_t id) { return set_daytemp(value, id); });
|
||||||
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { set_nofrosttemp(value, id); });
|
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
|
||||||
register_mqtt_cmd(F("remotetemp"), [&](const char * value, const int8_t id) { set_remotetemp(value, id); });
|
register_mqtt_cmd(F("remotetemp"), [&](const char * value, const int8_t id) { return set_remotetemp(value, id); });
|
||||||
register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { set_datetime(value, id); });
|
register_mqtt_cmd(F("datetime"), [&](const char * value, const int8_t id) { return set_datetime(value, id); });
|
||||||
register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { set_minexttemp(value, id); });
|
register_mqtt_cmd(F("minexttemp"), [&](const char * value, const int8_t id) { return set_minexttemp(value, id); });
|
||||||
register_mqtt_cmd(F("calinttemp"), [&](const char * value, const int8_t id) { set_calinttemp(value, id); });
|
register_mqtt_cmd(F("calinttemp"), [&](const char * value, const int8_t id) { return set_calinttemp(value, id); });
|
||||||
register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { set_building(value, id); });
|
register_mqtt_cmd(F("building"), [&](const char * value, const int8_t id) { return set_building(value, id); });
|
||||||
register_mqtt_cmd(F("control"), [&](const char * value, const int8_t id) { set_control(value, id); });
|
register_mqtt_cmd(F("control"), [&](const char * value, const int8_t id) { return set_control(value, id); });
|
||||||
register_mqtt_cmd(F("pause"), [&](const char * value, const int8_t id) { set_pause(value, id); });
|
register_mqtt_cmd(F("pause"), [&](const char * value, const int8_t id) { return set_pause(value, id); });
|
||||||
register_mqtt_cmd(F("party"), [&](const char * value, const int8_t id) { set_party(value, id); });
|
register_mqtt_cmd(F("party"), [&](const char * value, const int8_t id) { return set_party(value, id); });
|
||||||
register_mqtt_cmd(F("holiday"), [&](const char * value, const int8_t id) { set_holiday(value, id); });
|
register_mqtt_cmd(F("holiday"), [&](const char * value, const int8_t id) { return set_holiday(value, id); });
|
||||||
register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { set_summertemp(value, id); });
|
register_mqtt_cmd(F("summertemp"), [&](const char * value, const int8_t id) { return set_summertemp(value, id); });
|
||||||
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { set_designtemp(value, id); });
|
register_mqtt_cmd(F("designtemp"), [&](const char * value, const int8_t id) { return set_designtemp(value, id); });
|
||||||
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { set_offsettemp(value, id); });
|
register_mqtt_cmd(F("offsettemp"), [&](const char * value, const int8_t id) { return set_offsettemp(value, id); });
|
||||||
register_mqtt_cmd(F("holidaytemp"), [&](const char * value, const int8_t id) { set_holidaytemp(value, id); });
|
register_mqtt_cmd(F("holidaytemp"), [&](const char * value, const int8_t id) { return set_holidaytemp(value, id); });
|
||||||
break;
|
break;
|
||||||
case EMS_DEVICE_FLAG_JUNKERS:
|
case EMS_DEVICE_FLAG_JUNKERS:
|
||||||
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { set_nofrosttemp(value, id); });
|
register_mqtt_cmd(F("nofrosttemp"), [&](const char * value, const int8_t id) { return set_nofrosttemp(value, id); });
|
||||||
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { set_ecotemp(value, id); });
|
register_mqtt_cmd(F("ecotemp"), [&](const char * value, const int8_t id) { return set_ecotemp(value, id); });
|
||||||
register_mqtt_cmd(F("heattemp"), [&](const char * value, const int8_t id) { set_heattemp(value, id); });
|
register_mqtt_cmd(F("heattemp"), [&](const char * value, const int8_t id) { return set_heattemp(value, id); });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -246,48 +246,47 @@ class Thermostat : public EMSdevice {
|
|||||||
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
void process_RC300WWmode(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
// internal helper functions
|
// internal helper functions
|
||||||
void set_mode_n(const uint8_t mode, const uint8_t hc_num);
|
bool set_mode_n(const uint8_t mode, const uint8_t hc_num);
|
||||||
|
|
||||||
void set_temperature_value(const char * value, const int8_t id, const uint8_t mode);
|
bool set_temperature_value(const char * value, const int8_t id, const uint8_t mode);
|
||||||
void set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
bool set_temperature(const float temperature, const std::string & mode, const uint8_t hc_num);
|
||||||
void set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
|
bool set_temperature(const float temperature, const uint8_t mode, const uint8_t hc_num);
|
||||||
|
|
||||||
// for HA specifically. MQTT functions.
|
// for HA specifically. MQTT functions.
|
||||||
void thermostat_cmd_temp(const char * message);
|
bool thermostat_cmd_temp(const char * message);
|
||||||
void thermostat_cmd_mode(const char * message);
|
bool thermostat_cmd_mode(const char * message);
|
||||||
|
|
||||||
// set functions - these use the id/hc
|
// set functions - these use the id/hc
|
||||||
void set_mode(const char * value, const int8_t id);
|
bool set_mode(const char * value, const int8_t id);
|
||||||
void set_control(const char * value, const int8_t id);
|
bool set_control(const char * value, const int8_t id);
|
||||||
void set_holiday(const char * value, const int8_t id);
|
bool set_holiday(const char * value, const int8_t id);
|
||||||
void set_pause(const char * value, const int8_t id);
|
bool set_pause(const char * value, const int8_t id);
|
||||||
void set_party(const char * value, const int8_t id);
|
bool set_party(const char * value, const int8_t id);
|
||||||
|
|
||||||
void set_temp(const char * value, const int8_t id);
|
bool set_temp(const char * value, const int8_t id);
|
||||||
void set_nighttemp(const char * value, const int8_t id);
|
bool set_nighttemp(const char * value, const int8_t id);
|
||||||
void set_daytemp(const char * value, const int8_t id);
|
bool set_daytemp(const char * value, const int8_t id);
|
||||||
void set_comforttemp(const char * value, const int8_t id);
|
bool set_comforttemp(const char * value, const int8_t id);
|
||||||
void set_nofrosttemp(const char * value, const int8_t id);
|
bool set_nofrosttemp(const char * value, const int8_t id);
|
||||||
void set_ecotemp(const char * value, const int8_t id);
|
bool set_ecotemp(const char * value, const int8_t id);
|
||||||
void set_heattemp(const char * value, const int8_t id);
|
bool set_heattemp(const char * value, const int8_t id);
|
||||||
void set_summertemp(const char * value, const int8_t id);
|
bool set_summertemp(const char * value, const int8_t id);
|
||||||
void set_designtemp(const char * value, const int8_t id);
|
bool set_designtemp(const char * value, const int8_t id);
|
||||||
void set_offsettemp(const char * value, const int8_t id);
|
bool set_offsettemp(const char * value, const int8_t id);
|
||||||
void set_holidaytemp(const char * value, const int8_t id);
|
bool set_holidaytemp(const char * value, const int8_t id);
|
||||||
void set_manualtemp(const char * value, const int8_t id);
|
bool set_manualtemp(const char * value, const int8_t id);
|
||||||
|
bool set_remotetemp(const char * value, const int8_t id);
|
||||||
void set_remotetemp(const char * value, const int8_t id);
|
|
||||||
|
|
||||||
// set functions - these don't use the id/hc, the parameters are ignored
|
// set functions - these don't use the id/hc, the parameters are ignored
|
||||||
void set_wwmode(const char * value, const int8_t id);
|
bool set_wwmode(const char * value, const int8_t id);
|
||||||
void set_datetime(const char * value, const int8_t id);
|
bool set_datetime(const char * value, const int8_t id);
|
||||||
void set_minexttemp(const char * value, const int8_t id);
|
bool set_minexttemp(const char * value, const int8_t id);
|
||||||
void set_clockoffset(const char * value, const int8_t id);
|
bool set_clockoffset(const char * value, const int8_t id);
|
||||||
void set_calinttemp(const char * value, const int8_t id);
|
bool set_calinttemp(const char * value, const int8_t id);
|
||||||
void set_display(const char * value, const int8_t id);
|
bool set_display(const char * value, const int8_t id);
|
||||||
void set_building(const char * value, const int8_t id);
|
bool set_building(const char * value, const int8_t id);
|
||||||
void set_language(const char * value, const int8_t id);
|
bool set_language(const char * value, const int8_t id);
|
||||||
}; // namespace emsesp
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
|
|
||||||
#include "emsdevice.h"
|
#include "emsdevice.h"
|
||||||
#include "emsesp.h"
|
#include "emsesp.h"
|
||||||
#include "mqtt.h" // for the mqtt_function_p
|
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -54,30 +53,30 @@ std::string EMSdevice::brand_to_string() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns the name of the MQTT topic to use for a specific device
|
// returns the name of the MQTT topic to use for a specific device
|
||||||
std::string EMSdevice::device_type_topic_name(const uint8_t device_type) {
|
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
|
||||||
switch (device_type) {
|
switch (device_type) {
|
||||||
case DeviceType::SERVICEKEY:
|
case DeviceType::SERVICEKEY:
|
||||||
return read_flash_string(F("system_cmd"));
|
return read_flash_string(F("system"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceType::BOILER:
|
case DeviceType::BOILER:
|
||||||
return read_flash_string(F("boiler_cmd"));
|
return read_flash_string(F("boiler"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceType::THERMOSTAT:
|
case DeviceType::THERMOSTAT:
|
||||||
return read_flash_string(F("thermostat_cmd"));
|
return read_flash_string(F("thermostat"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceType::HEATPUMP:
|
case DeviceType::HEATPUMP:
|
||||||
return read_flash_string(F("heatpump_cmd"));
|
return read_flash_string(F("heatpump"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceType::SOLAR:
|
case DeviceType::SOLAR:
|
||||||
return read_flash_string(F("solar_cmd"));
|
return read_flash_string(F("solar"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceType::MIXING:
|
case DeviceType::MIXING:
|
||||||
return read_flash_string(F("mixing_cmd"));
|
return read_flash_string(F("mixing"));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -86,6 +85,35 @@ std::string EMSdevice::device_type_topic_name(const uint8_t device_type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns device_type from a string
|
||||||
|
uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
|
||||||
|
if (strcmp(topic, "boiler") == 0) {
|
||||||
|
return DeviceType::BOILER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(topic, "thermostat") == 0) {
|
||||||
|
return DeviceType::THERMOSTAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(topic, "system") == 0) {
|
||||||
|
return DeviceType::SERVICEKEY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(topic, "heatpump") == 0) {
|
||||||
|
return DeviceType::HEATPUMP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(topic, "solar") == 0) {
|
||||||
|
return DeviceType::SOLAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(topic, "mixing") == 0) {
|
||||||
|
return DeviceType::MIXING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DeviceType::UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
std::string EMSdevice::device_type_name() const {
|
std::string EMSdevice::device_type_name() const {
|
||||||
switch (device_type_) {
|
switch (device_type_) {
|
||||||
case DeviceType::BOILER:
|
case DeviceType::BOILER:
|
||||||
@@ -202,7 +230,7 @@ void EMSdevice::show_values(uuid::console::Shell & shell) {
|
|||||||
|
|
||||||
// for each telegram that has the fetch value set (true) do a read request
|
// for each telegram that has the fetch value set (true) do a read request
|
||||||
void EMSdevice::fetch_values() {
|
void EMSdevice::fetch_values() {
|
||||||
LOG_DEBUG(F("Fetching values for device ID 0x%02X"), get_device_id());
|
LOG_DEBUG(F("Fetching values for device ID 0x%02X"), device_id());
|
||||||
|
|
||||||
for (const auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if (tf.fetch_) {
|
if (tf.fetch_) {
|
||||||
@@ -213,7 +241,7 @@ void EMSdevice::fetch_values() {
|
|||||||
|
|
||||||
// toggle on/off automatic fetch for a telegram id
|
// toggle on/off automatic fetch for a telegram id
|
||||||
void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
|
void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
|
||||||
LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), get_device_id(), telegram_id, toggle);
|
LOG_DEBUG(F("Toggling fetch for device ID 0x%02X, telegram ID 0x%02X to %d"), device_id(), telegram_id, toggle);
|
||||||
|
|
||||||
for (auto & tf : telegram_functions_) {
|
for (auto & tf : telegram_functions_) {
|
||||||
if (tf.telegram_type_id_ == telegram_id) {
|
if (tf.telegram_type_id_ == telegram_id) {
|
||||||
@@ -226,7 +254,7 @@ void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
|
|||||||
bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) {
|
bool EMSdevice::get_toggle_fetch(uint16_t telegram_id) {
|
||||||
for (auto & tf : telegram_functions_) {
|
for (auto & tf : telegram_functions_) {
|
||||||
if (tf.telegram_type_id_ == telegram_id) {
|
if (tf.telegram_type_id_ == telegram_id) {
|
||||||
return tf.fetch_ ;
|
return tf.fetch_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -256,8 +284,9 @@ void EMSdevice::register_mqtt_topic(const std::string & topic, mqtt_subfunction_
|
|||||||
Mqtt::subscribe(this->device_type_, topic, f);
|
Mqtt::subscribe(this->device_type_, topic, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, mqtt_cmdfunction_p f) {
|
// add command to library
|
||||||
Mqtt::add_command(this->device_type_, this->device_id_, cmd, f);
|
void EMSdevice::register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f) {
|
||||||
|
Command::add_command(this->device_type_, this->device_id_, cmd, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// register a call back function for a specific telegram type
|
// register a call back function for a specific telegram type
|
||||||
@@ -306,22 +335,22 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
|
|
||||||
// send Tx write with a data block
|
// send Tx write with a data block
|
||||||
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid) {
|
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid) {
|
||||||
EMSESP::send_write_request(type_id, this->get_device_id(), offset, message_data, message_length, validate_typeid);
|
EMSESP::send_write_request(type_id, this->device_id(), offset, message_data, message_length, validate_typeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx write with a single value
|
// send Tx write with a single value
|
||||||
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) {
|
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) {
|
||||||
EMSESP::send_write_request(type_id, this->get_device_id(), offset, value, validate_typeid);
|
EMSESP::send_write_request(type_id, this->device_id(), offset, value, validate_typeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx write with a single value, with no post validation
|
// send Tx write with a single value, with no post validation
|
||||||
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) {
|
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) {
|
||||||
EMSESP::send_write_request(type_id, this->get_device_id(), offset, value, 0);
|
EMSESP::send_write_request(type_id, this->device_id(), offset, value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx read command to the device
|
// send Tx read command to the device
|
||||||
void EMSdevice::read_command(const uint16_t type_id) {
|
void EMSdevice::read_command(const uint16_t type_id) {
|
||||||
EMSESP::send_read_request(type_id, get_device_id());
|
EMSESP::send_read_request(type_id, device_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
// prints a string value to the console
|
// prints a string value to the console
|
||||||
@@ -339,60 +368,4 @@ void EMSdevice::print_value(uuid::console::Shell & shell, uint8_t padding, const
|
|||||||
shell.printfln(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
shell.printfln(PSTR("%s: %s"), uuid::read_flash_string(name).c_str(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// given a context, automatically add the commands taken them from the MQTT registry for "<device_type>_cmd" topics
|
|
||||||
void EMSdevice::add_context_commands(unsigned int context) {
|
|
||||||
// if we're adding commands for a thermostat or mixing, then include an additional optional paramter called heating circuit
|
|
||||||
flash_string_vector params;
|
|
||||||
if ((context == ShellContext::THERMOSTAT) || (context == ShellContext::MIXING)) {
|
|
||||||
params = flash_string_vector{F_(cmd_optional), F_(data_optional), F_(hc_optional)};
|
|
||||||
} else {
|
|
||||||
params = flash_string_vector{F_(cmd_optional), F_(data_optional)};
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(
|
|
||||||
context,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(call)},
|
|
||||||
params,
|
|
||||||
[&](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
uint8_t device_type_ = device_type();
|
|
||||||
if (arguments.empty()) {
|
|
||||||
// list options
|
|
||||||
shell.print("Available commands:");
|
|
||||||
for (const auto & cf : Mqtt::commands()) {
|
|
||||||
if (cf.device_type_ == device_type_) {
|
|
||||||
shell.printf(" %s", uuid::read_flash_string(cf.cmd_).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shell.println();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char * cmd = arguments[0].c_str();
|
|
||||||
if (arguments.size() == 1) {
|
|
||||||
// no value specified
|
|
||||||
Mqtt::call_command(device_type_, cmd, nullptr, -1);
|
|
||||||
} else if (arguments.size() == 2) {
|
|
||||||
// has a value but no id
|
|
||||||
Mqtt::call_command(device_type_, cmd, arguments.back().c_str(), -1);
|
|
||||||
} else {
|
|
||||||
// use value, which could be an id or hc
|
|
||||||
Mqtt::call_command(device_type_, cmd, arguments[1].c_str(), atoi(arguments[2].c_str()));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[&](Shell & shell __attribute__((unused)), const std::vector<std::string> & arguments) -> std::vector<std::string> {
|
|
||||||
if (arguments.size() > 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
std::vector<std::string> commands;
|
|
||||||
for (const auto & cf : Mqtt::commands()) {
|
|
||||||
if (cf.device_type_ == device_type()) {
|
|
||||||
commands.emplace_back(uuid::read_flash_string(cf.cmd_));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commands;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
@@ -47,12 +47,13 @@ class EMSdevice {
|
|||||||
|
|
||||||
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
virtual ~EMSdevice() = default; // destructor of base class must always be virtual because it's a polymorphic class
|
||||||
|
|
||||||
inline uint8_t get_device_id() const {
|
inline uint8_t device_id() const {
|
||||||
return device_id_;
|
return device_id_;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string device_type_name() const;
|
std::string device_type_name() const;
|
||||||
static std::string device_type_topic_name(const uint8_t device_type);
|
static std::string device_type_2_device_name(const uint8_t device_type);
|
||||||
|
static uint8_t device_name_2_device_type(const char * topic);
|
||||||
|
|
||||||
inline uint8_t product_id() const {
|
inline uint8_t product_id() const {
|
||||||
return product_id_;
|
return product_id_;
|
||||||
@@ -127,13 +128,10 @@ class EMSdevice {
|
|||||||
void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid);
|
void write_command(const uint16_t type_id, const uint8_t offset, uint8_t * message_data, const uint8_t message_length, const uint16_t validate_typeid);
|
||||||
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid);
|
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid);
|
||||||
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value);
|
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value);
|
||||||
|
|
||||||
void read_command(const uint16_t type_id);
|
void read_command(const uint16_t type_id);
|
||||||
|
|
||||||
void add_context_commands(unsigned int context);
|
|
||||||
|
|
||||||
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
void register_mqtt_topic(const std::string & topic, mqtt_subfunction_p f);
|
||||||
void register_mqtt_cmd(const __FlashStringHelper * cmd, mqtt_cmdfunction_p f);
|
void register_mqtt_cmd(const __FlashStringHelper * cmd, cmdfunction_p f);
|
||||||
|
|
||||||
// virtual functions overrules by derived classes
|
// virtual functions overrules by derived classes
|
||||||
virtual void show_values(uuid::console::Shell & shell) = 0;
|
virtual void show_values(uuid::console::Shell & shell) = 0;
|
||||||
@@ -230,7 +228,7 @@ class EMSdevice {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum DeviceType : uint8_t {
|
enum DeviceType : uint8_t {
|
||||||
SERVICEKEY = 0, // this is us
|
SERVICEKEY = 0, // this is us (EMS-ESP)
|
||||||
BOILER,
|
BOILER,
|
||||||
THERMOSTAT,
|
THERMOSTAT,
|
||||||
MIXING,
|
MIXING,
|
||||||
@@ -239,8 +237,8 @@ class EMSdevice {
|
|||||||
GATEWAY,
|
GATEWAY,
|
||||||
SWITCH,
|
SWITCH,
|
||||||
CONTROLLER,
|
CONTROLLER,
|
||||||
CONNECT
|
CONNECT,
|
||||||
|
UNKNOWN
|
||||||
};
|
};
|
||||||
|
|
||||||
// device IDs
|
// device IDs
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ EMSESPSettingsService EMSESP::emsespSettingsService = EMSESPSettingsService(&web
|
|||||||
|
|
||||||
EMSESPStatusService EMSESP::emsespStatusService = EMSESPStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
EMSESPStatusService EMSESP::emsespStatusService = EMSESPStatusService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||||
EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
EMSESPDevicesService EMSESP::emsespDevicesService = EMSESPDevicesService(&webServer, EMSESP::esp8266React.getSecurityManager());
|
||||||
|
EMSESPAPIService EMSESP::emsespAPIService = EMSESPAPIService(&webServer);
|
||||||
|
|
||||||
using DeviceFlags = emsesp::EMSdevice;
|
using DeviceFlags = emsesp::EMSdevice;
|
||||||
using DeviceType = emsesp::EMSdevice::DeviceType;
|
using DeviceType = emsesp::EMSdevice::DeviceType;
|
||||||
@@ -615,7 +616,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
|||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
||||||
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
|
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
|
||||||
if ((emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT) && (emsdevice->get_device_id() == actual_master_thermostat())) {
|
if ((emsdevice->device_type() == EMSdevice::DeviceType::THERMOSTAT) && (emsdevice->device_id() == actual_master_thermostat())) {
|
||||||
shell.printf(F(" ** master device **"));
|
shell.printf(F(" ** master device **"));
|
||||||
}
|
}
|
||||||
shell.println();
|
shell.println();
|
||||||
@@ -727,7 +728,7 @@ void EMSESP::send_write_request(const uint16_t type_id, const uint8_t dest, cons
|
|||||||
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
|
// we check if its a complete telegram or just a single byte (which could be a poll or a return status)
|
||||||
// the CRC check is not done here, only when it's added to the Rx queue with add()
|
// the CRC check is not done here, only when it's added to the Rx queue with add()
|
||||||
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
static uint32_t rx_time_ = 0;
|
static uint32_t rx_time_ = 0;
|
||||||
#endif
|
#endif
|
||||||
// check first for echo
|
// check first for echo
|
||||||
@@ -735,9 +736,9 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
|
if (((first_value & 0x7F) == txservice_.ems_bus_id()) && (length > 1)) {
|
||||||
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20
|
// if we ask ourself at roomcontrol for version e.g. 0B 98 02 00 20
|
||||||
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
|
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data);
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
// get_uptime is only updated once per loop, does not give the right time
|
// get_uptime is only updated once per loop, does not give the right time
|
||||||
LOG_TRACE(F("[DEBUG] Echo after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
LOG_TRACE(F("[UART_DEBUG] Echo after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
||||||
#endif
|
#endif
|
||||||
return; // it's an echo
|
return; // it's an echo
|
||||||
}
|
}
|
||||||
@@ -786,14 +787,14 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
|
EMSbus::last_bus_activity(uuid::get_uptime()); // set the flag indication the EMS bus is active
|
||||||
|
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
char s[4];
|
char s[4];
|
||||||
if (first_value & 0x80) {
|
if (first_value & 0x80) {
|
||||||
LOG_TRACE(F("[DEBUG] next Poll %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
LOG_TRACE(F("[UART_DEBUG] next Poll %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
||||||
// time measurement starts here, use millis because get_uptime is only updated once per loop
|
// time measurement starts here, use millis because get_uptime is only updated once per loop
|
||||||
rx_time_ = ::millis();
|
rx_time_ = ::millis();
|
||||||
} else {
|
} else {
|
||||||
LOG_TRACE(F("[DEBUG] Poll ack %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
LOG_TRACE(F("[UART_DEBUG] Poll ack %s after %d ms"), Helpers::hextoa(s, first_value), ::millis() - rx_time_);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// check for poll to us, if so send top message from Tx queue immediately and quit
|
// check for poll to us, if so send top message from Tx queue immediately and quit
|
||||||
@@ -805,8 +806,8 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask());
|
Roomctrl::send(first_value ^ 0x80 ^ rxservice_.ems_mask());
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_UART_DEBUG
|
||||||
LOG_TRACE(F("[DEBUG] Reply after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
LOG_TRACE(F("[UART_DEBUG] Reply after %d ms: %s"), ::millis() - rx_time_, Helpers::data_to_hex(data, length).c_str());
|
||||||
#endif
|
#endif
|
||||||
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); // check if there is a message for the roomcontroller
|
Roomctrl::check((data[1] ^ 0x80 ^ rxservice_.ems_mask()), data); // check if there is a message for the roomcontroller
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "EMSESPStatusService.h"
|
#include "EMSESPStatusService.h"
|
||||||
#include "EMSESPDevicesService.h"
|
#include "EMSESPDevicesService.h"
|
||||||
#include "EMSESPSettingsService.h"
|
#include "EMSESPSettingsService.h"
|
||||||
|
#include "EMSESPAPIService.h"
|
||||||
|
|
||||||
#include "emsdevice.h"
|
#include "emsdevice.h"
|
||||||
#include "emsfactory.h"
|
#include "emsfactory.h"
|
||||||
@@ -47,6 +48,7 @@
|
|||||||
#include "console.h"
|
#include "console.h"
|
||||||
#include "shower.h"
|
#include "shower.h"
|
||||||
#include "roomcontrol.h"
|
#include "roomcontrol.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
#define WATCH_ID_NONE 0 // no watch id set
|
#define WATCH_ID_NONE 0 // no watch id set
|
||||||
|
|
||||||
@@ -162,6 +164,7 @@ class EMSESP {
|
|||||||
static EMSESPSettingsService emsespSettingsService;
|
static EMSESPSettingsService emsespSettingsService;
|
||||||
static EMSESPStatusService emsespStatusService;
|
static EMSESPStatusService emsespStatusService;
|
||||||
static EMSESPDevicesService emsespDevicesService;
|
static EMSESPDevicesService emsespDevicesService;
|
||||||
|
static EMSESPAPIService emsespAPIService;
|
||||||
|
|
||||||
static uuid::log::Logger logger() {
|
static uuid::log::Logger logger() {
|
||||||
return logger_;
|
return logger_;
|
||||||
|
|||||||
@@ -61,11 +61,20 @@ MAKE_PSTR_WORD(ssid)
|
|||||||
MAKE_PSTR_WORD(heartbeat)
|
MAKE_PSTR_WORD(heartbeat)
|
||||||
MAKE_PSTR_WORD(users)
|
MAKE_PSTR_WORD(users)
|
||||||
MAKE_PSTR_WORD(master)
|
MAKE_PSTR_WORD(master)
|
||||||
MAKE_PSTR_WORD(test)
|
|
||||||
MAKE_PSTR_WORD(pin)
|
MAKE_PSTR_WORD(pin)
|
||||||
|
|
||||||
|
#if defined(EMSESP_DEBUG)
|
||||||
|
MAKE_PSTR_WORD(test)
|
||||||
|
#endif
|
||||||
|
|
||||||
// for commands
|
// for commands
|
||||||
MAKE_PSTR_WORD(call)
|
MAKE_PSTR_WORD(call)
|
||||||
|
MAKE_PSTR_WORD(cmd)
|
||||||
|
MAKE_PSTR_WORD(id)
|
||||||
|
MAKE_PSTR_WORD(device)
|
||||||
|
MAKE_PSTR_WORD(data)
|
||||||
|
MAKE_PSTR_WORD(command)
|
||||||
|
MAKE_PSTR_WORD(commands)
|
||||||
|
|
||||||
// devices
|
// devices
|
||||||
MAKE_PSTR_WORD(boiler)
|
MAKE_PSTR_WORD(boiler)
|
||||||
@@ -104,7 +113,6 @@ MAKE_PSTR(degrees, "°C")
|
|||||||
MAKE_PSTR(asterisks, "********")
|
MAKE_PSTR(asterisks, "********")
|
||||||
MAKE_PSTR(n_mandatory, "<n>")
|
MAKE_PSTR(n_mandatory, "<n>")
|
||||||
MAKE_PSTR(n_optional, "[n]")
|
MAKE_PSTR(n_optional, "[n]")
|
||||||
MAKE_PSTR(gpio_mandatory, "<gpio>")
|
|
||||||
MAKE_PSTR(data_optional, "[data]")
|
MAKE_PSTR(data_optional, "[data]")
|
||||||
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
MAKE_PSTR(typeid_mandatory, "<type ID>")
|
||||||
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
MAKE_PSTR(deviceid_mandatory, "<device ID>")
|
||||||
|
|||||||
68
src/mqtt.cpp
68
src/mqtt.cpp
@@ -37,7 +37,6 @@ uint32_t Mqtt::publish_time_other_;
|
|||||||
uint32_t Mqtt::publish_time_sensor_;
|
uint32_t Mqtt::publish_time_sensor_;
|
||||||
|
|
||||||
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
std::vector<Mqtt::MQTTSubFunction> Mqtt::mqtt_subfunctions_;
|
||||||
std::vector<Mqtt::MQTTCmdFunction> Mqtt::mqtt_cmdfunctions_;
|
|
||||||
|
|
||||||
uint16_t Mqtt::mqtt_publish_fails_ = 0;
|
uint16_t Mqtt::mqtt_publish_fails_ = 0;
|
||||||
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
|
size_t Mqtt::maximum_mqtt_messages_ = Mqtt::MAX_MQTT_MESSAGES;
|
||||||
@@ -67,10 +66,9 @@ void Mqtt::subscribe(const uint8_t device_type, const std::string & topic, mqtt_
|
|||||||
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(message->topic), std::move(cb));
|
mqtt_subfunctions_.emplace_back(device_type, std::move(topic), std::move(message->topic), std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds a command and callback function for a specific device
|
// subscribe to the command topic if it doesn't exist yet
|
||||||
void Mqtt::add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb) {
|
void Mqtt::register_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb) {
|
||||||
// subscribe to the command topic if it doesn't exist yet
|
std::string cmd_topic = EMSdevice::device_type_2_device_name(device_type);
|
||||||
std::string cmd_topic = EMSdevice::device_type_topic_name(device_type); // cmd topic for a device like "<device_type>_cmd" e.g. "boiler_cmd"
|
|
||||||
|
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
if (!mqtt_subfunctions_.empty()) {
|
if (!mqtt_subfunctions_.empty()) {
|
||||||
@@ -84,9 +82,7 @@ void Mqtt::add_command(const uint8_t device_type, const uint8_t device_id, const
|
|||||||
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
|
Mqtt::subscribe(device_type, cmd_topic, nullptr); // use an empty function handler to signal this is a command function
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_topic_name(device_type).c_str());
|
LOG_DEBUG(F("Registering MQTT cmd %s with topic %s"), uuid::read_flash_string(cmd).c_str(), EMSdevice::device_type_2_device_name(device_type).c_str());
|
||||||
|
|
||||||
mqtt_cmdfunctions_.emplace_back(device_type, device_id, cmd, cb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
|
// subscribe to an MQTT topic, and store the associated callback function. For generic functions not tied to a specific device
|
||||||
@@ -156,25 +152,13 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
|
|||||||
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) { system_heartbeat = settings.system_heartbeat; });
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) { system_heartbeat = settings.system_heartbeat; });
|
||||||
shell.printfln(F_(system_heartbeat_fmt), system_heartbeat ? F_(enabled) : F_(disabled));
|
shell.printfln(F_(system_heartbeat_fmt), system_heartbeat ? F_(enabled) : F_(disabled));
|
||||||
|
|
||||||
shell.printfln(F("MQTT publish fails: %lu"), mqtt_publish_fails_);
|
shell.printfln(F("MQTT publish fails count: %lu"), mqtt_publish_fails_);
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
// show subscriptions
|
// show subscriptions
|
||||||
shell.printfln(F("MQTT subscriptions:"));
|
shell.printfln(F("MQTT topic subscriptions:"));
|
||||||
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
|
||||||
// don't show commands if its homeassistant
|
shell.printfln(F(" %s"), mqtt_subfunction.full_topic_.c_str());
|
||||||
if ((strncmp(mqtt_subfunction.full_topic_.c_str(), "homeassistant/", 13) == 0)) {
|
|
||||||
shell.printf(F(" topic: %s"), mqtt_subfunction.full_topic_.c_str());
|
|
||||||
} else {
|
|
||||||
// show the commands associated with this subscription
|
|
||||||
shell.printf(F(" topic: %s, [cmd]:"), mqtt_subfunction.full_topic_.c_str());
|
|
||||||
for (const auto & mqtt_cmdfunction : mqtt_cmdfunctions_) {
|
|
||||||
if (EMSdevice::device_type_topic_name(mqtt_cmdfunction.device_type_) == mqtt_subfunction.topic_) {
|
|
||||||
shell.printf(F(" %s"), uuid::read_flash_string(mqtt_cmdfunction.cmd_).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
shell.println();
|
|
||||||
}
|
}
|
||||||
shell.println();
|
shell.println();
|
||||||
|
|
||||||
@@ -224,31 +208,6 @@ void Mqtt::incoming(const char * topic, const char * payload) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// calls a command, context is the device_type
|
|
||||||
// id may be used to represent a heating circuit for example
|
|
||||||
bool Mqtt::call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id) {
|
|
||||||
#ifdef EMSESP_DEBUG
|
|
||||||
if (id == -1) {
|
|
||||||
LOG_DEBUG(F("[DEBUG] Calling command %s, value %s, id is default"), cmd, value);
|
|
||||||
} else {
|
|
||||||
LOG_DEBUG(F("[DEBUG] Calling command %s, value %s, id is %d"), cmd, value, id);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!mqtt_cmdfunctions_.empty()) {
|
|
||||||
for (const auto & cf : mqtt_cmdfunctions_) {
|
|
||||||
if (cf.device_type_ == device_type) {
|
|
||||||
const char * cf_cmd = uuid::read_flash_string(cf.cmd_).c_str();
|
|
||||||
if (strcmp(cf_cmd, cmd) == 0) {
|
|
||||||
(cf.mqtt_cmdfunction_)(value, id); // call function, data needs to be a string and can be null
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// received an MQTT message that we subscribed too
|
// received an MQTT message that we subscribed too
|
||||||
void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
|
void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
@@ -295,13 +254,13 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
|
|||||||
bool cmd_known = false;
|
bool cmd_known = false;
|
||||||
JsonVariant data = doc["data"];
|
JsonVariant data = doc["data"];
|
||||||
if (data.is<char *>()) {
|
if (data.is<char *>()) {
|
||||||
cmd_known = call_command(mf.device_type_, command, data.as<char *>(), n);
|
cmd_known = Command::call_command(mf.device_type_, command, data.as<char *>(), n);
|
||||||
} else if (data.is<int>()) {
|
} else if (data.is<int>()) {
|
||||||
char data_str[10];
|
char data_str[10];
|
||||||
cmd_known = call_command(mf.device_type_, command, Helpers::itoa(data_str, (int16_t)data.as<int>()), n);
|
cmd_known = Command::call_command(mf.device_type_, command, Helpers::itoa(data_str, (int16_t)data.as<int>()), n);
|
||||||
} else if (data.is<float>()) {
|
} else if (data.is<float>()) {
|
||||||
char data_str[10];
|
char data_str[10];
|
||||||
cmd_known = call_command(mf.device_type_, command, Helpers::render_value(data_str, (float)data.as<float>(), 2), n);
|
cmd_known = Command::call_command(mf.device_type_, command, Helpers::render_value(data_str, (float)data.as<float>(), 2), n);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd_known) {
|
if (!cmd_known) {
|
||||||
@@ -417,7 +376,6 @@ void Mqtt::start() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// create space for command buffer, to avoid heap memory fragmentation
|
// create space for command buffer, to avoid heap memory fragmentation
|
||||||
mqtt_cmdfunctions_.reserve(40); // current count with boiler+thermostat is 37
|
|
||||||
mqtt_subfunctions_.reserve(10);
|
mqtt_subfunctions_.reserve(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,9 +451,9 @@ void Mqtt::on_connect() {
|
|||||||
|
|
||||||
resubscribe(); // in case this is a reconnect, re-subscribe again to all MQTT topics
|
resubscribe(); // in case this is a reconnect, re-subscribe again to all MQTT topics
|
||||||
|
|
||||||
// these commands respond to the topic "system_cmd" and take a payload like {cmd:"", data:"", id:""}
|
// these commands respond to the topic "system" and take a payload like {cmd:"", data:"", id:""}
|
||||||
add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("pin"), System::mqtt_command_pin);
|
Command::add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("pin"), System::command_pin);
|
||||||
add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("send"), System::mqtt_command_send);
|
Command::add_command(EMSdevice::DeviceType::SERVICEKEY, bus_id_, F("send"), System::command_send);
|
||||||
|
|
||||||
LOG_INFO(F("MQTT connected"));
|
LOG_INFO(F("MQTT connected"));
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/mqtt.h
26
src/mqtt.h
@@ -32,6 +32,7 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "console.h"
|
#include "console.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
#include <uuid/log.h>
|
#include <uuid/log.h>
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ using uuid::console::Shell;
|
|||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
using mqtt_subfunction_p = std::function<void(const char * message)>;
|
using mqtt_subfunction_p = std::function<void(const char * message)>;
|
||||||
using mqtt_cmdfunction_p = std::function<void(const char * data, const int8_t id)>;
|
using cmdfunction_p = std::function<bool(const char * data, const int8_t id)>;
|
||||||
|
|
||||||
struct MqttMessage {
|
struct MqttMessage {
|
||||||
~MqttMessage() = default;
|
~MqttMessage() = default;
|
||||||
@@ -85,7 +86,7 @@ class Mqtt {
|
|||||||
static void subscribe(const std::string & topic, mqtt_subfunction_p cb);
|
static void subscribe(const std::string & topic, mqtt_subfunction_p cb);
|
||||||
static void resubscribe();
|
static void resubscribe();
|
||||||
|
|
||||||
static void add_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p cb);
|
static void register_command(const uint8_t device_type, const uint8_t device_id, const __FlashStringHelper * cmd, cmdfunction_p cb);
|
||||||
|
|
||||||
static void publish(const std::string & topic, const std::string & payload);
|
static void publish(const std::string & topic, const std::string & payload);
|
||||||
static void publish(const std::string & topic, const JsonDocument & payload);
|
static void publish(const std::string & topic, const JsonDocument & payload);
|
||||||
@@ -104,8 +105,6 @@ class Mqtt {
|
|||||||
|
|
||||||
static void on_connect();
|
static void on_connect();
|
||||||
|
|
||||||
static bool call_command(const uint8_t device_type, const char * cmd, const char * value, const int8_t id);
|
|
||||||
|
|
||||||
void disconnect() {
|
void disconnect() {
|
||||||
mqttClient_->disconnect();
|
mqttClient_->disconnect();
|
||||||
}
|
}
|
||||||
@@ -126,24 +125,6 @@ class Mqtt {
|
|||||||
mqtt_publish_fails_ = 0;
|
mqtt_publish_fails_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MQTTCmdFunction {
|
|
||||||
uint8_t device_type_;
|
|
||||||
uint8_t device_id_;
|
|
||||||
const __FlashStringHelper * cmd_;
|
|
||||||
mqtt_cmdfunction_p mqtt_cmdfunction_;
|
|
||||||
|
|
||||||
MQTTCmdFunction(uint8_t device_type, uint8_t device_id, const __FlashStringHelper * cmd, mqtt_cmdfunction_p mqtt_cmdfunction)
|
|
||||||
: device_type_(device_type)
|
|
||||||
, device_id_(device_id)
|
|
||||||
, cmd_(cmd)
|
|
||||||
, mqtt_cmdfunction_(mqtt_cmdfunction) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<MQTTCmdFunction> commands() {
|
|
||||||
return mqtt_cmdfunctions_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
@@ -199,7 +180,6 @@ class Mqtt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
|
static std::vector<MQTTSubFunction> mqtt_subfunctions_; // list of mqtt subscribe callbacks for all devices
|
||||||
static std::vector<MQTTCmdFunction> mqtt_cmdfunctions_; // list of commands
|
|
||||||
|
|
||||||
uint32_t last_mqtt_poll_ = 0;
|
uint32_t last_mqtt_poll_ = 0;
|
||||||
uint32_t last_publish_boiler_ = 0;
|
uint32_t last_publish_boiler_ = 0;
|
||||||
|
|||||||
107
src/system.cpp
107
src/system.cpp
@@ -39,18 +39,22 @@ uint16_t System::analog_ = 0;
|
|||||||
|
|
||||||
// send on/off to a gpio pin
|
// send on/off to a gpio pin
|
||||||
// value: true = HIGH, false = LOW
|
// value: true = HIGH, false = LOW
|
||||||
void System::mqtt_command_pin(const char * value, const int8_t id) {
|
bool System::command_pin(const char * value, const int8_t id) {
|
||||||
bool v = false;
|
bool v = false;
|
||||||
if (Helpers::value2bool(value, v)) {
|
if (Helpers::value2bool(value, v)) {
|
||||||
pinMode(id, OUTPUT);
|
pinMode(id, OUTPUT);
|
||||||
digitalWrite(id, v);
|
digitalWrite(id, v);
|
||||||
LOG_INFO(F("GPIO %d set to %s"), id, v ? "HIGH" : "LOW");
|
LOG_INFO(F("GPIO %d set to %s"), id, v ? "HIGH" : "LOW");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send raw
|
// send raw
|
||||||
void System::mqtt_command_send(const char * value, const int8_t id) {
|
bool System::command_send(const char * value, const int8_t id) {
|
||||||
EMSESP::send_raw_telegram(value); // ignore id
|
EMSESP::send_raw_telegram(value); // ignore id
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart EMS-ESP
|
// restart EMS-ESP
|
||||||
@@ -590,32 +594,12 @@ void System::console_commands(Shell & shell, unsigned int context) {
|
|||||||
shell.printfln(F_(wifi_password_fmt), wifiSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
shell.printfln(F_(wifi_password_fmt), wifiSettings.ssid.isEmpty() ? F_(unset) : F_(asterisks));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
|
||||||
CommandFlags::USER,
|
|
||||||
flash_string_vector{F_(show), F_(mqtt)},
|
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { Mqtt::show_mqtt(shell); });
|
|
||||||
*/
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
||||||
CommandFlags::ADMIN,
|
CommandFlags::ADMIN,
|
||||||
flash_string_vector{F_(show), F_(users)},
|
flash_string_vector{F_(show), F_(users)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { System::show_users(shell); });
|
[](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { System::show_users(shell); });
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(ShellContext::SYSTEM,
|
|
||||||
CommandFlags::ADMIN,
|
|
||||||
flash_string_vector{F_(pin)},
|
|
||||||
flash_string_vector{F_(gpio_mandatory), F_(data_optional)},
|
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
|
||||||
if (arguments.size() == 1) {
|
|
||||||
shell.printfln(F("use on/off, 1/0 or true/false"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
int pin = 0;
|
|
||||||
if (Helpers::value2number(arguments[0].c_str(), pin)) {
|
|
||||||
System::mqtt_command_pin(arguments[1].c_str(), pin);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// enter the context
|
// enter the context
|
||||||
Console::enter_custom_context(shell, context);
|
Console::enter_custom_context(shell, context);
|
||||||
}
|
}
|
||||||
@@ -820,4 +804,81 @@ bool System::check_upgrade() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// export all settings to JSON text
|
||||||
|
// http://ems-esp/api?device=system&cmd=info
|
||||||
|
String System::export_settings() {
|
||||||
|
StaticJsonDocument<EMSESP_MAX_JSON_SIZE_LARGE> doc;
|
||||||
|
|
||||||
|
#ifndef EMSESP_STANDALONE
|
||||||
|
JsonObject root = doc.to<JsonObject>();
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getWiFiSettingsService()->read([&](WiFiSettings & settings) {
|
||||||
|
JsonObject node = root.createNestedObject("WIFI");
|
||||||
|
node["ssid"] = settings.ssid;
|
||||||
|
// node["password"] = settings.password;
|
||||||
|
node["hostname"] = settings.hostname;
|
||||||
|
node["static_ip_config"] = settings.staticIPConfig;
|
||||||
|
JsonUtils::writeIP(node, "local_ip", settings.localIP);
|
||||||
|
JsonUtils::writeIP(node, "gateway_ip", settings.gatewayIP);
|
||||||
|
JsonUtils::writeIP(node, "subnet_mask", settings.subnetMask);
|
||||||
|
JsonUtils::writeIP(node, "dns_ip_1", settings.dnsIP1);
|
||||||
|
JsonUtils::writeIP(node, "dns_ip_2", settings.dnsIP2);
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getAPSettingsService()->read([&](APSettings & settings) {
|
||||||
|
JsonObject node = root.createNestedObject("AP");
|
||||||
|
node["provision_mode"] = settings.provisionMode;
|
||||||
|
node["ssid"] = settings.ssid;
|
||||||
|
// node["password"] = settings.password;
|
||||||
|
node["local_ip"] = settings.localIP.toString();
|
||||||
|
node["gateway_ip"] = settings.gatewayIP.toString();
|
||||||
|
node["subnet_mask"] = settings.subnetMask.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getMqttSettingsService()->read([&](MqttSettings & settings) {
|
||||||
|
JsonObject node = root.createNestedObject("MQTT");
|
||||||
|
node["enabled"] = settings.enabled;
|
||||||
|
node["host"] = settings.host;
|
||||||
|
node["port"] = settings.port;
|
||||||
|
node["username"] = settings.username;
|
||||||
|
// node["password"] = settings.password;
|
||||||
|
node["client_id"] = settings.clientId;
|
||||||
|
node["keep_alive"] = settings.keepAlive;
|
||||||
|
node["clean_session"] = settings.cleanSession;
|
||||||
|
node["max_topic_length"] = settings.maxTopicLength;
|
||||||
|
node["system_heartbeat"] = settings.system_heartbeat;
|
||||||
|
node["publish_time_boiler"] = settings.publish_time_boiler;
|
||||||
|
node["publish_time_thermostat"] = settings.publish_time_thermostat;
|
||||||
|
node["publish_time_solar"] = settings.publish_time_solar;
|
||||||
|
node["publish_time_mixing"] = settings.publish_time_mixing;
|
||||||
|
node["publish_time_other"] = settings.publish_time_other;
|
||||||
|
node["publish_time_sensor"] = settings.publish_time_sensor;
|
||||||
|
node["mqtt_format"] = settings.mqtt_format;
|
||||||
|
node["mqtt_qos"] = settings.mqtt_qos;
|
||||||
|
node["mqtt_retain"] = settings.mqtt_retain;
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getNTPSettingsService()->read([&](NTPSettings & settings) {
|
||||||
|
JsonObject node = root.createNestedObject("NTP");
|
||||||
|
node["enabled"] = settings.enabled;
|
||||||
|
node["server"] = settings.server;
|
||||||
|
node["tz_label"] = settings.tzLabel;
|
||||||
|
node["tz_format"] = settings.tzFormat;
|
||||||
|
});
|
||||||
|
|
||||||
|
EMSESP::esp8266React.getOTASettingsService()->read([&](OTASettings & settings) {
|
||||||
|
JsonObject node = root.createNestedObject("OTA");
|
||||||
|
node["enabled"] = settings.enabled;
|
||||||
|
node["port"] = settings.port;
|
||||||
|
// node["password"] = settings.password;
|
||||||
|
});
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String buffer;
|
||||||
|
serializeJsonPretty(doc, buffer);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
13
src/system.h
13
src/system.h
@@ -47,19 +47,20 @@ class System {
|
|||||||
static void format(uuid::console::Shell & shell);
|
static void format(uuid::console::Shell & shell);
|
||||||
|
|
||||||
static void console_commands(Shell & shell, unsigned int context);
|
static void console_commands(Shell & shell, unsigned int context);
|
||||||
|
static bool command_pin(const char * value, const int8_t id);
|
||||||
static void mqtt_command_pin(const char * value, const int8_t id);
|
static bool command_send(const char * value, const int8_t id);
|
||||||
static void mqtt_command_send(const char * value, const int8_t id);
|
|
||||||
|
|
||||||
static uint8_t free_mem();
|
static uint8_t free_mem();
|
||||||
static void upload_status(bool in_progress);
|
static void upload_status(bool in_progress);
|
||||||
static bool upload_status();
|
static bool upload_status();
|
||||||
|
static void show_mem(const char * note);
|
||||||
|
static void set_led();
|
||||||
|
static String export_settings();
|
||||||
|
|
||||||
|
bool check_upgrade();
|
||||||
void syslog_init();
|
void syslog_init();
|
||||||
void set_heartbeat(bool system_heartbeat);
|
void set_heartbeat(bool system_heartbeat);
|
||||||
void send_heartbeat();
|
void send_heartbeat();
|
||||||
static void show_mem(const char * note);
|
|
||||||
static void set_led();
|
|
||||||
bool check_upgrade();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|||||||
@@ -601,12 +601,12 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & command) {
|
|||||||
|
|
||||||
// test publish and adding to queue
|
// test publish and adding to queue
|
||||||
EMSESP::txservice_.flush_tx_queue();
|
EMSESP::txservice_.flush_tx_queue();
|
||||||
EMSESP::EMSESP::mqtt_.publish("boiler_cmd", "test me");
|
EMSESP::EMSESP::mqtt_.publish("boiler", "test me");
|
||||||
Mqtt::show_mqtt(shell); // show queue
|
Mqtt::show_mqtt(shell); // show queue
|
||||||
|
|
||||||
strcpy(boiler_topic, "ems-esp/boiler_cmd");
|
strcpy(boiler_topic, "ems-esp/boiler");
|
||||||
strcpy(thermostat_topic, "ems-esp/thermostat_cmd");
|
strcpy(thermostat_topic, "ems-esp/thermostat");
|
||||||
strcpy(system_topic, "ems-esp/saystem_cmd");
|
strcpy(system_topic, "ems-esp/saystem");
|
||||||
|
|
||||||
EMSESP::mqtt_.incoming(boiler_topic, "12345"); // invalid format
|
EMSESP::mqtt_.incoming(boiler_topic, "12345"); // invalid format
|
||||||
EMSESP::mqtt_.incoming("bad_topic", "12345"); // no matching topic
|
EMSESP::mqtt_.incoming("bad_topic", "12345"); // no matching topic
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define EMSESP_APP_VERSION "2.0.2b2"
|
#define EMSESP_APP_VERSION "2.0.2b3"
|
||||||
|
|||||||
Reference in New Issue
Block a user