Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev_no_master_thermostat

This commit is contained in:
MichaelDvP
2022-03-08 10:53:13 +01:00
40 changed files with 642 additions and 625 deletions

56
.github/workflows/sonar_check.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: Sonar Check
on:
push:
branches:
- dev
pull_request:
types: [opened, synchronize, reopened]
jobs:
build:
name: Build
runs-on: ubuntu-latest
env:
# https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/
# SONAR_SCANNER_VERSION: 4.6.1.2450
SONAR_SCANNER_VERSION: 4.7.0.2747
SONAR_SERVER_URL: "https://sonarcloud.io"
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Set up JDK 11
uses: actions/setup-java@v1
with:
java-version: 11
- name: Cache SonarCloud packages
uses: actions/cache@v1
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Download and set up sonar-scanner
env:
SONAR_SCANNER_DOWNLOAD_URL: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${{ env.SONAR_SCANNER_VERSION }}-linux.zip
run: |
mkdir -p $HOME/.sonar
curl -sSLo $HOME/.sonar/sonar-scanner.zip ${{ env.SONAR_SCANNER_DOWNLOAD_URL }}
unzip -o $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/
echo "$HOME/.sonar/sonar-scanner-${{ env.SONAR_SCANNER_VERSION }}-linux/bin" >> $GITHUB_PATH
- name: Download and set up build-wrapper
env:
BUILD_WRAPPER_DOWNLOAD_URL: ${{ env.SONAR_SERVER_URL }}/static/cpp/build-wrapper-linux-x86.zip
run: |
curl -sSLo $HOME/.sonar/build-wrapper-linux-x86.zip ${{ env.BUILD_WRAPPER_DOWNLOAD_URL }}
unzip -o $HOME/.sonar/build-wrapper-linux-x86.zip -d $HOME/.sonar/
echo "$HOME/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH
- name: Run build-wrapper
run: |
make clean
build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make clean all
- name: Run sonar-scanner
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
sonar-scanner

5
.gitignore vendored
View File

@@ -28,3 +28,8 @@ node_modules
test.sh
scripts/__pycache__
.temp
# sonar
.scannerwork/
sonar/
build_wrapper_output_directory/

View File

@@ -113,6 +113,7 @@ COMPILE.cpp = $(CXX) $(CXX_STANDARD) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
#----------------------------------------------------------------------
# Targets
#----------------------------------------------------------------------
.PHONY: all
all: $(OUTPUT)
$(OUTPUT): $(OBJS)
@@ -138,6 +139,7 @@ cppcheck: $(SOURCES)
run: $(OUTPUT)
@$<
.PHONY: clean
clean:
@$(RM) -r $(BUILD) $(OUTPUT)

View File

@@ -16,7 +16,7 @@
"@types/lodash": "^4.14.179",
"@types/node": "^17.0.21",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@types/react-dom": "^17.0.13",
"@types/react-router-dom": "^5.3.3",
"async-validator": "^4.0.7",
"axios": "^0.26.0",
@@ -3793,9 +3793,9 @@
}
},
"node_modules/@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
"integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
"version": "17.0.13",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.13.tgz",
"integrity": "sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ==",
"dependencies": {
"@types/react": "*"
}
@@ -20246,9 +20246,9 @@
}
},
"@types/react-dom": {
"version": "17.0.11",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
"integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
"version": "17.0.13",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.13.tgz",
"integrity": "sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ==",
"requires": {
"@types/react": "*"
}

View File

@@ -12,7 +12,7 @@
"@types/lodash": "^4.14.179",
"@types/node": "^17.0.21",
"@types/react": "^17.0.39",
"@types/react-dom": "^17.0.11",
"@types/react-dom": "^17.0.13",
"@types/react-router-dom": "^5.3.3",
"async-validator": "^4.0.7",
"axios": "^0.26.0",

8
scripts/run_sonar.sh Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
# make sure you add the soanr token here
# export SONAR_TOKEN=""
make clean
build-wrapper-linux-x86-64 --out-dir build_wrapper_output_directory make all
sonar-scanner

11
sonar-project.properties Normal file
View File

@@ -0,0 +1,11 @@
sonar.organization=emsesp
sonar.projectKey=emsesp_EMS-ESP32
sonar.projectName=EMS-ESP32
sonar.projectVersion=3.4
sonar.sources=./src
sonar.cfamily.build-wrapper-output=build_wrapper_output_directory
sonar.sourceEncoding=UTF-8
sonar.host.url=https://sonarcloud.io
sonar.cfamily.threads=8
sonar.cfamily.cache.enabled=false
; sonar.cfamily.cache.path=./sonar/cache

View File

@@ -64,12 +64,11 @@ void AnalogSensor::reload() {
// load the list of analog sensors from the customization service
// and store them locally and then activate them
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
auto sensors = settings.analogCustomizations;
auto it = sensors_.begin();
auto it = sensors_.begin();
for (auto & sensor_ : sensors_) {
// update existing sensors
bool found = false;
for (auto & sensor : sensors) { //search customlist
for (const auto & sensor : settings.analogCustomizations) { //search customlist
if (sensor_.id() == sensor.id) {
// for output sensors set value to new start-value
if ((sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT)
@@ -90,10 +89,11 @@ void AnalogSensor::reload() {
}
it++;
}
// add new sensors from list
for (auto & sensor : sensors) {
for (const auto & sensor : settings.analogCustomizations) {
bool found = false;
for (auto & sensor_ : sensors_) {
for (const auto & sensor_ : sensors_) {
if (sensor_.id() == sensor.id) {
found = true;
}
@@ -295,13 +295,13 @@ bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, fl
if (!found_sensor) {
EMSESP::webCustomizationService.update(
[&](WebCustomization & settings) {
AnalogCustomization newSensor = AnalogCustomization();
newSensor.id = id;
newSensor.name = name;
newSensor.offset = offset;
newSensor.factor = factor;
newSensor.uom = uom;
newSensor.type = type;
auto newSensor = AnalogCustomization();
newSensor.id = id;
newSensor.name = name;
newSensor.offset = offset;
newSensor.factor = factor;
newSensor.uom = uom;
newSensor.type = type;
settings.analogCustomizations.push_back(newSensor);
LOG_DEBUG(F("Adding new customization for analog sensor ID %d"), id);
return StateUpdateResult::CHANGED; // persist the change
@@ -325,7 +325,7 @@ bool AnalogSensor::updated_values() {
}
// publish a single sensor to MQTT
void AnalogSensor::publish_sensor(const Sensor & sensor) {
void AnalogSensor::publish_sensor(const Sensor & sensor) const {
if (Mqtt::publish_single()) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
if (Mqtt::publish_single2cmd()) {
@@ -339,7 +339,7 @@ void AnalogSensor::publish_sensor(const Sensor & sensor) {
}
// send empty config topic to remove the entry from HA
void AnalogSensor::remove_ha_topic(const uint8_t id) {
void AnalogSensor::remove_ha_topic(const uint8_t id) const {
if (!Mqtt::ha_enabled()) {
return;
}
@@ -363,7 +363,6 @@ void AnalogSensor::publish_values(const bool force) {
for (const auto & sensor : sensors_) {
publish_sensor(sensor);
}
// return;
}
DynamicJsonDocument doc(120 * num_sensors);
@@ -383,61 +382,59 @@ void AnalogSensor::publish_values(const bool force) {
case AnalogType::PWM_0:
case AnalogType::PWM_1:
case AnalogType::PWM_2:
dataSensor["value"] = (float)sensor.value(); // float
dataSensor["value"] = sensor.value(); // float
break;
case AnalogType::DIGITAL_IN:
case AnalogType::DIGITAL_OUT:
default:
dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0
break;
}
// create HA config
if (Mqtt::ha_enabled()) {
if (!sensor.ha_registered || force) {
LOG_DEBUG(F("Recreating HA config for analog sensor ID %d"), sensor.id());
if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) {
LOG_DEBUG(F("Recreating HA config for analog sensor ID %d"), sensor.id());
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
StaticJsonDocument<EMSESP_JSON_SIZE_MEDIUM> config;
char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str());
config["stat_t"] = stat_t;
char stat_t[50];
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str());
config["stat_t"] = stat_t;
char str[50];
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.id());
config["val_tpl"] = str;
char str[50];
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.id());
config["val_tpl"] = str;
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
config["name"] = str;
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
config["name"] = str;
snprintf(str, sizeof(str), "analogsensor_%d", sensor.id());
config["uniq_id"] = str;
snprintf(str, sizeof(str), "analogsensor_%d", sensor.id());
config["uniq_id"] = str;
JsonObject dev = config.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");
JsonObject dev = config.createNestedObject("dev");
JsonArray ids = dev.createNestedArray("ids");
ids.add("ems-esp");
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.id());
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.id());
Mqtt::publish_ha(topic, config.as<JsonObject>());
Mqtt::publish_ha(topic, config.as<JsonObject>());
sensor.ha_registered = true;
}
sensor.ha_registered = true;
}
} else {
// not nested
doc[sensor.name()] = sensor.value();
}
}
}
Mqtt::publish(F("analogsensor_data"), doc.as<JsonObject>());
}
// called from emsesp.cpp, similar to the emsdevice->get_value_info
// searches by name
bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) {
bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) const {
for (const auto & sensor : sensors_) {
if (strcmp(cmd, sensor.name().c_str()) == 0) {
output["id"] = sensor.id();
@@ -455,8 +452,8 @@ bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const i
// creates JSON doc from values
// returns false if there are no sensors
bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject & output) {
if (sensors_.size() == 0) {
bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject & output) const {
if (sensors_.empty()) {
return false;
}
@@ -532,7 +529,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t id) {
return true;
} else if (sensor.type() == AnalogType::DIGITAL_OUT) {
uint8_t v = val;
if ((sensor.id() == 25 || sensor.id() == 26)) {
if (sensor.id() == 25 || sensor.id() == 26) {
sensor.set_offset(v);
sensor.set_value(v);
pinMode(sensor.id(), OUTPUT);
@@ -573,7 +570,6 @@ bool AnalogSensor::command_commands(const char * value, const int8_t id, JsonObj
// hard coded tests
#ifdef EMSESP_DEBUG
void AnalogSensor::test() {
// Sensor(const uint8_t id, const std::string & name, const float offset, const float factor, const uint8_t uom, const int8_t type);
sensors_.emplace_back(36, "test12", 0, 0.1, 17, AnalogType::ADC);
sensors_.back().set_value(12.4);

View File

@@ -127,38 +127,38 @@ class AnalogSensor {
void start();
void loop();
void publish_sensor(const Sensor & sensor);
void publish_sensor(const Sensor & sensor) const;
void publish_values(const bool force);
void reload();
bool updated_values();
// return back reference to the sensor list, used by other classes
const std::vector<Sensor> sensors() const {
std::vector<Sensor> sensors() const {
return sensors_;
}
uint32_t reads() {
uint32_t reads() const {
return sensorreads_;
}
uint32_t fails() {
uint32_t fails() const {
return sensorfails_;
}
bool analog_enabled() {
bool analog_enabled() const {
return (analog_enabled_);
}
bool have_sensors() {
return (sensors_.size() > 0);
bool have_sensors() const {
return (!sensors_.empty());
}
size_t no_sensors() {
size_t no_sensors() const {
return sensors_.size();
}
bool update(uint8_t id, const std::string & name, float offset, float factor, uint8_t uom, int8_t type);
bool get_value_info(JsonObject & output, const char * cmd, const int8_t id);
bool get_value_info(JsonObject & output, const char * cmd, const int8_t id) const;
#ifdef EMSESP_DEBUG
void test();
@@ -170,10 +170,10 @@ class AnalogSensor {
static uuid::log::Logger logger_;
void remove_ha_topic(const uint8_t id);
void remove_ha_topic(const uint8_t id) const;
bool command_setvalue(const char * value, const int8_t id);
void measure();
bool command_info(const char * value, const int8_t id, JsonObject & output);
bool command_info(const char * value, const int8_t id, JsonObject & output) const;
bool command_commands(const char * value, const int8_t id, JsonObject & output);
std::vector<Sensor> sensors_; // our list of sensors

View File

@@ -39,13 +39,13 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
}
// check first if it's from API, if so strip the "api/"
if ((p.paths().front() == "api")) {
if (p.paths().front() == "api") {
p.paths().erase(p.paths().begin());
} else {
// not /api, so must be MQTT path. Check for base and remove it.
if (!strncmp(path, Mqtt::base().c_str(), Mqtt::base().length())) {
char new_path[Mqtt::MQTT_TOPIC_MAX_SIZE];
strncpy(new_path, path, sizeof(new_path));
strlcpy(new_path, path, sizeof(new_path));
p.parse(new_path + Mqtt::base().length() + 1); // re-parse the stripped path
} else {
return message(CommandRet::ERROR, "unrecognized path", output); // error
@@ -151,7 +151,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
return_code = Command::call(device_type, command_p, Helpers::itoa((int16_t)data.as<int>(), data_str), is_admin, id_n, output);
} else if (data.is<float>()) {
char data_str[10];
return_code = Command::call(device_type, command_p, Helpers::render_value(data_str, (float)data.as<float>(), 2), is_admin, id_n, output);
return_code = Command::call(device_type, command_p, Helpers::render_value(data_str, data.as<float>(), 2), is_admin, id_n, output);
} else if (data.isNull()) {
return_code = Command::call(device_type, command_p, "", is_admin, id_n, output); // empty, will do a query instead
} else {
@@ -160,22 +160,19 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
return return_code;
}
const std::string Command::return_code_string(const uint8_t return_code) {
std::string Command::return_code_string(const uint8_t return_code) {
switch (return_code) {
case CommandRet::ERROR:
return read_flash_string(F("Error"));
break;
case CommandRet::OK:
return read_flash_string(F("OK"));
break;
case CommandRet::NOT_FOUND:
return read_flash_string(F("Not Found"));
break;
case CommandRet::NOT_ALLOWED:
return read_flash_string(F("Not Authorized"));
break;
case CommandRet::FAIL:
return read_flash_string(F("Failed"));
default:
break;
}
char s[4];
@@ -191,7 +188,7 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
// make a copy of the string command for parsing
char command_s[100];
strncpy(command_s, command, sizeof(command_s));
strlcpy(command_s, command, sizeof(command_s));
// look for a delimeter and split the string
char * p = command_s;
@@ -365,7 +362,7 @@ bool Command::list(const uint8_t device_type, JsonObject & output) {
}
sorted_cmds.sort();
for (auto & cl : sorted_cmds) {
for (const auto & cl : sorted_cmds) {
for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) {
output[cl] = cf.description_;
@@ -394,7 +391,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
// if not in verbose mode, just print them on a single line
if (!verbose) {
for (auto & cl : sorted_cmds) {
for (const auto & cl : sorted_cmds) {
shell.print(cl);
shell.print(" ");
}
@@ -404,7 +401,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
// verbose mode
shell.println();
for (auto & cl : sorted_cmds) {
for (const auto & cl : sorted_cmds) {
// find and print the description
for (const auto & cf : cmdfunctions_) {
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) {
@@ -462,7 +459,7 @@ bool Command::device_has_commands(const uint8_t device_type) {
}
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
// device found, now see if it has any commands
for (const auto & cf : cmdfunctions_) {
if (cf.device_type_ == device_type) {
@@ -488,7 +485,7 @@ void Command::show_devices(uuid::console::Shell & shell) {
for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first) && (device_has_commands(device_class.first))) {
if (emsdevice && (emsdevice->device_type() == device_class.first) && (device_has_commands(device_class.first))) {
shell.printf("%s ", EMSdevice::device_type_2_device_name(device_class.first).c_str());
break; // we only want to show one (not multiple of the same device types)
}
@@ -541,7 +538,7 @@ void Command::show_all(uuid::console::Shell & shell) {
// e.g. //one/two////three/// becomes /one/two/three
std::string SUrlParser::path() {
std::string s = "/"; // set up the beginning slash
for (std::string & f : m_folders) {
for (const std::string & f : m_folders) {
s += f;
s += "/";
}
@@ -554,6 +551,14 @@ SUrlParser::SUrlParser(const char * uri) {
}
bool SUrlParser::parse(const char * uri) {
if (uri == nullptr) {
return false;
}
if (*uri == '\0') {
return false;
}
m_folders.clear();
m_keysvalues.clear();
enum Type { begin, folder, param, value };
@@ -563,54 +568,53 @@ bool SUrlParser::parse(const char * uri) {
enum Type t = Type::begin;
std::string last_param;
if (c != nullptr || *c != '\0') {
do {
if (*c == '/') {
if (s.length() > 0) {
m_folders.push_back(s);
s.clear();
}
t = Type::folder;
} else if (*c == '?' && (t == Type::folder || t == Type::begin)) {
if (s.length() > 0) {
m_folders.push_back(s);
s.clear();
}
t = Type::param;
} else if (*c == '=' && (t == Type::param || t == Type::begin)) {
do {
if (*c == '/') {
if (s.length() > 0) {
m_folders.push_back(s);
s.clear();
}
t = Type::folder;
} else if (*c == '?' && (t == Type::folder || t == Type::begin)) {
if (s.length() > 0) {
m_folders.push_back(s);
s.clear();
}
t = Type::param;
} else if (*c == '=' && (t == Type::param || t == Type::begin)) {
m_keysvalues[s] = "";
last_param = s;
s.clear();
t = Type::value;
} else if (*c == '&' && (t == Type::value || t == Type::param || t == Type::begin)) {
if (t == Type::value) {
m_keysvalues[last_param] = s;
} else if ((t == Type::param || t == Type::begin) && (s.length() > 0)) {
m_keysvalues[s] = "";
last_param = s;
s.clear();
t = Type::value;
} else if (*c == '&' && (t == Type::value || t == Type::param || t == Type::begin)) {
if (t == Type::value) {
m_keysvalues[last_param] = s;
} else if ((t == Type::param || t == Type::begin) && (s.length() > 0)) {
m_keysvalues[s] = "";
last_param = s;
}
t = Type::param;
s.clear();
} else if (*c == '\0' && s.length() > 0) {
if (t == Type::value) {
m_keysvalues[last_param] = s;
} else if (t == Type::folder || t == Type::begin) {
m_folders.push_back(s);
} else if (t == Type::param) {
m_keysvalues[s] = "";
last_param = s;
}
s.clear();
} else if (*c == '\0' && s.length() == 0) {
if (t == Type::param && last_param.length() > 0) {
m_keysvalues[last_param] = "";
}
s.clear();
} else {
s += *c;
}
} while (*c++ != '\0');
}
t = Type::param;
s.clear();
} else if (*c == '\0' && s.length() > 0) {
if (t == Type::value) {
m_keysvalues[last_param] = s;
} else if (t == Type::folder || t == Type::begin) {
m_folders.push_back(s);
} else if (t == Type::param) {
m_keysvalues[s] = "";
last_param = s;
}
s.clear();
} else if (*c == '\0' && s.length() == 0) {
if (t == Type::param && last_param.length() > 0) {
m_keysvalues[last_param] = "";
}
s.clear();
} else {
s += *c;
}
} while (*c++ != '\0');
return true;
}

View File

@@ -125,22 +125,22 @@ class Command {
static const char * parse_command_string(const char * command, int8_t & id);
static const std::string return_code_string(const uint8_t return_code);
static std::string return_code_string(const uint8_t return_code);
private:
static uuid::log::Logger logger_;
static std::vector<CmdFunction> cmdfunctions_; // the list of commands
inline static uint8_t message(uint8_t error_code, const char * message, JsonObject & output) {
inline static uint8_t message(uint8_t error_code, const char * message, const JsonObject & output) {
output.clear();
output["message"] = (const char *)message;
output["message"] = message;
return error_code;
}
};
typedef std::unordered_map<std::string, std::string> KeyValueMap_t;
typedef std::vector<std::string> Folder_t;
using KeyValueMap_t = std::unordered_map<std::string, std::string>;
using Folder_t = std::vector<std::string>;
class SUrlParser {
private:
@@ -148,7 +148,7 @@ class SUrlParser {
Folder_t m_folders;
public:
SUrlParser(){};
SUrlParser() = default;
SUrlParser(const char * url);
bool parse(const char * url);

View File

@@ -31,9 +31,8 @@ std::shared_ptr<Commands> EMSESPShell::commands = [] {
return commands;
}();
static std::shared_ptr<EMSESPShell> shell;
std::vector<bool> EMSESPStreamConsole::ptys_;
std::shared_ptr<EMSESPShell> shell;
std::vector<bool> EMSESPStreamConsole::ptys_;
#ifndef EMSESP_STANDALONE
uuid::telnet::TelnetService telnet_([](Stream & stream, const IPAddress & addr, uint16_t port) -> std::shared_ptr<uuid::console::Shell> {
@@ -447,7 +446,7 @@ void Console::load_standard_commands(unsigned int context) {
flash_string_vector{F("test")},
flash_string_vector{F_(name_optional), F_(data_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.size() == 0) {
if (arguments.empty()) {
Test::run_test(shell, "default");
} else if (arguments.size() == 1) {
Test::run_test(shell, arguments.front());
@@ -467,7 +466,7 @@ void Console::load_standard_commands(unsigned int context) {
flash_string_vector{F_(debug)},
flash_string_vector{F_(name_optional)},
[](Shell & shell, const std::vector<std::string> & arguments) {
if (arguments.size() == 0) {
if (arguments.empty()) {
Test::debug(shell, "default");
} else {
Test::debug(shell, arguments.front());
@@ -515,10 +514,7 @@ void Console::load_standard_commands(unsigned int context) {
EMSESPShell::commands->add_command(context,
CommandFlags::USER,
flash_string_vector{F_(exit)},
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
shell.stop();
// shell.exit_context();
});
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.stop(); });
EMSESPShell::commands->add_command(context,
CommandFlags::USER,

View File

@@ -354,7 +354,7 @@ bool DallasSensor::command_commands(const char * value, const int8_t id, JsonObj
// creates JSON doc from values
// returns false if there are no sensors
bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject & output) {
if (sensors_.size() == 0) {
if (sensors_.empty()) {
return false;
}
@@ -435,7 +435,6 @@ void DallasSensor::publish_values(const bool force) {
for (const auto & sensor : sensors_) {
publish_sensor(sensor);
}
// return;
}
DynamicJsonDocument doc(120 * num_sensors);
@@ -536,8 +535,8 @@ std::string DallasSensor::Sensor::name() const {
bool DallasSensor::Sensor::apply_customization() {
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
auto sensors = settings.sensorCustomizations;
if (sensors.size() != 0) {
for (auto & sensor : sensors) {
if (sensors.empty()) {
for (const auto & sensor : sensors) {
#if defined(EMSESP_DEBUG)
LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id_str.c_str());
#endif

View File

@@ -85,7 +85,7 @@ class DallasSensor {
bool get_value_info(JsonObject & output, const char * cmd, const int8_t id);
// return back reference to the sensor list, used by other classes
const std::vector<Sensor> sensors() const {
std::vector<Sensor> sensors() const {
return sensors_;
}
@@ -102,7 +102,7 @@ class DallasSensor {
}
bool have_sensors() {
return (sensors_.size() > 0);
return (!sensors_.empty());
}
size_t no_sensors() {

View File

@@ -532,7 +532,7 @@ void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
has_update(telegram, wwDisinfectionTemp_, 8);
has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve
uint8_t wwComfort;
uint8_t wwComfort = EMS_VALUE_UINT_NOTSET;
telegram->read_value(wwComfort, 9);
if (wwComfort == 0) {
wwComfort = 0; // Hot
@@ -594,7 +594,7 @@ void Boiler::process_UBAMonitorFastPlus(std::shared_ptr<const Telegram> telegram
// read 3 char service code / installation status as appears on the display
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
char serviceCode[4];
char serviceCode[4] = {0};
telegram->read_value(serviceCode[0], 1);
serviceCode[0] = (serviceCode[0] == (char)0xF0) ? '~' : serviceCode[0];
telegram->read_value(serviceCode[1], 2);
@@ -878,19 +878,19 @@ void Boiler::process_UBAErrorMessage(std::shared_ptr<const Telegram> telegram) {
if (telegram->message_data[4] & 0x80) { // valid date
static uint32_t lastCodeDate_ = 0; // last code date
char code[3];
uint16_t codeNo;
code[0] = telegram->message_data[0];
code[1] = telegram->message_data[1];
code[2] = 0;
char code[3] = {0};
uint16_t codeNo = EMS_VALUE_SHORT_NOTSET;
code[0] = telegram->message_data[0];
code[1] = telegram->message_data[1];
code[2] = 0;
telegram->read_value(codeNo, 2);
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
uint8_t month = telegram->message_data[5];
uint8_t day = telegram->message_data[7];
uint8_t hour = telegram->message_data[6];
uint8_t min = telegram->message_data[8];
uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min;
uint16_t duration;
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
uint8_t month = telegram->message_data[5];
uint8_t day = telegram->message_data[7];
uint8_t hour = telegram->message_data[6];
uint8_t min = telegram->message_data[8];
uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min;
uint16_t duration = EMS_VALUE_SHORT_NOTSET;
telegram->read_value(duration, 9);
// store only the newest code from telegrams 10 and 11
if (date > lastCodeDate_) {
@@ -908,12 +908,12 @@ void Boiler::process_UBAErrorMessage2(std::shared_ptr<const Telegram> telegram)
return;
}
char code[sizeof(lastCode_)];
uint16_t codeNo;
code[0] = telegram->message_data[5];
code[1] = telegram->message_data[6];
code[2] = telegram->message_data[7];
code[3] = 0;
char code[sizeof(lastCode_)] = {0};
uint16_t codeNo = EMS_VALUE_SHORT_NOTSET;
code[0] = telegram->message_data[5];
code[1] = telegram->message_data[6];
code[2] = telegram->message_data[7];
code[3] = 0;
telegram->read_value(codeNo, 8);
// check for valid date, https://github.com/emsesp/EMS-ESP32/issues/204
@@ -1486,8 +1486,12 @@ bool Boiler::set_reset(const char * value, const int8_t id) {
return false;
}
//maintenance
// maintenance
bool Boiler::set_maintenance(const char * value, const int8_t id) {
if (value == nullptr) {
return false;
}
std::string s;
if (Helpers::value2string(value, s)) {
if (s == Helpers::toLower(read_flash_string(F_(reset)))) {
@@ -1549,7 +1553,7 @@ bool Boiler::set_maintenancetime(const char * value, const int8_t id) {
//maintenance
bool Boiler::set_maintenancedate(const char * value, const int8_t id) {
if (strlen(value) == 10) { // date
if ((value != nullptr) && strlen(value) == 10) { // date
uint8_t day = (value[0] - '0') * 10 + (value[1] - '0');
uint8_t month = (value[3] - '0') * 10 + (value[4] - '0');
uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000);

View File

@@ -293,7 +293,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
*/
// if it's the first set the status flag
if (heating_circuits_.size() == 0) {
if (heating_circuits_.empty()) {
strlcpy(status_, "online", sizeof(status_));
}
@@ -333,7 +333,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
}
// add the HVAC/Climate HA component for the HC
void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) {
void Thermostat::add_ha_climate(std::shared_ptr<HeatingCircuit> hc) const {
if (!Mqtt::ha_enabled()) {
hc->climate = EMS_VALUE_UINT_NOTSET;
return;
@@ -452,65 +452,44 @@ std::string Thermostat::mode_tostring(uint8_t mode) {
switch (mode) {
case HeatingCircuit::Mode::OFF:
return read_flash_string(F_(off));
break;
case HeatingCircuit::Mode::MANUAL:
return read_flash_string(F_(manual));
break;
case HeatingCircuit::Mode::DAY:
return read_flash_string(F_(day));
break;
case HeatingCircuit::Mode::NIGHT:
return read_flash_string(F_(night));
break;
case HeatingCircuit::Mode::ECO:
return read_flash_string(F_(eco));
break;
case HeatingCircuit::Mode::COMFORT:
return read_flash_string(F_(comfort));
break;
case HeatingCircuit::Mode::HEAT:
return read_flash_string(F_(heat));
break;
case HeatingCircuit::Mode::HOLIDAY:
return read_flash_string(F_(holiday));
break;
case HeatingCircuit::Mode::NOFROST:
return read_flash_string(F_(nofrost));
break;
case HeatingCircuit::Mode::AUTO:
return read_flash_string(F_(auto));
break;
case HeatingCircuit::Mode::SUMMER:
return read_flash_string(F_(summer));
break;
case HeatingCircuit::Mode::OFFSET:
return read_flash_string(F_(offset));
break;
case HeatingCircuit::Mode::DESIGN:
return read_flash_string(F_(design));
break;
case HeatingCircuit::Mode::MINFLOW:
return read_flash_string(F_(minflow));
break;
case HeatingCircuit::Mode::MAXFLOW:
return read_flash_string(F_(maxflow));
break;
case HeatingCircuit::Mode::ROOMINFLUENCE:
return read_flash_string(F_(roominfluence[0]));
break;
case HeatingCircuit::Mode::FLOWOFFSET:
return read_flash_string(F_(flowtempoffset[0]));
break;
case HeatingCircuit::Mode::TEMPAUTO:
return read_flash_string(F_(tempauto));
break;
case HeatingCircuit::Mode::NOREDUCE:
return read_flash_string(F_(noreduce));
break;
default:
case HeatingCircuit::Mode::UNKNOWN:
return read_flash_string(F_(unknown));
break;
}
}
@@ -1237,18 +1216,18 @@ void Thermostat::process_RCErrorMessage(std::shared_ptr<const Telegram> telegram
// data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr
if (telegram->message_data[4] & 0x80) { // valid date
char code[sizeof(lastCode_)];
uint16_t codeNo = EMS_VALUE_USHORT_NOTSET;
code[0] = telegram->message_data[0];
code[1] = telegram->message_data[1];
code[2] = 0;
char code[sizeof(lastCode_)] = {0};
uint16_t codeNo = EMS_VALUE_USHORT_NOTSET;
code[0] = telegram->message_data[0];
code[1] = telegram->message_data[1];
code[2] = 0;
telegram->read_value(codeNo, 2);
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
uint8_t month = telegram->message_data[5];
uint8_t day = telegram->message_data[7];
uint8_t hour = telegram->message_data[6];
uint8_t min = telegram->message_data[8];
uint16_t duration;
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
uint8_t month = telegram->message_data[5];
uint8_t day = telegram->message_data[7];
uint8_t hour = telegram->message_data[6];
uint8_t min = telegram->message_data[8];
uint16_t duration = EMS_VALUE_SHORT_NOTSET;
telegram->read_value(duration, 9);
snprintf(&code[2], sizeof(code) - 2, "(%d) %02d.%02d.%d %02d:%02d (%d min)", codeNo, day, month, year, hour, min, duration);
has_update(lastCode_, code, sizeof(lastCode_));
@@ -1292,7 +1271,7 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) {
return false;
}
int8_t t = (int8_t)(ct * 10);
auto t = (int8_t)(ct * 10);
LOG_DEBUG(F("Calibrating internal temperature to %d.%d C"), t / 10, t < 0 ? -t % 10 : t % 10);
if (model() == EMS_DEVICE_FLAG_RC10) {
@@ -1658,9 +1637,11 @@ bool Thermostat::set_wwCircProg(const char * value, const int8_t id) {
bool Thermostat::set_holiday(const char * value, const int8_t id, const bool vacation) {
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
if (hc == nullptr) {
if ((hc == nullptr) || (value == nullptr)) {
return false;
}
if (strlen(value) != 21) {
return false;
}
@@ -1805,7 +1786,7 @@ bool Thermostat::set_roominfl_factor(const char * value, const int8_t id) {
// sets the thermostat working mode, where mode is a string
// converts string mode to HeatingCircuit::Mode
bool Thermostat::set_mode(const char * value, const int8_t id) {
if (strlen(value) >= 20) {
if ((value == nullptr) || (strlen(value) >= 20)) {
return false;
}
@@ -1907,9 +1888,7 @@ bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
set_mode_value = 1;
break;
default:
case HeatingCircuit::Mode::AUTO:
case HeatingCircuit::Mode::ECO:
default: // AUTO & ECO
set_mode_value = 2;
break;
}
@@ -2133,7 +2112,7 @@ bool Thermostat::set_switchtime(const char * value, const uint16_t type_id, char
}
const char * s_mode = doc["mode"];
const char * s_time = doc["time"];
if ((model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N)) {
if (model() == EMS_DEVICE_FLAG_RC35 || model() == EMS_DEVICE_FLAG_RC30_N) {
bool b;
if (Helpers::value2bool(s_mode, b)) {
on = b ? 1 : 0;
@@ -2348,6 +2327,8 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = 4;
}
break;
default:
break;
}
} else if (model == EMS_DEVICE_FLAG_RC20) {
switch (mode) {
@@ -2381,6 +2362,8 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_RC20Set_temp_auto;
}
break;
default:
break;
}
} else if (model == EMS_DEVICE_FLAG_RC30) {
@@ -2460,7 +2443,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
factor = 1;
break;
default:
case HeatingCircuit::Mode::AUTO:
// HeatingCircuit::Mode::AUTO:
uint8_t mode_ = hc->get_mode();
if (mode_ == HeatingCircuit::Mode::MANUAL) {
offset = 0x0A; // manual offset
@@ -2499,7 +2482,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_RC20_2_Set_temp_day;
break;
default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
// automatic selection, if no type is defined, we use the standard code
uint8_t mode_ = hc->get_mode();
if (mode_ == HeatingCircuit::Mode::NIGHT) {
offset = EMS_OFFSET_RC20_2_Set_temp_night;
@@ -2570,7 +2553,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
factor = 1;
break;
default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
// automatic selection, if no type is defined, we use the standard code
validate_typeid = monitor_typeids[hc->hc()]; //get setpoint roomtemp back
if (model == EMS_DEVICE_FLAG_RC35) {
uint8_t mode_ = hc->get_mode();
@@ -2606,7 +2589,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_JunkersSetMessage_day_temp;
break;
default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
// automatic selection, if no type is defined, we use the standard code
uint8_t modetype = hc->get_mode_type();
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
offset = EMS_OFFSET_JunkersSetMessage_night_temp;
@@ -2633,7 +2616,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
offset = EMS_OFFSET_JunkersSetMessage2_heat_temp;
break;
default:
case HeatingCircuit::Mode::AUTO: // automatic selection, if no type is defined, we use the standard code
// automatic selection, if no type is defined, we use the standard code
uint8_t modetype = hc->get_mode_type();
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
offset = EMS_OFFSET_JunkersSetMessage2_eco_temp;
@@ -2651,7 +2634,7 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
if (offset != -1) {
// 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
write_command(set_typeid, offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
write_command(set_typeid, offset, (uint8_t)(temperature * (float)factor), validate_typeid);
return true;
}
@@ -3300,6 +3283,8 @@ void Thermostat::register_device_values_hc(std::shared_ptr<Thermostat::HeatingCi
register_device_value(tag, &hc->program, DeviceValueType::ENUM, FL_(enum_progMode4), FL_(program), DeviceValueUOM::NONE, MAKE_CF_CB(set_program));
register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES);
break;
default:
break;
}
}

View File

@@ -93,7 +93,7 @@ class Thermostat : public EMSdevice {
}
// determines if the heating circuit is actually present and has data
bool is_active() {
bool is_active() const {
return Helpers::hasValue(selTemp);
}
@@ -292,7 +292,7 @@ class Thermostat : public EMSdevice {
void register_device_values_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc);
void add_ha_climate(std::shared_ptr<HeatingCircuit> hc);
void add_ha_climate(std::shared_ptr<HeatingCircuit> hc) const;
void process_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
void process_IBASettings(std::shared_ptr<const Telegram> telegram);

View File

@@ -34,7 +34,7 @@ uint8_t EMSdevice::count_entities() {
}
// see if there are entities, excluding any commands
bool EMSdevice::has_entities() {
bool EMSdevice::has_entities() const {
for (const auto & dv : devicevalues_) {
if (dv.type != DeviceValueType::CMD) {
return true;
@@ -43,107 +43,71 @@ bool EMSdevice::has_entities() {
return false;
}
const std::string EMSdevice::tag_to_string(uint8_t tag) {
std::string EMSdevice::tag_to_string(uint8_t tag) {
return read_flash_string(DeviceValue::DeviceValueTAG_s[tag]);
}
const std::string EMSdevice::tag_to_mqtt(uint8_t tag) {
std::string EMSdevice::tag_to_mqtt(uint8_t tag) {
return read_flash_string(DeviceValue::DeviceValueTAG_mqtt[tag]);
}
const std::string EMSdevice::uom_to_string(uint8_t uom) {
std::string EMSdevice::uom_to_string(uint8_t uom) {
if (EMSESP::system_.fahrenheit() && (uom == DeviceValueUOM::DEGREES || uom == DeviceValueUOM::DEGREES_R)) {
return read_flash_string(DeviceValue::DeviceValueUOM_s[DeviceValueUOM::FAHRENHEIT]);
}
return read_flash_string(DeviceValue::DeviceValueUOM_s[uom]);
}
const std::string EMSdevice::brand_to_string() const {
std::string EMSdevice::brand_to_string() const {
switch (brand_) {
case EMSdevice::Brand::BOSCH:
return read_flash_string(F("Bosch"));
break;
case EMSdevice::Brand::JUNKERS:
return read_flash_string(F("Junkers"));
break;
case EMSdevice::Brand::BUDERUS:
return read_flash_string(F("Buderus"));
break;
case EMSdevice::Brand::NEFIT:
return read_flash_string(F("Nefit"));
break;
case EMSdevice::Brand::SIEGER:
return read_flash_string(F("Sieger"));
break;
case EMSdevice::Brand::WORCESTER:
return read_flash_string(F("Worcester"));
break;
case EMSdevice::Brand::IVT:
return read_flash_string(F("IVT"));
break;
case EMSdevice::Brand::NO_BRAND:
default:
return read_flash_string(F(""));
break;
}
return std::string{};
}
// returns the name of the MQTT topic to use for a specific device, without the base
const std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
std::string EMSdevice::device_type_2_device_name(const uint8_t device_type) {
switch (device_type) {
case DeviceType::SYSTEM:
return read_flash_string(F_(system));
break;
case DeviceType::BOILER:
return read_flash_string(F_(boiler));
break;
case DeviceType::THERMOSTAT:
return read_flash_string(F_(thermostat));
break;
case DeviceType::HEATPUMP:
return read_flash_string(F_(heatpump));
break;
case DeviceType::SOLAR:
return read_flash_string(F_(solar));
break;
case DeviceType::CONNECT:
return read_flash_string(F_(connect));
break;
case DeviceType::MIXER:
return read_flash_string(F_(mixer));
break;
case DeviceType::DALLASSENSOR:
return read_flash_string(F_(dallassensor));
break;
case DeviceType::ANALOGSENSOR:
return read_flash_string(F_(analogsensor));
break;
case DeviceType::CONTROLLER:
return read_flash_string(F_(controller));
break;
case DeviceType::SWITCH:
return read_flash_string(F_(switch));
break;
case DeviceType::GATEWAY:
return read_flash_string(F_(gateway));
break;
default:
return read_flash_string(F_(unknown));
break;
}
}
@@ -196,7 +160,7 @@ uint8_t EMSdevice::device_name_2_device_type(const char * topic) {
}
// return name of the device type, capitalized
const std::string EMSdevice::device_type_name() const {
std::string EMSdevice::device_type_name() const {
std::string s = device_type_2_device_name(device_type_);
s[0] = toupper(s[0]);
return s;
@@ -207,34 +171,25 @@ uint8_t EMSdevice::decode_brand(uint8_t value) {
switch (value) {
case 1:
return EMSdevice::Brand::BOSCH;
break;
case 2:
return EMSdevice::Brand::JUNKERS;
break;
case 3:
return EMSdevice::Brand::BUDERUS;
break;
case 4:
return EMSdevice::Brand::NEFIT;
break;
case 5:
return EMSdevice::Brand::SIEGER;
break;
case 11:
return EMSdevice::Brand::WORCESTER;
break;
case 13:
return EMSdevice::Brand::IVT;
break;
case 0:
default:
return EMSdevice::Brand::NO_BRAND;
break;
}
}
// returns string of a human friendly description of the EMS device
const std::string EMSdevice::to_string() const {
std::string EMSdevice::to_string() const {
// for devices that haven't been lookup yet, don't show all details
if (product_id_ == 0) {
return name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
@@ -249,7 +204,7 @@ const std::string EMSdevice::to_string() const {
}
// returns out brand + device name
const std::string EMSdevice::to_string_short() const {
std::string EMSdevice::to_string_short() const {
if (brand_ == Brand::NO_BRAND) {
return device_type_name() + ": " + name_;
}
@@ -280,8 +235,8 @@ void EMSdevice::toggle_fetch(uint16_t telegram_id, bool toggle) {
}
// get status of automatic fetch for a telegramID
bool EMSdevice::is_fetch(uint16_t telegram_id) {
for (auto & tf : telegram_functions_) {
bool EMSdevice::is_fetch(uint16_t telegram_id) const {
for (const auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == telegram_id) {
return tf.fetch_;
}
@@ -301,7 +256,7 @@ bool EMSdevice::has_tag(const uint8_t tag) {
// list of registered device entries
// called from the command 'entities'
void EMSdevice::list_device_entries(JsonObject & output) {
void EMSdevice::list_device_entries(JsonObject & output) const {
for (const auto & dv : devicevalues_) {
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD && dv.full_name) {
// if we have a tag prefix it
@@ -326,8 +281,8 @@ void EMSdevice::list_device_entries(JsonObject & output) {
}
// list all the telegram type IDs for this device
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
if (telegram_functions_.size() == 0) {
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
if (telegram_functions_.empty()) {
return;
}
/*
@@ -393,7 +348,7 @@ char * EMSdevice::show_telegram_handlers(char * result, uint8_t handlers) {
}
// list all the mqtt handlers for this device
void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) {
void EMSdevice::show_mqtt_handlers(uuid::console::Shell & shell) const {
Mqtt::show_topic_handlers(shell, device_type_);
}
@@ -426,7 +381,7 @@ void EMSdevice::register_device_value(uint8_t tag,
uint16_t max) {
// initialize the device value depending on it's type
if (type == DeviceValueType::STRING) {
*(char *)(value_p) = {'\0'};
*(char *)(value_p) = {'\0'}; // this is important for string functions like strlen() to work later
} else if (type == DeviceValueType::INT) {
*(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET;
} else if (type == DeviceValueType::SHORT) {
@@ -447,7 +402,7 @@ void EMSdevice::register_device_value(uint8_t tag,
uint8_t i = 0;
while (options[i++]) {
options_size++;
};
}
}
// this is the unique id set for the device entity. it's a simple sequence number
@@ -456,9 +411,6 @@ void EMSdevice::register_device_value(uint8_t tag,
// determine state
uint8_t state = DeviceValueState::DV_VISIBLE; // default to visible
// if (!full_name) {
// state = DeviceValueState::DV_DEFAULT; // don't show if the full_name is empty
// } else {
// scan through customizations to see if it's on the exclusion list by matching the productID and deviceID
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
for (EntityCustomization entityCustomization : settings.entityCustomizations) {
@@ -472,7 +424,6 @@ void EMSdevice::register_device_value(uint8_t tag,
}
}
});
// }
// add the device
devicevalues_.emplace_back(device_type_, tag, value_p, type, options, options_size, short_name, full_name, uom, 0, has_cmd, min, max, state, dv_id);
@@ -536,7 +487,7 @@ void EMSdevice::register_device_value(uint8_t tag,
}
// check if value is visible
bool EMSdevice::is_visible(void * value_p) {
bool EMSdevice::is_visible(const void * value_p) const {
for (const auto & dv : devicevalues_) {
if (dv.value_p == value_p) {
return dv.has_state(DeviceValueState::DV_VISIBLE);
@@ -546,10 +497,11 @@ bool EMSdevice::is_visible(void * value_p) {
}
// publish a single value on change
void EMSdevice::publish_value(void * value_p) {
void EMSdevice::publish_value(void * value_p) const {
if (!Mqtt::publish_single() || value_p == nullptr) {
return;
}
for (const auto & dv : devicevalues_) {
if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) {
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
@@ -593,7 +545,6 @@ void EMSdevice::publish_value(void * value_p) {
}
break;
}
case DeviceValueType::USHORT:
Helpers::render_value(payload, *(uint16_t *)(value_p), divider, fahrenheit);
break;
@@ -617,11 +568,12 @@ void EMSdevice::publish_value(void * value_p) {
Helpers::render_value(payload, *(uint32_t *)(value_p), divider);
break;
case DeviceValueType::STRING:
default:
if (Helpers::hasValue((char *)(value_p))) {
strlcpy(payload, (char *)(value_p), sizeof(payload));
}
break;
default:
break;
}
if (payload[0] != '\0') {
@@ -632,7 +584,7 @@ void EMSdevice::publish_value(void * value_p) {
}
// looks up the UOM for a given key from the device value table
const std::string EMSdevice::get_value_uom(const char * key) {
std::string EMSdevice::get_value_uom(const char * key) const {
// the key may have a TAG string prefixed at the beginning. If so, remove it
char new_key[80];
strlcpy(new_key, key, sizeof(new_key));
@@ -651,14 +603,12 @@ const std::string EMSdevice::get_value_uom(const char * key) {
// look up key in our device value list
for (const auto & dv : devicevalues_) {
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) {
if (read_flash_string(dv.full_name) == key_p) {
// ignore TIME since "minutes" is already added to the string value
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
break;
}
return EMSdevice::uom_to_string(dv.uom);
if ((dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) && (read_flash_string(dv.full_name) == key_p)) {
// ignore TIME since "minutes" is already added to the string value
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
break;
}
return EMSdevice::uom_to_string(dv.uom);
}
}
@@ -685,9 +635,9 @@ void EMSdevice::generate_values_web(JsonObject & output) {
// handle Booleans (true, false)
if (dv.type == DeviceValueType::BOOL) {
bool value_b = *(bool *)(dv.value_p);
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
obj["v"] = value_b ? "true" : "false";
} else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) {
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
obj["v"] = value_b ? 1 : 0;
} else {
char s[7];
@@ -816,9 +766,9 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
// handle Booleans (true, false)
if (dv.type == DeviceValueType::BOOL) {
bool value_b = *(bool *)(dv.value_p);
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
obj["v"] = value_b;
} else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) {
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
obj["v"] = value_b ? 1 : 0;
} else {
char s[7];
@@ -844,7 +794,8 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
uint8_t divider = 0;
uint8_t factor = 1;
if (dv.options_size == 1) {
const char * s = read_flash_string(dv.options[0]).c_str();
auto s_str = read_flash_string(dv.options[0]); // prevent object backing the pointer will be destroyed at the end of the full-expression
const char * s = s_str.c_str();
if (s[0] == '*') {
factor = Helpers::atoint(&s[1]);
} else {
@@ -853,13 +804,13 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
}
if (dv.type == DeviceValueType::INT) {
obj["v"] = (divider) ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p) * factor;
obj["v"] = divider ? Helpers::round2(*(int8_t *)(dv.value_p), divider) : *(int8_t *)(dv.value_p) * factor;
} else if (dv.type == DeviceValueType::UINT) {
obj["v"] = (divider) ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p) * factor;
obj["v"] = divider ? Helpers::round2(*(uint8_t *)(dv.value_p), divider) : *(uint8_t *)(dv.value_p) * factor;
} else if (dv.type == DeviceValueType::SHORT) {
obj["v"] = (divider) ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p) * factor;
obj["v"] = divider ? Helpers::round2(*(int16_t *)(dv.value_p), divider) : *(int16_t *)(dv.value_p) * factor;
} else if (dv.type == DeviceValueType::USHORT) {
obj["v"] = (divider) ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p) * factor;
obj["v"] = divider ? Helpers::round2(*(uint16_t *)(dv.value_p), divider) : *(uint16_t *)(dv.value_p) * factor;
} else if (dv.type == DeviceValueType::ULONG) {
obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor;
} else if (dv.type == DeviceValueType::TIME) {
@@ -988,10 +939,10 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
case DeviceValueType::BOOL:
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
bool value_b = (bool)(*(uint8_t *)(dv.value_p));
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
auto value_b = (bool)(*(uint8_t *)(dv.value_p));
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
json[value] = value_b;
} else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) {
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
json[value] = value_b ? 1 : 0;
} else {
char s[7];
@@ -1106,10 +1057,10 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
if (have_tag) {
snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); // prefix the tag
} else {
strcpy(name, read_flash_string(dv.full_name).c_str()); // use full name
strlcpy(name, read_flash_string(dv.full_name).c_str(), sizeof(name)); // use full name
}
} else {
strcpy(name, read_flash_string(dv.short_name).c_str()); // use short name
strlcpy(name, read_flash_string(dv.short_name).c_str(), sizeof(name)); // use short name
// if we have a tag, and its different to the last one create a nested object. only for hc, wwc and hs
if (dv.tag != old_tag) {
@@ -1123,14 +1074,14 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
// handle Booleans
if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
// see how to render the value depending on the setting
bool value_b = (bool)*(uint8_t *)(dv.value_p);
auto value_b = (bool)*(uint8_t *)(dv.value_p);
if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) {
char s[7];
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
} else {
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
json[name] = value_b;
} else if ((EMSESP::system_.bool_format() == BOOL_FORMAT_10)) {
} else if (EMSESP::system_.bool_format() == BOOL_FORMAT_10) {
json[name] = value_b ? 1 : 0;
} else {
char s[7];
@@ -1147,7 +1098,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
// handle ENUMs
else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) {
// check for numeric enum-format
if ((EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX)) {
if (EMSESP::system_.enum_format() == ENUM_FORMAT_INDEX) {
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p));
} else {
json[name] = dv.options[*(uint8_t *)(dv.value_p)];
@@ -1164,7 +1115,8 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
uint8_t divider = 0;
uint8_t factor = 1;
if (dv.options_size == 1) {
const char * s = read_flash_string(dv.options[0]).c_str();
auto s_str = read_flash_string(dv.options[0]); // prevent object backing the pointer will be destroyed at the end of the full-expression
const char * s = s_str.c_str();
if (s[0] == '*') {
factor = Helpers::atoint(&s[1]);
} else {
@@ -1300,7 +1252,7 @@ void EMSdevice::ha_config_clear() {
ha_config_done(false); // this will force the recreation of the main HA device config
}
bool EMSdevice::has_telegram_id(uint16_t id) {
bool EMSdevice::has_telegram_id(uint16_t id) const {
for (const auto & tf : telegram_functions_) {
if (tf.telegram_type_id_ == id) {
return true;
@@ -1310,7 +1262,7 @@ bool EMSdevice::has_telegram_id(uint16_t id) {
}
// return the name of the telegram type
const std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegram) {
std::string EMSdevice::telegram_type_name(std::shared_ptr<const Telegram> telegram) const {
// see if it's one of the common ones, like Version
if (telegram->type_id == EMS_TYPE_VERSION) {
return read_flash_string(F("Version"));
@@ -1351,22 +1303,22 @@ bool EMSdevice::handle_telegram(std::shared_ptr<const Telegram> telegram) {
}
// 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) const {
EMSESP::send_write_request(type_id, device_id(), offset, message_data, message_length, validate_typeid);
}
// 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) const {
EMSESP::send_write_request(type_id, device_id(), offset, value, validate_typeid);
}
// 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) const {
EMSESP::send_write_request(type_id, device_id(), offset, value, 0);
}
// send Tx read command to the device
void EMSdevice::read_command(const uint16_t type_id, const uint8_t offset, const uint8_t length) {
void EMSdevice::read_command(const uint16_t type_id, const uint8_t offset, const uint8_t length) const {
EMSESP::send_read_request(type_id, device_id(), offset, length);
}

View File

@@ -44,13 +44,13 @@ class EMSdevice {
strlcpy(version_, version, sizeof(version_));
}
const std::string device_type_name() const;
std::string device_type_name() const;
static const std::string device_type_2_device_name(const uint8_t device_type);
static uint8_t device_name_2_device_type(const char * topic);
static const std::string uom_to_string(uint8_t uom);
static const std::string tag_to_string(uint8_t tag);
static const std::string tag_to_mqtt(uint8_t tag);
static std::string device_type_2_device_name(const uint8_t device_type);
static uint8_t device_name_2_device_type(const char * topic);
static std::string uom_to_string(uint8_t uom);
static std::string tag_to_string(uint8_t tag);
static std::string tag_to_mqtt(uint8_t tag);
bool has_tag(const uint8_t tag);
@@ -66,7 +66,7 @@ class EMSdevice {
product_id_ = product_id;
}
inline bool is_device_id(uint8_t device_id) {
inline bool is_device_id(uint8_t device_id) const {
return ((device_id & 0x7F) == (device_id_ & 0x7F));
}
@@ -92,7 +92,7 @@ class EMSdevice {
strlcpy(version_, version, sizeof(version_));
}
inline const char * version() {
inline const char * version() const {
return version_;
}
@@ -134,7 +134,7 @@ class EMSdevice {
publish_value(value);
}
inline void has_update(char * value, char * newvalue, size_t len) {
inline void has_update(char * value, const char * newvalue, size_t len) {
if (strcmp(value, newvalue) != 0) {
strlcpy(value, newvalue, len);
has_update_ = true;
@@ -173,18 +173,18 @@ class EMSdevice {
}
}
const std::string brand_to_string() const;
static uint8_t decode_brand(uint8_t value);
std::string brand_to_string() const;
static uint8_t decode_brand(uint8_t value);
const std::string to_string() const;
const std::string to_string_short() const;
std::string to_string() const;
std::string to_string_short() const;
enum Handlers : uint8_t { ALL, RECEIVED, FETCHED, PENDING };
void show_telegram_handlers(uuid::console::Shell & shell);
void show_telegram_handlers(uuid::console::Shell & shell) const;
char * show_telegram_handlers(char * result, uint8_t handlers);
void show_mqtt_handlers(uuid::console::Shell & shell);
void list_device_entries(JsonObject & output);
void show_mqtt_handlers(uuid::console::Shell & shell) const;
void list_device_entries(JsonObject & output) const;
void exclude_entity(uint8_t entity_id);
void reset_exclude_entities();
@@ -193,9 +193,9 @@ class EMSdevice {
void register_telegram_type(const uint16_t telegram_type_id, const __FlashStringHelper * telegram_type_name, bool fetch, const process_function_p cb);
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
const std::string get_value_uom(const char * key);
bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
void get_dv_info(JsonObject & json);
std::string get_value_uom(const char * key) const;
bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
void get_dv_info(JsonObject & json);
enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT };
bool generate_values(JsonObject & output, const uint8_t tag_filter, const bool nested, const uint8_t output_target);
@@ -238,25 +238,25 @@ class EMSdevice {
const __FlashStringHelper * const * name,
uint8_t uom);
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);
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) const;
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) const;
void write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) const;
void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0);
void read_command(const uint16_t type_id, uint8_t offset = 0, uint8_t length = 0) const;
bool is_visible(void * value_p);
void publish_value(void * value_p);
bool is_visible(const void * value_p) const;
void publish_value(void * value_p) const;
void publish_all_values();
void mqtt_ha_entity_config_create();
void mqtt_ha_entity_config_remove();
const std::string telegram_type_name(std::shared_ptr<const Telegram> telegram);
std::string telegram_type_name(std::shared_ptr<const Telegram> telegram) const;
void fetch_values();
void toggle_fetch(uint16_t telegram_id, bool toggle);
bool is_fetch(uint16_t telegram_id);
bool has_telegram_id(uint16_t id);
bool is_fetch(uint16_t telegram_id) const;
bool has_telegram_id(uint16_t id) const;
void ha_config_clear();
bool ha_config_done() const {
@@ -347,7 +347,7 @@ class EMSdevice {
static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 12; // CRF200 only monitor
uint8_t count_entities();
bool has_entities();
bool has_entities() const;
private:
uint8_t unique_id_;

View File

@@ -77,12 +77,10 @@ bool EMSESP::wait_km_ = true;
// or if device_id is 0 it will fetch from all our known and active devices
void EMSESP::fetch_device_values(const uint8_t device_id) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if ((device_id == 0) || emsdevice->is_device_id(device_id)) {
emsdevice->fetch_values();
if (device_id != 0) {
return; // quit, we only want to return the selected device
}
if ((device_id == 0) || emsdevice->is_device_id(device_id)) {
emsdevice->fetch_values();
if (device_id != 0) {
return; // quit, we only want to return the selected device
}
}
}
@@ -91,10 +89,8 @@ void EMSESP::fetch_device_values(const uint8_t device_id) {
// see if the deviceID exists
bool EMSESP::valid_device(const uint8_t device_id) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if (emsdevice->is_device_id(device_id)) {
return true;
}
if (emsdevice && emsdevice->is_device_id(device_id)) {
return true;
}
}
return false; // can't find it
@@ -103,7 +99,7 @@ bool EMSESP::valid_device(const uint8_t device_id) {
// for a specific EMS device type go and request data values
void EMSESP::fetch_device_values_type(const uint8_t device_type) {
for (const auto & emsdevice : emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
emsdevice->fetch_values();
}
}
@@ -170,9 +166,9 @@ void EMSESP::watch_id(uint16_t watch_id) {
// resets all counters and bumps the UART
// this is called when the tx_mode is persisted in the FS either via Web UI or the console
void EMSESP::uart_init() {
uint8_t tx_mode;
uint8_t rx_gpio;
uint8_t tx_gpio;
uint8_t tx_mode = 0;
uint8_t rx_gpio = 0;
uint8_t tx_gpio = 0;
EMSESP::webSettingsService.read([&](WebSettings & settings) {
tx_mode = settings.tx_mode;
rx_gpio = settings.rx_gpio;
@@ -217,10 +213,8 @@ uint8_t EMSESP::bus_status() {
}
// Tx Failure rate > 10%
if (total_fail < total_sent) {
if (((total_fail * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT) {
return BUS_STATUS_TX_ERRORS;
}
if ((total_fail < total_sent) && (((total_fail * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT)) {
return BUS_STATUS_TX_ERRORS;
}
return BUS_STATUS_CONNECTED;
@@ -236,7 +230,6 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
case BUS_STATUS_TX_ERRORS:
shell.printfln(F("EMS Bus is connected, but Tx is not stable."));
break;
case BUS_STATUS_CONNECTED:
default:
shell.printfln(F("EMS Bus is connected."));
break;
@@ -248,7 +241,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
shell.printfln(F("EMS Bus info:"));
EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(F(" Tx mode: %d"), settings.tx_mode); });
shell.printfln(F(" Bus protocol: %s"), EMSbus::is_ht3() ? F("HT3") : F("Buderus"));
shell.printfln(F(" #recognized EMS devices: %d"), (EMSESP::emsdevices).size());
shell.printfln(F(" #recognized EMS devices: %d"), EMSESP::emsdevices.size());
shell.printfln(F(" #telegrams received: %d"), rxservice_.telegram_count());
shell.printfln(F(" #read requests sent: %d"), txservice_.telegram_read_count());
shell.printfln(F(" #write requests sent: %d"), txservice_.telegram_write_count());
@@ -308,7 +301,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
// 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 : emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
// print header
shell.printfln(F("%s: %s (%d)"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str(), emsdevice->count_entities());
@@ -330,7 +323,7 @@ void EMSESP::show_device_values(uuid::console::Shell & shell) {
shell.print(data.as<int>());
} else if (data.is<float>()) {
char s[10];
shell.print(Helpers::render_value(s, (float)data.as<float>(), 1));
shell.print(Helpers::render_value(s, data.as<float>(), 1));
} else if (data.is<bool>()) {
shell.print(data.as<bool>() ? F_(on) : F_(off));
}
@@ -400,8 +393,8 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
sensor.offset());
break;
default:
case AnalogSensor::AnalogType::DIGITAL_IN:
case AnalogSensor::AnalogType::COUNTER:
// case AnalogSensor::AnalogType::DIGITAL_IN:
// case AnalogSensor::AnalogType::COUNTER:
shell.printfln(F(" %s: %s%d%s (Type: %s)"),
sensor.name().c_str(),
COLOR_BRIGHT_GREEN,
@@ -582,7 +575,7 @@ void EMSESP::publish_response(std::shared_ptr<const Telegram> telegram) {
doc["dest"] = Helpers::hextoa(buffer, telegram->dest);
doc["type"] = Helpers::hextoa(buffer, telegram->type_id);
doc["offset"] = Helpers::hextoa(buffer, telegram->offset);
strcpy(buffer, Helpers::data_to_hex(telegram->message_data, telegram->message_length).c_str()); // telegram is without crc
strlcpy(buffer, Helpers::data_to_hex(telegram->message_data, telegram->message_length).c_str(), sizeof(buffer)); // telegram is without crc
doc["data"] = buffer;
if (telegram->message_length <= 4) {
@@ -830,31 +823,29 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
bool found = false;
bool knowndevice = false;
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
knowndevice = true;
found = emsdevice->handle_telegram(telegram);
if (found && emsdevice->is_device_id(telegram->dest)) {
LOG_DEBUG(F("Process setting 0x%02X for device 0x%02X"), telegram->type_id, telegram->dest);
}
// if we correctly processed the telegram then follow up with sending it via MQTT (if enabled)
if (found && Mqtt::connected()) {
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
|| (telegram->type_id == publish_id_ && telegram->dest == txservice_.ems_bus_id())) {
if (telegram->type_id == publish_id_) {
publish_id_ = 0;
}
emsdevice->has_update(false); // reset flag
if (!Mqtt::publish_single()) {
publish_device_values(emsdevice->device_type()); // publish to MQTT if we explicitly have too
}
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
knowndevice = true;
found = emsdevice->handle_telegram(telegram);
if (found && emsdevice->is_device_id(telegram->dest)) {
LOG_DEBUG(F("Process setting 0x%02X for device 0x%02X"), telegram->type_id, telegram->dest);
}
// if we correctly processed the telegram then follow up with sending it via MQTT (if enabled)
if (found && Mqtt::connected()) {
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
|| (telegram->type_id == publish_id_ && telegram->dest == txservice_.ems_bus_id())) {
if (telegram->type_id == publish_id_) {
publish_id_ = 0;
}
emsdevice->has_update(false); // reset flag
if (!Mqtt::publish_single()) {
publish_device_values(emsdevice->device_type()); // publish to MQTT if we explicitly have too
}
}
if (wait_validate_ == telegram->type_id) {
wait_validate_ = 0;
}
break;
}
if (wait_validate_ == telegram->type_id) {
wait_validate_ = 0;
}
break;
}
}
@@ -874,10 +865,8 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
// return true if we have this device already registered
bool EMSESP::device_exists(const uint8_t device_id) {
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if (emsdevice->is_device_id(device_id)) {
return true;
}
if (emsdevice && emsdevice->is_device_id(device_id)) {
return true;
}
}
@@ -898,7 +887,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
// count the number of thermostats
uint8_t num_thermostats = 0;
for (const auto & emsdevice : emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == DeviceType::THERMOSTAT)) {
if (emsdevice && (emsdevice->device_type() == DeviceType::THERMOSTAT)) {
num_thermostats++;
}
}
@@ -907,7 +896,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
// so we keep a consistent order
for (const auto & device_class : EMSFactory::device_handlers()) {
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.println();
emsdevice->show_telegram_handlers(shell);
@@ -931,25 +920,23 @@ bool EMSESP::add_device(const uint8_t device_id, const uint8_t product_id, const
// first check to see if we already have it, if so update the record
for (const auto & emsdevice : emsdevices) {
if (emsdevice) {
if (emsdevice->is_device_id(device_id)) {
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
emsdevice->product_id(product_id);
emsdevice->version(version);
// only set brand if it doesn't already exist
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
emsdevice->brand(brand);
}
// find the name and flags in our database
for (const auto & device : device_library_) {
if (device.product_id == product_id && device.device_type == emsdevice->device_type()) {
emsdevice->name(std::move(read_flash_string(device.name)));
emsdevice->add_flags(device.flags);
}
}
return true; // finish up
if (emsdevice && emsdevice->is_device_id(device_id)) {
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
emsdevice->product_id(product_id);
emsdevice->version(version);
// only set brand if it doesn't already exist
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
emsdevice->brand(brand);
}
// find the name and flags in our database
for (const auto & device : device_library_) {
if (device.product_id == product_id && device.device_type == emsdevice->device_type()) {
emsdevice->name(std::move(read_flash_string(device.name)));
emsdevice->add_flags(device.flags);
}
}
return true; // finish up
}
}
@@ -1085,7 +1072,7 @@ bool EMSESP::command_entities(uint8_t device_type, JsonObject & output, const in
JsonObject node;
for (const auto & emsdevice : emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
if (emsdevice && (emsdevice->device_type() == device_type)) {
emsdevice->list_device_entries(output);
return true;
}
@@ -1213,11 +1200,10 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
txservice_.send_poll(); // close the bus
txservice_.reset_retry_count();
tx_successful = true;
// if telegram is longer read next part with offset +25 for ems+ or +27 for ems1.0
if (length == 32) {
if (txservice_.read_next_tx(data[3]) == read_id_) {
read_next_ = true;
}
if ((length == 32) && (txservice_.read_next_tx(data[3]) == read_id_)) {
read_next_ = true;
}
}
}
@@ -1341,7 +1327,7 @@ void EMSESP::scheduled_fetch_values() {
if (txservice_.tx_queue_empty()) {
uint8_t i = 0;
for (const auto & emsdevice : emsdevices) {
if (emsdevice && ++i >= no) {
if (++i >= no) {
emsdevice->fetch_values();
no++;
return;

View File

@@ -64,8 +64,8 @@ std::string Helpers::hextoa(const uint16_t value, bool prefix) {
#ifdef EMSESP_STANDALONE
// special function to work outside of ESP's libraries
char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) {
if (NULL == ptr) {
return NULL;
if (nullptr == ptr) {
return nullptr;
}
unsigned long t = 0;
@@ -191,7 +191,7 @@ char * Helpers::render_boolean(char * result, bool value) {
// render for native char strings
char * Helpers::render_value(char * result, const char * value, const int8_t format __attribute__((unused))) {
strcpy(result, value);
strcpy(result, value); // un-safe but we don't care
return result;
}
@@ -256,8 +256,8 @@ char * Helpers::render_value(char * result, const float value, const int8_t form
uint32_t p[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
char * ret = result;
int32_t whole = (int32_t)value;
char * ret = result;
auto whole = (int32_t)value;
itoa(whole, result, 10);
@@ -356,12 +356,11 @@ char * Helpers::render_value(char * result, const uint32_t value, const int8_t f
} else {
strlcpy(result, ltoa(new_value * format * -1, s, 10), sizeof(s));
}
#else
if (!format) {
strlcpy(result, ultostr(s, new_value, 10), sizeof(s)); // format is 0
} else {
strncpy(result, ultostr(s, new_value / format, 10), sizeof(s));
strlcpy(result, ultostr(s, new_value / format, 10), sizeof(s));
strlcat(result, ".", sizeof(s));
strncat(result, ultostr(s, new_value % format, 10), sizeof(s));
}
@@ -481,7 +480,7 @@ bool Helpers::hasValue(const int8_t & v) {
return (v != EMS_VALUE_INT_NOTSET);
}
bool Helpers::hasValue(char * v) {
bool Helpers::hasValue(const char * v) {
if ((v == nullptr) || (strlen(v) == 0)) {
return false;
}
@@ -508,7 +507,8 @@ bool Helpers::value2number(const char * v, int & value, const int min, const int
value = 0;
return false;
}
value = atoi((char *)v);
value = atoi(v);
if (value >= min && value <= max) {
return true;
}
@@ -521,12 +521,14 @@ bool Helpers::value2float(const char * v, float & value) {
if ((v == nullptr) || (strlen(v) == 0)) {
return false;
}
if (v[0] == '-' || v[0] == '.' || (v[0] >= '0' && v[0] <= '9')) {
value = atof((char *)v);
value = atof(v);
return true;
}
if (v[0] == '+' && (v[1] == '.' || (v[1] >= '0' && v[1] <= '9'))) {
value = atof((char *)(v + 1));
value = atof(v + 1);
return true;
}
return false;
@@ -584,12 +586,12 @@ bool Helpers::value2bool(const char * v, bool & value) {
std::string bool_str = toLower(v); // convert to lower case
if ((bool_str == read_flash_string(F_(on))) || (bool_str == "1") or (bool_str == "true")) {
if ((bool_str == read_flash_string(F_(on))) || (bool_str == "1") || (bool_str == "true")) {
value = true;
return true; // is a bool
}
if ((bool_str == read_flash_string(F_(off))) || (bool_str == "0") or (bool_str == "false")) {
if ((bool_str == read_flash_string(F_(off))) || (bool_str == "0") || (bool_str == "false")) {
value = false;
return true; // is a bool
}

View File

@@ -63,7 +63,7 @@ class Helpers {
static bool hasValue(const int16_t & v);
static bool hasValue(const uint16_t & v);
static bool hasValue(const uint32_t & v);
static bool hasValue(char * v);
static bool hasValue(const char * v);
static bool value2number(const char * v, int & value, const int min = -2147483648, const int max = 2147483647);
static bool value2float(const char * v, float & value);

View File

@@ -379,7 +379,18 @@ MAKE_PSTR_LIST(enum_j_control, F_(off), F("fb10"), F("fb110"))
MAKE_PSTR_LIST(enum_wwProgMode, F("std Prog"), F_(own_prog))
MAKE_PSTR_LIST(enum_dayOfWeek, F("Mo"), F("Di"), F("Mi"), F("Do"), F("Fr"), F("Sa"), F("So"), F("Alle"))
MAKE_PSTR_LIST(enum_progMode, F("Prog_1"), F("Prog_2"))
MAKE_PSTR_LIST(enum_progMode2, F("Eigen_1"), F("Familie"), F("Morgends"), F("Abends"), F("Vormittag"), F("Nachmittag"), F("Mittag"), F("Singles"), F("Senioren"), F("Neu"), F("Eigen_2"))
MAKE_PSTR_LIST(enum_progMode2,
F("Eigen_1"),
F("Familie"),
F("Morgends"),
F("Abends"),
F("Vormittag"),
F("Nachmittag"),
F("Mittag"),
F("Singles"),
F("Senioren"),
F("Neu"),
F("Eigen_2"))
MAKE_PSTR_LIST(enum_progMode3, F("Familie"), F("Morgends"), F("Abends"), F("Vormittag"), F("Nachmittag"), F("Mittag"), F("Singles"), F("Senioren"))
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))

View File

@@ -244,14 +244,16 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
#if defined(EMSESP_DEBUG)
// simulate receiving a MQTT message, used only for testing
void Mqtt::incoming(const char * topic, const char * payload) {
on_message(topic, payload, strlen(payload));
if (payload != nullptr) {
on_message(topic, payload, strlen(payload));
}
}
#endif
// received an MQTT message that we subscribed too
// topic is the full path
// payload is json or a single string and converted to a json with key 'value'
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) const {
// sometimes the payload is not terminated correctly, so make a copy
// convert payload to a null-terminated char string
char message[len + 2];
@@ -280,16 +282,14 @@ void Mqtt::on_message(const char * topic, const char * payload, size_t len) {
// add the base back
char full_topic[MQTT_TOPIC_MAX_SIZE];
snprintf(full_topic, sizeof(full_topic), "%s/%s", mqtt_base_.c_str(), mf.topic_.c_str());
if (!strcmp(topic, full_topic)) {
if (mf.mqtt_subfunction_) {
if (!(mf.mqtt_subfunction_)(message)) {
LOG_ERROR(F("error: invalid payload %s for this topic %s"), message, topic);
if (send_response_) {
Mqtt::publish(F_(response), "error: invalid data");
}
if ((!strcmp(topic, full_topic)) && (mf.mqtt_subfunction_)) {
if (!(mf.mqtt_subfunction_)(message)) {
LOG_ERROR(F("error: invalid payload %s for this topic %s"), message, topic);
if (send_response_) {
Mqtt::publish(F_(response), "error: invalid data");
}
return;
}
return;
}
}
@@ -353,7 +353,7 @@ void Mqtt::show_topic_handlers(uuid::console::Shell & shell, const uint8_t devic
// its a poor man's QOS we assume the ACK represents the last Publish sent
// check if ACK matches the last Publish we sent, if not report an error. Only if qos is 1 or 2
// and always remove from queue
void Mqtt::on_publish(uint16_t packetId) {
void Mqtt::on_publish(uint16_t packetId) const {
// find the MQTT message in the queue and remove it
if (mqtt_messages_.empty()) {
#if defined(EMSESP_DEBUG)
@@ -462,7 +462,7 @@ void Mqtt::start() {
snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "%s/status", mqtt_base_.c_str());
mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true
mqttClient_->onMessage([this](char * topic, char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
mqttClient_->onMessage([this](const char * topic, const char * payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
on_message(topic, payload, len); // receiving mqtt
});
@@ -804,7 +804,7 @@ void Mqtt::process_queue() {
char topic[MQTT_TOPIC_MAX_SIZE];
if (message->topic.find(discovery_prefix_) == 0) {
strcpy(topic, message->topic.c_str()); // leave topic as it is
strlcpy(topic, message->topic.c_str(), sizeof(topic)); // leave topic as it is
} else {
snprintf(topic, MQTT_TOPIC_MAX_SIZE, "%s/%s", mqtt_base_.c_str(), message->topic.c_str());
}
@@ -1313,7 +1313,7 @@ void Mqtt::publish_ha_climate_config(uint8_t tag, bool has_roomtemp, bool remove
// based on the device and tag, create the MQTT topic name (without the basename)
// differs based on whether MQTT nested is enabled
// tag = EMSdevice::DeviceValueTAG
const std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
std::string Mqtt::tag_to_topic(uint8_t device_type, uint8_t tag) {
// the system device is treated differently. The topic is 'heartbeat' and doesn't follow the usual convention
if (device_type == EMSdevice::DeviceType::SYSTEM) {
return EMSdevice::tag_to_mqtt(tag);

View File

@@ -30,7 +30,7 @@
using uuid::console::Shell;
// size of queue
#define MAX_MQTT_MESSAGES 300
static constexpr uint16_t MAX_MQTT_MESSAGES = 300;
namespace emsesp {
@@ -208,11 +208,11 @@ class Mqtt {
send_response_ = send_response;
}
void set_qos(uint8_t mqtt_qos) {
void set_qos(uint8_t mqtt_qos) const {
mqtt_qos_ = mqtt_qos;
}
void set_retain(bool mqtt_retain) {
void set_retain(bool mqtt_retain) const {
mqtt_retain_ = mqtt_retain;
}
@@ -220,20 +220,18 @@ class Mqtt {
return mqtt_messages_.empty();
}
static const std::string tag_to_topic(uint8_t device_type, uint8_t tag);
static std::string tag_to_topic(uint8_t device_type, uint8_t tag);
struct QueuedMqttMessage {
const uint32_t id_;
const std::shared_ptr<const MqttMessage> content_;
uint8_t retry_count_;
uint16_t packet_id_;
uint8_t retry_count_ = 0;
uint16_t packet_id_ = 0;
~QueuedMqttMessage() = default;
QueuedMqttMessage(uint32_t id, std::shared_ptr<MqttMessage> && content)
: id_(id)
, content_(std::move(content)) {
retry_count_ = 0;
packet_id_ = 0;
}
};
static std::deque<QueuedMqttMessage> mqtt_messages_;
@@ -253,8 +251,8 @@ class Mqtt {
static std::shared_ptr<const MqttMessage> queue_subscribe_message(const std::string & topic);
static std::shared_ptr<const MqttMessage> queue_unsubscribe_message(const std::string & topic);
void on_publish(uint16_t packetId);
void on_message(const char * topic, const char * payload, size_t len);
void on_publish(uint16_t packetId) const;
void on_message(const char * topic, const char * payload, size_t len) const;
void process_queue();
// function handlers for MQTT subscriptions

View File

@@ -65,12 +65,12 @@ void Shower::loop() {
}
} else { // hot water is off
// if it just turned off, record the time as it could be a short pause
if ((timer_start_) && (timer_pause_ == 0)) {
if (timer_start_ && (timer_pause_ == 0)) {
timer_pause_ = time_now;
}
// if shower has been off for longer than the wait time
if ((timer_pause_) && ((time_now - timer_pause_) > SHOWER_PAUSE_TIME)) {
if (timer_pause_ && ((time_now - timer_pause_) > SHOWER_PAUSE_TIME)) {
// it is over the wait period, so assume that the shower has finished and calculate the total time and publish
// because its unsigned long, can't have negative so check if length is less than OFFSET_TIME
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
@@ -121,7 +121,7 @@ void Shower::shower_alert_start() {
// Publish to the shower_data topic
// showing whether the shower timer and alert are enabled or disabled
// and the duration of the last shower
void Shower::publish_shower_data() {
void Shower::publish_shower_data() const {
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {

View File

@@ -55,7 +55,7 @@ class Shower {
static constexpr uint32_t SHOWER_COLDSHOT_DURATION = 10000; // 10 seconds for cold water before turning back hot water
static constexpr uint32_t SHOWER_MAX_DURATION = 420000; // in ms. 7 minutes, before trigger a shot of cold water
void publish_shower_data();
void publish_shower_data() const;
void shower_alert_start();
void shower_alert_stop();

View File

@@ -484,7 +484,7 @@ bool System::upload_status() {
void System::upload_status(bool in_progress) {
// if we've just started an upload
if ((!upload_status_) && (in_progress)) {
if (!upload_status_ && in_progress) {
EMSuart::stop();
}
upload_status_ = in_progress;
@@ -615,7 +615,7 @@ void System::network_init(bool refresh) {
// ETH_CLOCK_GPIO0_OUT = 1 RMII clock output from GPIO0
// ETH_CLOCK_GPIO16_OUT = 2 RMII clock output from GPIO16
// ETH_CLOCK_GPIO17_OUT = 3 RMII clock output from GPIO17, for 50hz inverted clock
eth_clock_mode_t clock_mode = (eth_clock_mode_t)eth_clock_mode_;
auto clock_mode = (eth_clock_mode_t)eth_clock_mode_;
ETH.begin(phy_addr, power, mdc, mdio, type, clock_mode);
}
@@ -1133,9 +1133,11 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
node["bus status"] = (F("connected, tx issues - try a different tx-mode"));
break;
case EMSESP::BUS_STATUS_CONNECTED:
default:
node["bus status"] = (F("connected"));
break;
default:
node["bus status"] = (F("unknown"));
break;
}
if (EMSESP::bus_status() != EMSESP::BUS_STATUS_OFFLINE) {
@@ -1180,7 +1182,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject & outp
JsonArray devices = output.createNestedArray("Devices");
for (const auto & device_class : EMSFactory::device_handlers()) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
JsonObject obj = devices.createNestedObject();
obj["type"] = emsdevice->device_type_name();
// obj["name"] = emsdevice->to_string();
@@ -1278,7 +1280,7 @@ bool System::command_restart(const char * value, const int8_t id) {
return true;
}
const std::string System::reset_reason(uint8_t cpu) {
std::string System::reset_reason(uint8_t cpu) const {
#ifndef EMSESP_STANDALONE
switch (rtc_get_reset_reason(cpu)) {
case 1:

View File

@@ -65,7 +65,7 @@ class System {
static bool command_customizations(const char * value, const int8_t id, JsonObject & output);
static bool command_commands(const char * value, const int8_t id, JsonObject & output);
const std::string reset_reason(uint8_t cpu);
std::string reset_reason(uint8_t cpu) const;
void system_restart();
void format(uuid::console::Shell & shell);

View File

@@ -261,7 +261,7 @@ void TxService::start() {
}
// sends a 1 byte poll which is our own deviceID
void TxService::send_poll() {
void TxService::send_poll() const {
//LOG_DEBUG(F("Ack %02X"),ems_bus_id() ^ ems_mask());
if (tx_mode()) {
EMSuart::send_poll(ems_bus_id() ^ ems_mask());
@@ -568,7 +568,7 @@ void TxService::send_raw(const char * telegram_data) {
while (p != 0) {
if ((p = strtok(nullptr, " ,"))) {
strlcpy(value, p, sizeof(value));
uint8_t val = (uint8_t)strtol(value, 0, 16);
auto val = (uint8_t)strtol(value, 0, 16);
data[++count] = val;
}
}

View File

@@ -87,11 +87,12 @@ class Telegram {
// reads a bit value from a given telegram position
bool read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
uint8_t abs_index = (index - this->offset);
if (abs_index >= this->message_length) {
if ((abs_index >= this->message_length) || (abs_index > EMS_MAX_TELEGRAM_MESSAGE_LENGTH)) {
return false; // out of bounds
}
uint8_t val = value;
value = (uint8_t)(((this->message_data[abs_index]) >> (bit)) & 0x01);
value = (uint8_t)(((this->message_data[abs_index]) >> bit) & 0x01);
return (val != value);
}
@@ -105,14 +106,17 @@ class Telegram {
bool read_value(Value & value, const uint8_t index, uint8_t s = 0) const {
uint8_t num_bytes = (!s) ? sizeof(Value) : s;
// check for out of bounds, if so don't modify the value
if ((index < this->offset) || ((index - this->offset + num_bytes - 1) >= this->message_length)) {
auto msg_size = (index - this->offset + num_bytes - 1);
if ((index < this->offset) || (msg_size >= this->message_length) || (msg_size > EMS_MAX_TELEGRAM_MESSAGE_LENGTH)) {
return false;
}
auto val = value;
value = 0;
Value val = value;
value = 0;
for (uint8_t i = 0; i < num_bytes; i++) {
value = (value << 8) + this->message_data[index - this->offset + i]; // shift by byte
}
return (val != value);
}
@@ -120,6 +124,7 @@ class Telegram {
if ((index < this->offset) || ((index - this->offset) >= this->message_length)) {
return false;
}
uint8_t val = value;
value = this->message_data[index - this->offset] - start;
return (val != value);
@@ -265,7 +270,7 @@ class RxService : public EMSbus {
}
};
const std::deque<QueuedRxTelegram> queue() const {
std::deque<QueuedRxTelegram> queue() const {
return rx_telegrams_;
}
@@ -300,7 +305,7 @@ class TxService : public EMSbus {
void add(const uint8_t operation, const uint8_t * data, const uint8_t length, const uint16_t validateid, const bool front = false);
void read_request(const uint16_t type_id, const uint8_t dest, const uint8_t offset = 0, const uint8_t length = 0);
void send_raw(const char * telegram_data);
void send_poll();
void send_poll() const;
void retry_tx(const uint8_t operation, const uint8_t * data, const uint8_t length);
bool is_last_tx(const uint8_t src, const uint8_t dest) const;
uint16_t post_send_query();
@@ -318,7 +323,7 @@ class TxService : public EMSbus {
telegram_last_post_send_query_ = type_id;
}
uint16_t get_post_send_query() {
uint16_t get_post_send_query() const {
return telegram_last_post_send_query_;
}
@@ -362,14 +367,14 @@ class TxService : public EMSbus {
if (telegram_read_fail_count_ == 0) {
return 100; // all good, 100%
}
return (100 - (uint8_t)((telegram_read_fail_count_ * 100 / (telegram_read_fail_count_ + telegram_read_count_))));
return (100 - (uint8_t)(telegram_read_fail_count_ * 100 / (telegram_read_fail_count_ + telegram_read_count_)));
}
uint8_t write_quality() const {
if (telegram_write_fail_count_ == 0) {
return 100; // all good, 100%
}
return (100 - (uint8_t)((telegram_write_fail_count_ * 100 / (telegram_write_fail_count_ + telegram_write_count_))));
return (100 - (uint8_t)(telegram_write_fail_count_ * 100 / (telegram_write_fail_count_ + telegram_write_count_)));
}
void increment_telegram_read_fail_count() {
@@ -395,12 +400,12 @@ class TxService : public EMSbus {
}
};
const std::deque<QueuedTxTelegram> queue() const {
std::deque<QueuedTxTelegram> queue() const {
return tx_telegrams_;
}
bool tx_queue_empty() {
return tx_telegrams_.size() == 0;
bool tx_queue_empty() const {
return tx_telegrams_.empty();
}
#if defined(EMSESP_DEBUG)

View File

@@ -804,28 +804,28 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
// test command parse
int8_t id_n;
const char * cmd;
const char * ncmd;
char command_s[100];
id_n = -1;
strcpy(command_s, "hc2/seltemp");
cmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
strlcpy(command_s, "hc2/seltemp", sizeof(command_s));
ncmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
id_n = -1;
strcpy(command_s, "seltemp");
cmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
strlcpy(command_s, "seltemp", sizeof(command_s));
ncmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
id_n = -1;
strcpy(command_s, "xyz/seltemp");
cmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
strlcpy(command_s, "xyz/seltemp", sizeof(command_s));
ncmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
id_n = -1;
strcpy(command_s, "wwc4/seltemp");
cmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
strlcpy(command_s, "wwc4/seltemp", sizeof(command_s));
ncmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
id_n = -1;
strcpy(command_s, "hc3_seltemp");
cmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
strlcpy(command_s, "hc3_seltemp", sizeof(command_s));
ncmd = Command::parse_command_string(command_s, id_n);
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
#endif
@@ -1335,12 +1335,12 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
Mqtt::show_mqtt(shell); // show queue
strcpy(boiler_topic, "ems-esp/boiler");
strcpy(thermostat_topic, "ems-esp/thermostat");
strcpy(system_topic, "ems-esp/system");
strlcpy(boiler_topic, "ems-esp/boiler", sizeof(boiler_topic));
strlcpy(thermostat_topic, "ems-esp/thermostat", sizeof(thermostat_topic));
strlcpy(system_topic, "ems-esp/system", sizeof(system_topic));
// test publishing
EMSESP::EMSESP::mqtt_.publish(boiler_topic, "test me");
EMSESP::mqtt_.publish(boiler_topic, "test me");
// test receiving
EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads, should return values

View File

@@ -49,7 +49,7 @@ void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) {
// POST /{device}[/{hc|id}][/{name}]
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json) {
// if no body then treat it as a secure GET
if (not json.is<JsonObject>()) {
if (!json.is<JsonObject>()) {
webAPIService_get(request);
return;
}
@@ -63,10 +63,10 @@ void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVari
// reporting back any errors
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
// check if the user has admin privileges (token is included and authorized)
bool is_admin;
bool is_admin = false;
EMSESP::webSettingsService.read([&](WebSettings & settings) {
Authentication authentication = _securityManager->authenticateRequest(request);
is_admin = settings.notoken_api | AuthenticationPredicates::IS_ADMIN(authentication);
is_admin = settings.notoken_api || AuthenticationPredicates::IS_ADMIN(authentication);
});
// check for query parameters first, the old style from v2
@@ -97,8 +97,8 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
}
// output json buffer
PrettyAsyncJsonResponse * response = new PrettyAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
JsonObject output = response->getRoot();
auto * response = new PrettyAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
JsonObject output = response->getRoot();
// call command
uint8_t return_code = Command::process(request->url().c_str(), is_admin, input, output);

View File

@@ -99,10 +99,10 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
if (root["sensors"].is<JsonArray>()) {
for (const JsonObject sensorJson : root["sensors"].as<JsonArray>()) {
// create each of the sensor, overwritting any previous settings
SensorCustomization sensor = SensorCustomization();
sensor.id_str = sensorJson["id_str"].as<std::string>();
sensor.name = sensorJson["name"].as<std::string>();
sensor.offset = sensorJson["offset"];
auto sensor = SensorCustomization();
sensor.id_str = sensorJson["id_str"].as<std::string>();
sensor.name = sensorJson["name"].as<std::string>();
sensor.offset = sensorJson["offset"];
settings.sensorCustomizations.push_back(sensor); // add to list
}
}
@@ -112,13 +112,13 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
if (root["analogs"].is<JsonArray>()) {
for (const JsonObject analogJson : root["analogs"].as<JsonArray>()) {
// create each of the sensor, overwritting any previous settings
AnalogCustomization sensor = AnalogCustomization();
sensor.id = analogJson["id"];
sensor.name = analogJson["name"].as<std::string>();
sensor.offset = analogJson["offset"];
sensor.factor = analogJson["factor"];
sensor.uom = analogJson["uom"];
sensor.type = analogJson["type"];
auto sensor = AnalogCustomization();
sensor.id = analogJson["id"];
sensor.name = analogJson["name"].as<std::string>();
sensor.offset = analogJson["offset"];
sensor.factor = analogJson["factor"];
sensor.uom = analogJson["uom"];
sensor.type = analogJson["type"];
settings.analogCustomizations.push_back(sensor); // add to list
}
}
@@ -127,9 +127,9 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
settings.entityCustomizations.clear();
if (root["exclude_entities"].is<JsonArray>()) {
for (const JsonObject exclude_entities : root["exclude_entities"].as<JsonArray>()) {
EntityCustomization new_entry = EntityCustomization();
new_entry.product_id = exclude_entities["product_id"];
new_entry.device_id = exclude_entities["device_id"];
auto new_entry = EntityCustomization();
new_entry.product_id = exclude_entities["product_id"];
new_entry.device_id = exclude_entities["device_id"];
for (const JsonVariant exclude_entity_id : exclude_entities["entity_ids"].as<JsonArray>()) {
new_entry.entity_ids.push_back(exclude_entity_id.as<uint8_t>()); // add entity list
@@ -158,11 +158,11 @@ void WebCustomizationService::reset_customization(AsyncWebServerRequest * reques
// send back a short list devices used in the customization page
void WebCustomizationService::devices(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
JsonObject root = response->getRoot();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
JsonObject root = response->getRoot();
JsonArray devices = root.createNestedArray("devices");
for (auto & emsdevice : EMSESP::emsdevices) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice->has_entities()) {
JsonObject obj = devices.createNestedObject();
obj["i"] = emsdevice->unique_id(); // a unique id
@@ -185,18 +185,16 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
// send back list device entities
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(true, EMSESP_JSON_SIZE_XXLARGE_DYN);
auto * response = new MsgpackAsyncJsonResponse(true, EMSESP_JSON_SIZE_XXLARGE_DYN);
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
if (emsdevice->unique_id() == json["id"]) {
if (emsdevice->unique_id() == json["id"]) {
#ifndef EMSESP_STANDALONE
JsonArray output = response->getRoot();
emsdevice->generate_values_web_all(output);
JsonArray output = response->getRoot();
emsdevice->generate_values_web_all(output);
#endif
response->setLength();
request->send(response);
return;
}
response->setLength();
request->send(response);
return;
}
}
}

View File

@@ -70,13 +70,13 @@ void WebDataService::scan_devices(AsyncWebServerRequest * request) {
// this is used in the dashboard and contains all ems device information
// /coreData endpoint
void WebDataService::core_data(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
JsonObject root = response->getRoot();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
JsonObject root = response->getRoot();
// list is already sorted by device type
// Ignore Contoller
JsonArray devices = root.createNestedArray("devices");
for (auto & emsdevice : EMSESP::emsdevices) {
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice && emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER) {
JsonObject obj = devices.createNestedObject();
obj["i"] = emsdevice->unique_id(); // a unique id
@@ -102,8 +102,8 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
// /sensorData endpoint
// the "sensors" and "analogs" are arrays and must exist
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
JsonObject root = response->getRoot();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
JsonObject root = response->getRoot();
// dallas sensors
JsonArray sensors = root.createNestedArray("sensors");
@@ -158,23 +158,21 @@ void WebDataService::sensor_data(AsyncWebServerRequest * request) {
// Compresses the JSON using MsgPack https://msgpack.org/index.html
void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXXLARGE_DYN);
auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXXLARGE_DYN);
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
if (emsdevice->unique_id() == json["id"]) {
// wait max 2.5 sec for updated data (post_send_delay is 2 sec)
for (uint16_t i = 0; i < (emsesp::TxService::POST_SEND_DELAY + 500) && EMSESP::wait_validate(); i++) {
delay(1);
}
EMSESP::wait_validate(0); // reset in case of timeout
#ifndef EMSESP_STANDALONE
JsonObject output = response->getRoot();
emsdevice->generate_values_web(output);
#endif
response->setLength();
request->send(response);
return;
if (emsdevice->unique_id() == json["id"]) {
// wait max 2.5 sec for updated data (post_send_delay is 2 sec)
for (uint16_t i = 0; i < (emsesp::TxService::POST_SEND_DELAY + 500) && EMSESP::wait_validate(); i++) {
delay(1);
}
EMSESP::wait_validate(0); // reset in case of timeout
#ifndef EMSESP_STANDALONE
JsonObject output = response->getRoot();
emsdevice->generate_values_web(output);
#endif
response->setLength();
request->send(response);
return;
}
}
}
@@ -195,46 +193,44 @@ void WebDataService::write_value(AsyncWebServerRequest * request, JsonVariant &
// using the unique ID from the web find the real device type
// id is the selected device
for (const auto & emsdevice : EMSESP::emsdevices) {
if (emsdevice) {
if (emsdevice->unique_id() == unique_id) {
// parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp
const char * cmd = dv["c"]; // the command
int8_t id = -1; // default
cmd = Command::parse_command_string(cmd, id); // extract hc or wwc
if (emsdevice->unique_id() == unique_id) {
// parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp
const char * cmd = dv["c"]; // the command
int8_t id = -1; // default
cmd = Command::parse_command_string(cmd, id); // extract hc or wwc
// create JSON for output
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response->getRoot();
// create JSON for output
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject output = response->getRoot();
// the data could be in any format, but we need string
// authenticated is always true
JsonVariant data = dv["v"]; // the value in any format
uint8_t return_code = CommandRet::OK;
uint8_t device_type = emsdevice->device_type();
if (data.is<const char *>()) {
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
} else if (data.is<int>()) {
char s[10];
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int16_t>(), 0), true, id, output);
} else if (data.is<float>()) {
char s[10];
return_code = Command::call(device_type, cmd, Helpers::render_value(s, (float)data.as<float>(), 1), true, id, output);
} else if (data.is<bool>()) {
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
}
// write debug
if (return_code != CommandRet::OK) {
EMSESP::logger().err(F("Write command failed %s (%s)"), (const char *)output["message"], Command::return_code_string(return_code).c_str());
} else {
EMSESP::logger().debug(F("Write command successful"));
}
response->setCode((return_code == CommandRet::OK) ? 200 : 204);
response->setLength();
request->send(response);
return;
// the data could be in any format, but we need string
// authenticated is always true
JsonVariant data = dv["v"]; // the value in any format
uint8_t return_code = CommandRet::OK;
uint8_t device_type = emsdevice->device_type();
if (data.is<const char *>()) {
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
} else if (data.is<int>()) {
char s[10];
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int16_t>(), 0), true, id, output);
} else if (data.is<float>()) {
char s[10];
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<float>(), 1), true, id, output);
} else if (data.is<bool>()) {
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
}
// write debug
if (return_code != CommandRet::OK) {
EMSESP::logger().err(F("Write command failed %s (%s)"), (const char *)output["message"], Command::return_code_string(return_code).c_str());
} else {
EMSESP::logger().debug(F("Write command successful"));
}
response->setCode((return_code == CommandRet::OK) ? 200 : 204);
response->setLength();
request->send(response);
return;
}
}
}

View File

@@ -90,7 +90,7 @@ void WebLogService::maximum_log_messages(size_t count) {
"local");
}
bool WebLogService::compact() {
bool WebLogService::compact() const {
return compact_;
}
@@ -156,24 +156,24 @@ void WebLogService::loop() {
}
// convert time to real offset
char * WebLogService::messagetime(char * out, const uint64_t t) {
char * WebLogService::messagetime(char * out, const uint64_t t, const size_t bufsize) {
if (!time_offset_) {
strcpy(out, uuid::log::format_timestamp_ms(t, 3).c_str());
strlcpy(out, uuid::log::format_timestamp_ms(t, 3).c_str(), bufsize);
} else {
time_t t1 = time_offset_ + t / 1000ULL;
strftime(out, 25, "%F %T", localtime(&t1));
snprintf(out, 25, "%s.%03d", out, (uint16_t)(t % 1000));
strftime(out, bufsize, "%F %T", localtime(&t1));
snprintf(out, bufsize, "%s.%03d", out, (uint16_t)(t % 1000));
}
return out;
}
// send to web eventsource
void WebLogService::transmit(const QueuedLogMessage & message) {
DynamicJsonDocument jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
JsonObject logEvent = jsonDocument.to<JsonObject>();
char time_string[25];
auto jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
JsonObject logEvent = jsonDocument.to<JsonObject>();
char time_string[25];
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms);
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
logEvent["l"] = message.content_->level;
logEvent["i"] = message.id_;
logEvent["n"] = message.content_->name;
@@ -190,9 +190,9 @@ void WebLogService::transmit(const QueuedLogMessage & message) {
// send the complete log buffer to the API, not filtering on log level
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
JsonObject root = response->getRoot();
JsonArray log = root.createNestedArray("events");
auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
JsonObject root = response->getRoot();
JsonArray log = root.createNestedArray("events");
log_message_id_tail_ = log_messages_.back().id_;
last_transmit_ = uuid::get_uptime_ms();
@@ -200,7 +200,7 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
JsonObject logEvent = log.createNestedObject();
char time_string[25];
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms);
logEvent["t"] = messagetime(time_string, message.content_->uptime_ms, sizeof(time_string));
logEvent["l"] = message.content_->level;
logEvent["i"] = message.id_;
logEvent["n"] = message.content_->name;
@@ -213,7 +213,7 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
// sets the values like level after a POST
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
if (not json.is<JsonObject>()) {
if (!json.is<JsonObject>()) {
return;
}
@@ -233,11 +233,11 @@ void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & jso
// return the current value settings after a GET
void WebLogService::getValues(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject root = response->getRoot();
root["level"] = log_level();
root["max_messages"] = maximum_log_messages();
root["compact"] = compact();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
JsonObject root = response->getRoot();
root["level"] = log_level();
root["max_messages"] = maximum_log_messages();
root["compact"] = compact();
response->setLength();
request->send(response);
}

View File

@@ -38,7 +38,7 @@ class WebLogService : public uuid::log::Handler {
void log_level(uuid::log::Level level);
size_t maximum_log_messages() const;
void maximum_log_messages(size_t count);
bool compact();
bool compact() const;
void compact(bool compact);
void loop();
@@ -62,9 +62,10 @@ class WebLogService : public uuid::log::Handler {
void fetchLog(AsyncWebServerRequest * request);
void getValues(AsyncWebServerRequest * request);
char * messagetime(char * out, const uint64_t t);
char * messagetime(char * out, const uint64_t t, const size_t bufsize);
void setValues(AsyncWebServerRequest * request, JsonVariant & json);
void setValues(AsyncWebServerRequest * request, JsonVariant & json);
AsyncCallbackJsonWebHandler setValues_; // for POSTs
uint64_t last_transmit_ = 0; // Last transmit time

View File

@@ -271,8 +271,8 @@ void WebSettingsService::save() {
// build the json profile to send back
void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVariant & json) {
if (json.is<JsonObject>()) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
JsonObject root = response->getRoot();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
JsonObject root = response->getRoot();
if (json.containsKey("board_profile")) {
String board_profile = json["board_profile"];

View File

@@ -126,8 +126,8 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
}
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM_DYN);
JsonObject root = response->getRoot();
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM_DYN);
JsonObject root = response->getRoot();
root["status"] = EMSESP::bus_status(); // 0, 1 or 2
root["num_devices"] = EMSESP::count_devices(); // excluding Controller
@@ -163,7 +163,7 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
}
// start the multicast UDP service so EMS-ESP is discoverable via .local
void WebStatusService::mDNS_start() {
void WebStatusService::mDNS_start() const {
#ifndef EMSESP_STANDALONE
MDNS.end();
if (!MDNS.begin(EMSESP::system_.hostname().c_str())) {

View File

@@ -32,7 +32,7 @@ class WebStatusService {
private:
void webStatusService(AsyncWebServerRequest * request);
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
void mDNS_start();
void mDNS_start() const;
};
} // namespace emsesp