mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
Merge branch 'dev' of https://github.com/emsesp/EMS-ESP32 into dev_no_master_thermostat
This commit is contained in:
56
.github/workflows/sonar_check.yml
vendored
Normal file
56
.github/workflows/sonar_check.yml
vendored
Normal 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
5
.gitignore
vendored
@@ -28,3 +28,8 @@ node_modules
|
|||||||
test.sh
|
test.sh
|
||||||
scripts/__pycache__
|
scripts/__pycache__
|
||||||
.temp
|
.temp
|
||||||
|
|
||||||
|
# sonar
|
||||||
|
.scannerwork/
|
||||||
|
sonar/
|
||||||
|
build_wrapper_output_directory/
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -113,6 +113,7 @@ COMPILE.cpp = $(CXX) $(CXX_STANDARD) $(CXXFLAGS) $(DEPFLAGS) -c $< -o $@
|
|||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
# Targets
|
# Targets
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
|
.PHONY: all
|
||||||
all: $(OUTPUT)
|
all: $(OUTPUT)
|
||||||
|
|
||||||
$(OUTPUT): $(OBJS)
|
$(OUTPUT): $(OBJS)
|
||||||
@@ -138,6 +139,7 @@ cppcheck: $(SOURCES)
|
|||||||
run: $(OUTPUT)
|
run: $(OUTPUT)
|
||||||
@$<
|
@$<
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@$(RM) -r $(BUILD) $(OUTPUT)
|
@$(RM) -r $(BUILD) $(OUTPUT)
|
||||||
|
|
||||||
|
|||||||
14
interface/package-lock.json
generated
14
interface/package-lock.json
generated
@@ -16,7 +16,7 @@
|
|||||||
"@types/lodash": "^4.14.179",
|
"@types/lodash": "^4.14.179",
|
||||||
"@types/node": "^17.0.21",
|
"@types/node": "^17.0.21",
|
||||||
"@types/react": "^17.0.39",
|
"@types/react": "^17.0.39",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.13",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.0.7",
|
||||||
"axios": "^0.26.0",
|
"axios": "^0.26.0",
|
||||||
@@ -3793,9 +3793,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "17.0.11",
|
"version": "17.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.13.tgz",
|
||||||
"integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
|
"integrity": "sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
@@ -20246,9 +20246,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "17.0.11",
|
"version": "17.0.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.13.tgz",
|
||||||
"integrity": "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==",
|
"integrity": "sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"@types/lodash": "^4.14.179",
|
"@types/lodash": "^4.14.179",
|
||||||
"@types/node": "^17.0.21",
|
"@types/node": "^17.0.21",
|
||||||
"@types/react": "^17.0.39",
|
"@types/react": "^17.0.39",
|
||||||
"@types/react-dom": "^17.0.11",
|
"@types/react-dom": "^17.0.13",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"async-validator": "^4.0.7",
|
"async-validator": "^4.0.7",
|
||||||
"axios": "^0.26.0",
|
"axios": "^0.26.0",
|
||||||
|
|||||||
8
scripts/run_sonar.sh
Executable file
8
scripts/run_sonar.sh
Executable 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
11
sonar-project.properties
Normal 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
|
||||||
@@ -64,12 +64,11 @@ void AnalogSensor::reload() {
|
|||||||
// load the list of analog sensors from the customization service
|
// load the list of analog sensors from the customization service
|
||||||
// and store them locally and then activate them
|
// and store them locally and then activate them
|
||||||
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
||||||
auto sensors = settings.analogCustomizations;
|
auto it = sensors_.begin();
|
||||||
auto it = sensors_.begin();
|
|
||||||
for (auto & sensor_ : sensors_) {
|
for (auto & sensor_ : sensors_) {
|
||||||
// update existing sensors
|
// update existing sensors
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto & sensor : sensors) { //search customlist
|
for (const auto & sensor : settings.analogCustomizations) { //search customlist
|
||||||
if (sensor_.id() == sensor.id) {
|
if (sensor_.id() == sensor.id) {
|
||||||
// for output sensors set value to new start-value
|
// for output sensors set value to new start-value
|
||||||
if ((sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT)
|
if ((sensor.type == AnalogType::COUNTER || sensor.type >= AnalogType::DIGITAL_OUT)
|
||||||
@@ -90,10 +89,11 @@ void AnalogSensor::reload() {
|
|||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// add new sensors from list
|
// add new sensors from list
|
||||||
for (auto & sensor : sensors) {
|
for (const auto & sensor : settings.analogCustomizations) {
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto & sensor_ : sensors_) {
|
for (const auto & sensor_ : sensors_) {
|
||||||
if (sensor_.id() == sensor.id) {
|
if (sensor_.id() == sensor.id) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@@ -295,13 +295,13 @@ bool AnalogSensor::update(uint8_t id, const std::string & name, float offset, fl
|
|||||||
if (!found_sensor) {
|
if (!found_sensor) {
|
||||||
EMSESP::webCustomizationService.update(
|
EMSESP::webCustomizationService.update(
|
||||||
[&](WebCustomization & settings) {
|
[&](WebCustomization & settings) {
|
||||||
AnalogCustomization newSensor = AnalogCustomization();
|
auto newSensor = AnalogCustomization();
|
||||||
newSensor.id = id;
|
newSensor.id = id;
|
||||||
newSensor.name = name;
|
newSensor.name = name;
|
||||||
newSensor.offset = offset;
|
newSensor.offset = offset;
|
||||||
newSensor.factor = factor;
|
newSensor.factor = factor;
|
||||||
newSensor.uom = uom;
|
newSensor.uom = uom;
|
||||||
newSensor.type = type;
|
newSensor.type = type;
|
||||||
settings.analogCustomizations.push_back(newSensor);
|
settings.analogCustomizations.push_back(newSensor);
|
||||||
LOG_DEBUG(F("Adding new customization for analog sensor ID %d"), id);
|
LOG_DEBUG(F("Adding new customization for analog sensor ID %d"), id);
|
||||||
return StateUpdateResult::CHANGED; // persist the change
|
return StateUpdateResult::CHANGED; // persist the change
|
||||||
@@ -325,7 +325,7 @@ bool AnalogSensor::updated_values() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// publish a single sensor to MQTT
|
// 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()) {
|
if (Mqtt::publish_single()) {
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
if (Mqtt::publish_single2cmd()) {
|
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
|
// 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()) {
|
if (!Mqtt::ha_enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -363,7 +363,6 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
publish_sensor(sensor);
|
publish_sensor(sensor);
|
||||||
}
|
}
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(120 * num_sensors);
|
DynamicJsonDocument doc(120 * num_sensors);
|
||||||
@@ -383,61 +382,59 @@ void AnalogSensor::publish_values(const bool force) {
|
|||||||
case AnalogType::PWM_0:
|
case AnalogType::PWM_0:
|
||||||
case AnalogType::PWM_1:
|
case AnalogType::PWM_1:
|
||||||
case AnalogType::PWM_2:
|
case AnalogType::PWM_2:
|
||||||
dataSensor["value"] = (float)sensor.value(); // float
|
dataSensor["value"] = sensor.value(); // float
|
||||||
break;
|
break;
|
||||||
case AnalogType::DIGITAL_IN:
|
|
||||||
case AnalogType::DIGITAL_OUT:
|
|
||||||
default:
|
default:
|
||||||
dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0
|
dataSensor["value"] = (uint8_t)sensor.value(); // convert to char for 1 or 0
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create HA config
|
// create HA config
|
||||||
if (Mqtt::ha_enabled()) {
|
if (Mqtt::ha_enabled() && (!sensor.ha_registered || force)) {
|
||||||
if (!sensor.ha_registered || force) {
|
LOG_DEBUG(F("Recreating HA config for analog sensor ID %d"), sensor.id());
|
||||||
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];
|
char stat_t[50];
|
||||||
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str());
|
snprintf(stat_t, sizeof(stat_t), "%s/analogsensor_data", Mqtt::base().c_str());
|
||||||
config["stat_t"] = stat_t;
|
config["stat_t"] = stat_t;
|
||||||
|
|
||||||
char str[50];
|
char str[50];
|
||||||
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.id());
|
snprintf(str, sizeof(str), "{{value_json['%d'].value}}", sensor.id());
|
||||||
config["val_tpl"] = str;
|
config["val_tpl"] = str;
|
||||||
|
|
||||||
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
|
snprintf(str, sizeof(str), "Analog Sensor %s", sensor.name().c_str());
|
||||||
config["name"] = str;
|
config["name"] = str;
|
||||||
|
|
||||||
snprintf(str, sizeof(str), "analogsensor_%d", sensor.id());
|
snprintf(str, sizeof(str), "analogsensor_%d", sensor.id());
|
||||||
config["uniq_id"] = str;
|
config["uniq_id"] = str;
|
||||||
|
|
||||||
JsonObject dev = config.createNestedObject("dev");
|
JsonObject dev = config.createNestedObject("dev");
|
||||||
JsonArray ids = dev.createNestedArray("ids");
|
JsonArray ids = dev.createNestedArray("ids");
|
||||||
ids.add("ems-esp");
|
ids.add("ems-esp");
|
||||||
|
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf(topic, sizeof(topic), "sensor/%s/analogsensor_%d/config", Mqtt::base().c_str(), sensor.id());
|
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 {
|
} else {
|
||||||
// not nested
|
// not nested
|
||||||
doc[sensor.name()] = sensor.value();
|
doc[sensor.name()] = sensor.value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mqtt::publish(F("analogsensor_data"), doc.as<JsonObject>());
|
Mqtt::publish(F("analogsensor_data"), doc.as<JsonObject>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from emsesp.cpp, similar to the emsdevice->get_value_info
|
// called from emsesp.cpp, similar to the emsdevice->get_value_info
|
||||||
// searches by name
|
// 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_) {
|
for (const auto & sensor : sensors_) {
|
||||||
if (strcmp(cmd, sensor.name().c_str()) == 0) {
|
if (strcmp(cmd, sensor.name().c_str()) == 0) {
|
||||||
output["id"] = sensor.id();
|
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
|
// creates JSON doc from values
|
||||||
// returns false if there are no sensors
|
// returns false if there are no sensors
|
||||||
bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject & output) {
|
bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject & output) const {
|
||||||
if (sensors_.size() == 0) {
|
if (sensors_.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,7 +529,7 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t id) {
|
|||||||
return true;
|
return true;
|
||||||
} else if (sensor.type() == AnalogType::DIGITAL_OUT) {
|
} else if (sensor.type() == AnalogType::DIGITAL_OUT) {
|
||||||
uint8_t v = val;
|
uint8_t v = val;
|
||||||
if ((sensor.id() == 25 || sensor.id() == 26)) {
|
if (sensor.id() == 25 || sensor.id() == 26) {
|
||||||
sensor.set_offset(v);
|
sensor.set_offset(v);
|
||||||
sensor.set_value(v);
|
sensor.set_value(v);
|
||||||
pinMode(sensor.id(), OUTPUT);
|
pinMode(sensor.id(), OUTPUT);
|
||||||
@@ -573,7 +570,6 @@ bool AnalogSensor::command_commands(const char * value, const int8_t id, JsonObj
|
|||||||
// hard coded tests
|
// hard coded tests
|
||||||
#ifdef EMSESP_DEBUG
|
#ifdef EMSESP_DEBUG
|
||||||
void AnalogSensor::test() {
|
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_.emplace_back(36, "test12", 0, 0.1, 17, AnalogType::ADC);
|
||||||
sensors_.back().set_value(12.4);
|
sensors_.back().set_value(12.4);
|
||||||
|
|
||||||
|
|||||||
@@ -127,38 +127,38 @@ class AnalogSensor {
|
|||||||
|
|
||||||
void start();
|
void start();
|
||||||
void loop();
|
void loop();
|
||||||
void publish_sensor(const Sensor & sensor);
|
void publish_sensor(const Sensor & sensor) const;
|
||||||
void publish_values(const bool force);
|
void publish_values(const bool force);
|
||||||
void reload();
|
void reload();
|
||||||
bool updated_values();
|
bool updated_values();
|
||||||
|
|
||||||
// return back reference to the sensor list, used by other classes
|
// return back reference to the sensor list, used by other classes
|
||||||
const std::vector<Sensor> sensors() const {
|
std::vector<Sensor> sensors() const {
|
||||||
return sensors_;
|
return sensors_;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t reads() {
|
uint32_t reads() const {
|
||||||
return sensorreads_;
|
return sensorreads_;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t fails() {
|
uint32_t fails() const {
|
||||||
return sensorfails_;
|
return sensorfails_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool analog_enabled() {
|
bool analog_enabled() const {
|
||||||
return (analog_enabled_);
|
return (analog_enabled_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool have_sensors() {
|
bool have_sensors() const {
|
||||||
return (sensors_.size() > 0);
|
return (!sensors_.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t no_sensors() {
|
size_t no_sensors() const {
|
||||||
return sensors_.size();
|
return sensors_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update(uint8_t id, const std::string & name, float offset, float factor, uint8_t uom, int8_t type);
|
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
|
#ifdef EMSESP_DEBUG
|
||||||
void test();
|
void test();
|
||||||
@@ -170,10 +170,10 @@ class AnalogSensor {
|
|||||||
|
|
||||||
static uuid::log::Logger logger_;
|
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);
|
bool command_setvalue(const char * value, const int8_t id);
|
||||||
void measure();
|
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);
|
bool command_commands(const char * value, const int8_t id, JsonObject & output);
|
||||||
|
|
||||||
std::vector<Sensor> sensors_; // our list of sensors
|
std::vector<Sensor> sensors_; // our list of sensors
|
||||||
|
|||||||
124
src/command.cpp
124
src/command.cpp
@@ -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/"
|
// 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());
|
p.paths().erase(p.paths().begin());
|
||||||
} else {
|
} else {
|
||||||
// not /api, so must be MQTT path. Check for base and remove it.
|
// not /api, so must be MQTT path. Check for base and remove it.
|
||||||
if (!strncmp(path, Mqtt::base().c_str(), Mqtt::base().length())) {
|
if (!strncmp(path, Mqtt::base().c_str(), Mqtt::base().length())) {
|
||||||
char new_path[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
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
|
p.parse(new_path + Mqtt::base().length() + 1); // re-parse the stripped path
|
||||||
} else {
|
} else {
|
||||||
return message(CommandRet::ERROR, "unrecognized path", output); // error
|
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);
|
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>()) {
|
} else if (data.is<float>()) {
|
||||||
char data_str[10];
|
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()) {
|
} else if (data.isNull()) {
|
||||||
return_code = Command::call(device_type, command_p, "", is_admin, id_n, output); // empty, will do a query instead
|
return_code = Command::call(device_type, command_p, "", is_admin, id_n, output); // empty, will do a query instead
|
||||||
} else {
|
} else {
|
||||||
@@ -160,22 +160,19 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
|
|||||||
return return_code;
|
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) {
|
switch (return_code) {
|
||||||
case CommandRet::ERROR:
|
case CommandRet::ERROR:
|
||||||
return read_flash_string(F("Error"));
|
return read_flash_string(F("Error"));
|
||||||
break;
|
|
||||||
case CommandRet::OK:
|
case CommandRet::OK:
|
||||||
return read_flash_string(F("OK"));
|
return read_flash_string(F("OK"));
|
||||||
break;
|
|
||||||
case CommandRet::NOT_FOUND:
|
case CommandRet::NOT_FOUND:
|
||||||
return read_flash_string(F("Not Found"));
|
return read_flash_string(F("Not Found"));
|
||||||
break;
|
|
||||||
case CommandRet::NOT_ALLOWED:
|
case CommandRet::NOT_ALLOWED:
|
||||||
return read_flash_string(F("Not Authorized"));
|
return read_flash_string(F("Not Authorized"));
|
||||||
break;
|
|
||||||
case CommandRet::FAIL:
|
case CommandRet::FAIL:
|
||||||
return read_flash_string(F("Failed"));
|
return read_flash_string(F("Failed"));
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
char s[4];
|
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
|
// make a copy of the string command for parsing
|
||||||
char command_s[100];
|
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
|
// look for a delimeter and split the string
|
||||||
char * p = command_s;
|
char * p = command_s;
|
||||||
@@ -365,7 +362,7 @@ bool Command::list(const uint8_t device_type, JsonObject & output) {
|
|||||||
}
|
}
|
||||||
sorted_cmds.sort();
|
sorted_cmds.sort();
|
||||||
|
|
||||||
for (auto & cl : sorted_cmds) {
|
for (const auto & cl : sorted_cmds) {
|
||||||
for (const auto & cf : cmdfunctions_) {
|
for (const auto & cf : cmdfunctions_) {
|
||||||
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) {
|
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) {
|
||||||
output[cl] = cf.description_;
|
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 not in verbose mode, just print them on a single line
|
||||||
if (!verbose) {
|
if (!verbose) {
|
||||||
for (auto & cl : sorted_cmds) {
|
for (const auto & cl : sorted_cmds) {
|
||||||
shell.print(cl);
|
shell.print(cl);
|
||||||
shell.print(" ");
|
shell.print(" ");
|
||||||
}
|
}
|
||||||
@@ -404,7 +401,7 @@ void Command::show(uuid::console::Shell & shell, uint8_t device_type, bool verbo
|
|||||||
|
|
||||||
// verbose mode
|
// verbose mode
|
||||||
shell.println();
|
shell.println();
|
||||||
for (auto & cl : sorted_cmds) {
|
for (const auto & cl : sorted_cmds) {
|
||||||
// find and print the description
|
// find and print the description
|
||||||
for (const auto & cf : cmdfunctions_) {
|
for (const auto & cf : cmdfunctions_) {
|
||||||
if ((cf.device_type_ == device_type) && !cf.has_flags(CommandFlag::HIDDEN) && cf.description_ && (cl == read_flash_string(cf.cmd_))) {
|
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) {
|
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
|
// device found, now see if it has any commands
|
||||||
for (const auto & cf : cmdfunctions_) {
|
for (const auto & cf : cmdfunctions_) {
|
||||||
if (cf.device_type_ == device_type) {
|
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 & device_class : EMSFactory::device_handlers()) {
|
||||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
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());
|
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)
|
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
|
// e.g. //one/two////three/// becomes /one/two/three
|
||||||
std::string SUrlParser::path() {
|
std::string SUrlParser::path() {
|
||||||
std::string s = "/"; // set up the beginning slash
|
std::string s = "/"; // set up the beginning slash
|
||||||
for (std::string & f : m_folders) {
|
for (const std::string & f : m_folders) {
|
||||||
s += f;
|
s += f;
|
||||||
s += "/";
|
s += "/";
|
||||||
}
|
}
|
||||||
@@ -554,6 +551,14 @@ SUrlParser::SUrlParser(const char * uri) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool SUrlParser::parse(const char * uri) {
|
bool SUrlParser::parse(const char * uri) {
|
||||||
|
if (uri == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*uri == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_folders.clear();
|
m_folders.clear();
|
||||||
m_keysvalues.clear();
|
m_keysvalues.clear();
|
||||||
enum Type { begin, folder, param, value };
|
enum Type { begin, folder, param, value };
|
||||||
@@ -563,54 +568,53 @@ bool SUrlParser::parse(const char * uri) {
|
|||||||
enum Type t = Type::begin;
|
enum Type t = Type::begin;
|
||||||
std::string last_param;
|
std::string last_param;
|
||||||
|
|
||||||
if (c != nullptr || *c != '\0') {
|
do {
|
||||||
do {
|
if (*c == '/') {
|
||||||
if (*c == '/') {
|
if (s.length() > 0) {
|
||||||
if (s.length() > 0) {
|
m_folders.push_back(s);
|
||||||
m_folders.push_back(s);
|
s.clear();
|
||||||
s.clear();
|
}
|
||||||
}
|
t = Type::folder;
|
||||||
t = Type::folder;
|
} else if (*c == '?' && (t == Type::folder || t == Type::begin)) {
|
||||||
} else if (*c == '?' && (t == Type::folder || t == Type::begin)) {
|
if (s.length() > 0) {
|
||||||
if (s.length() > 0) {
|
m_folders.push_back(s);
|
||||||
m_folders.push_back(s);
|
s.clear();
|
||||||
s.clear();
|
}
|
||||||
}
|
t = Type::param;
|
||||||
t = Type::param;
|
} else if (*c == '=' && (t == Type::param || t == Type::begin)) {
|
||||||
} 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] = "";
|
m_keysvalues[s] = "";
|
||||||
last_param = 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,22 +125,22 @@ class Command {
|
|||||||
|
|
||||||
static const char * parse_command_string(const char * command, int8_t & id);
|
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:
|
private:
|
||||||
static uuid::log::Logger logger_;
|
static uuid::log::Logger logger_;
|
||||||
|
|
||||||
static std::vector<CmdFunction> cmdfunctions_; // the list of commands
|
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.clear();
|
||||||
output["message"] = (const char *)message;
|
output["message"] = message;
|
||||||
return error_code;
|
return error_code;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unordered_map<std::string, std::string> KeyValueMap_t;
|
using KeyValueMap_t = std::unordered_map<std::string, std::string>;
|
||||||
typedef std::vector<std::string> Folder_t;
|
using Folder_t = std::vector<std::string>;
|
||||||
|
|
||||||
class SUrlParser {
|
class SUrlParser {
|
||||||
private:
|
private:
|
||||||
@@ -148,7 +148,7 @@ class SUrlParser {
|
|||||||
Folder_t m_folders;
|
Folder_t m_folders;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SUrlParser(){};
|
SUrlParser() = default;
|
||||||
SUrlParser(const char * url);
|
SUrlParser(const char * url);
|
||||||
|
|
||||||
bool parse(const char * url);
|
bool parse(const char * url);
|
||||||
|
|||||||
@@ -31,9 +31,8 @@ std::shared_ptr<Commands> EMSESPShell::commands = [] {
|
|||||||
return commands;
|
return commands;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
static std::shared_ptr<EMSESPShell> shell;
|
std::shared_ptr<EMSESPShell> shell;
|
||||||
|
std::vector<bool> EMSESPStreamConsole::ptys_;
|
||||||
std::vector<bool> EMSESPStreamConsole::ptys_;
|
|
||||||
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
uuid::telnet::TelnetService telnet_([](Stream & stream, const IPAddress & addr, uint16_t port) -> std::shared_ptr<uuid::console::Shell> {
|
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("test")},
|
||||||
flash_string_vector{F_(name_optional), F_(data_optional)},
|
flash_string_vector{F_(name_optional), F_(data_optional)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
if (arguments.size() == 0) {
|
if (arguments.empty()) {
|
||||||
Test::run_test(shell, "default");
|
Test::run_test(shell, "default");
|
||||||
} else if (arguments.size() == 1) {
|
} else if (arguments.size() == 1) {
|
||||||
Test::run_test(shell, arguments.front());
|
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_(debug)},
|
||||||
flash_string_vector{F_(name_optional)},
|
flash_string_vector{F_(name_optional)},
|
||||||
[](Shell & shell, const std::vector<std::string> & arguments) {
|
[](Shell & shell, const std::vector<std::string> & arguments) {
|
||||||
if (arguments.size() == 0) {
|
if (arguments.empty()) {
|
||||||
Test::debug(shell, "default");
|
Test::debug(shell, "default");
|
||||||
} else {
|
} else {
|
||||||
Test::debug(shell, arguments.front());
|
Test::debug(shell, arguments.front());
|
||||||
@@ -515,10 +514,7 @@ void Console::load_standard_commands(unsigned int context) {
|
|||||||
EMSESPShell::commands->add_command(context,
|
EMSESPShell::commands->add_command(context,
|
||||||
CommandFlags::USER,
|
CommandFlags::USER,
|
||||||
flash_string_vector{F_(exit)},
|
flash_string_vector{F_(exit)},
|
||||||
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) {
|
[=](Shell & shell, const std::vector<std::string> & arguments __attribute__((unused))) { shell.stop(); });
|
||||||
shell.stop();
|
|
||||||
// shell.exit_context();
|
|
||||||
});
|
|
||||||
|
|
||||||
EMSESPShell::commands->add_command(context,
|
EMSESPShell::commands->add_command(context,
|
||||||
CommandFlags::USER,
|
CommandFlags::USER,
|
||||||
|
|||||||
@@ -354,7 +354,7 @@ bool DallasSensor::command_commands(const char * value, const int8_t id, JsonObj
|
|||||||
// creates JSON doc from values
|
// creates JSON doc from values
|
||||||
// returns false if there are no sensors
|
// returns false if there are no sensors
|
||||||
bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject & output) {
|
bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject & output) {
|
||||||
if (sensors_.size() == 0) {
|
if (sensors_.empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +435,6 @@ void DallasSensor::publish_values(const bool force) {
|
|||||||
for (const auto & sensor : sensors_) {
|
for (const auto & sensor : sensors_) {
|
||||||
publish_sensor(sensor);
|
publish_sensor(sensor);
|
||||||
}
|
}
|
||||||
// return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument doc(120 * num_sensors);
|
DynamicJsonDocument doc(120 * num_sensors);
|
||||||
@@ -536,8 +535,8 @@ std::string DallasSensor::Sensor::name() const {
|
|||||||
bool DallasSensor::Sensor::apply_customization() {
|
bool DallasSensor::Sensor::apply_customization() {
|
||||||
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
||||||
auto sensors = settings.sensorCustomizations;
|
auto sensors = settings.sensorCustomizations;
|
||||||
if (sensors.size() != 0) {
|
if (sensors.empty()) {
|
||||||
for (auto & sensor : sensors) {
|
for (const auto & sensor : sensors) {
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id_str.c_str());
|
LOG_DEBUG(F("Loading customization for dallas sensor %s"), sensor.id_str.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ class DallasSensor {
|
|||||||
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);
|
||||||
|
|
||||||
// return back reference to the sensor list, used by other classes
|
// return back reference to the sensor list, used by other classes
|
||||||
const std::vector<Sensor> sensors() const {
|
std::vector<Sensor> sensors() const {
|
||||||
return sensors_;
|
return sensors_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ class DallasSensor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool have_sensors() {
|
bool have_sensors() {
|
||||||
return (sensors_.size() > 0);
|
return (!sensors_.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t no_sensors() {
|
size_t no_sensors() {
|
||||||
|
|||||||
@@ -532,7 +532,7 @@ void Boiler::process_UBAParameterWW(std::shared_ptr<const Telegram> telegram) {
|
|||||||
has_update(telegram, wwDisinfectionTemp_, 8);
|
has_update(telegram, wwDisinfectionTemp_, 8);
|
||||||
has_bitupdate(telegram, wwChargeType_, 10, 0); // 0 = charge pump, 0xff = 3-way valve
|
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);
|
telegram->read_value(wwComfort, 9);
|
||||||
if (wwComfort == 0) {
|
if (wwComfort == 0) {
|
||||||
wwComfort = 0; // Hot
|
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
|
// read 3 char service code / installation status as appears on the display
|
||||||
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
|
if ((telegram->message_length > 3) && (telegram->offset == 0)) {
|
||||||
char serviceCode[4];
|
char serviceCode[4] = {0};
|
||||||
telegram->read_value(serviceCode[0], 1);
|
telegram->read_value(serviceCode[0], 1);
|
||||||
serviceCode[0] = (serviceCode[0] == (char)0xF0) ? '~' : serviceCode[0];
|
serviceCode[0] = (serviceCode[0] == (char)0xF0) ? '~' : serviceCode[0];
|
||||||
telegram->read_value(serviceCode[1], 2);
|
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
|
if (telegram->message_data[4] & 0x80) { // valid date
|
||||||
|
|
||||||
static uint32_t lastCodeDate_ = 0; // last code date
|
static uint32_t lastCodeDate_ = 0; // last code date
|
||||||
char code[3];
|
char code[3] = {0};
|
||||||
uint16_t codeNo;
|
uint16_t codeNo = EMS_VALUE_SHORT_NOTSET;
|
||||||
code[0] = telegram->message_data[0];
|
code[0] = telegram->message_data[0];
|
||||||
code[1] = telegram->message_data[1];
|
code[1] = telegram->message_data[1];
|
||||||
code[2] = 0;
|
code[2] = 0;
|
||||||
telegram->read_value(codeNo, 2);
|
telegram->read_value(codeNo, 2);
|
||||||
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
|
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
|
||||||
uint8_t month = telegram->message_data[5];
|
uint8_t month = telegram->message_data[5];
|
||||||
uint8_t day = telegram->message_data[7];
|
uint8_t day = telegram->message_data[7];
|
||||||
uint8_t hour = telegram->message_data[6];
|
uint8_t hour = telegram->message_data[6];
|
||||||
uint8_t min = telegram->message_data[8];
|
uint8_t min = telegram->message_data[8];
|
||||||
uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min;
|
uint32_t date = (year - 2000) * 535680UL + month * 44640UL + day * 1440UL + hour * 60 + min;
|
||||||
uint16_t duration;
|
uint16_t duration = EMS_VALUE_SHORT_NOTSET;
|
||||||
telegram->read_value(duration, 9);
|
telegram->read_value(duration, 9);
|
||||||
// store only the newest code from telegrams 10 and 11
|
// store only the newest code from telegrams 10 and 11
|
||||||
if (date > lastCodeDate_) {
|
if (date > lastCodeDate_) {
|
||||||
@@ -908,12 +908,12 @@ void Boiler::process_UBAErrorMessage2(std::shared_ptr<const Telegram> telegram)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char code[sizeof(lastCode_)];
|
char code[sizeof(lastCode_)] = {0};
|
||||||
uint16_t codeNo;
|
uint16_t codeNo = EMS_VALUE_SHORT_NOTSET;
|
||||||
code[0] = telegram->message_data[5];
|
code[0] = telegram->message_data[5];
|
||||||
code[1] = telegram->message_data[6];
|
code[1] = telegram->message_data[6];
|
||||||
code[2] = telegram->message_data[7];
|
code[2] = telegram->message_data[7];
|
||||||
code[3] = 0;
|
code[3] = 0;
|
||||||
telegram->read_value(codeNo, 8);
|
telegram->read_value(codeNo, 8);
|
||||||
|
|
||||||
// check for valid date, https://github.com/emsesp/EMS-ESP32/issues/204
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//maintenance
|
// maintenance
|
||||||
bool Boiler::set_maintenance(const char * value, const int8_t id) {
|
bool Boiler::set_maintenance(const char * value, const int8_t id) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string s;
|
std::string s;
|
||||||
if (Helpers::value2string(value, s)) {
|
if (Helpers::value2string(value, s)) {
|
||||||
if (s == Helpers::toLower(read_flash_string(F_(reset)))) {
|
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
|
//maintenance
|
||||||
bool Boiler::set_maintenancedate(const char * value, const int8_t id) {
|
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 day = (value[0] - '0') * 10 + (value[1] - '0');
|
||||||
uint8_t month = (value[3] - '0') * 10 + (value[4] - '0');
|
uint8_t month = (value[3] - '0') * 10 + (value[4] - '0');
|
||||||
uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000);
|
uint8_t year = (uint8_t)(Helpers::atoint(&value[6]) - 2000);
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ std::shared_ptr<Thermostat::HeatingCircuit> Thermostat::heating_circuit(std::sha
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// if it's the first set the status flag
|
// if it's the first set the status flag
|
||||||
if (heating_circuits_.size() == 0) {
|
if (heating_circuits_.empty()) {
|
||||||
strlcpy(status_, "online", sizeof(status_));
|
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
|
// 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()) {
|
if (!Mqtt::ha_enabled()) {
|
||||||
hc->climate = EMS_VALUE_UINT_NOTSET;
|
hc->climate = EMS_VALUE_UINT_NOTSET;
|
||||||
return;
|
return;
|
||||||
@@ -452,65 +452,44 @@ std::string Thermostat::mode_tostring(uint8_t mode) {
|
|||||||
switch (mode) {
|
switch (mode) {
|
||||||
case HeatingCircuit::Mode::OFF:
|
case HeatingCircuit::Mode::OFF:
|
||||||
return read_flash_string(F_(off));
|
return read_flash_string(F_(off));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::MANUAL:
|
case HeatingCircuit::Mode::MANUAL:
|
||||||
return read_flash_string(F_(manual));
|
return read_flash_string(F_(manual));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::DAY:
|
case HeatingCircuit::Mode::DAY:
|
||||||
return read_flash_string(F_(day));
|
return read_flash_string(F_(day));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::NIGHT:
|
case HeatingCircuit::Mode::NIGHT:
|
||||||
return read_flash_string(F_(night));
|
return read_flash_string(F_(night));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::ECO:
|
case HeatingCircuit::Mode::ECO:
|
||||||
return read_flash_string(F_(eco));
|
return read_flash_string(F_(eco));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::COMFORT:
|
case HeatingCircuit::Mode::COMFORT:
|
||||||
return read_flash_string(F_(comfort));
|
return read_flash_string(F_(comfort));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::HEAT:
|
case HeatingCircuit::Mode::HEAT:
|
||||||
return read_flash_string(F_(heat));
|
return read_flash_string(F_(heat));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::HOLIDAY:
|
case HeatingCircuit::Mode::HOLIDAY:
|
||||||
return read_flash_string(F_(holiday));
|
return read_flash_string(F_(holiday));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::NOFROST:
|
case HeatingCircuit::Mode::NOFROST:
|
||||||
return read_flash_string(F_(nofrost));
|
return read_flash_string(F_(nofrost));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::AUTO:
|
case HeatingCircuit::Mode::AUTO:
|
||||||
return read_flash_string(F_(auto));
|
return read_flash_string(F_(auto));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::SUMMER:
|
case HeatingCircuit::Mode::SUMMER:
|
||||||
return read_flash_string(F_(summer));
|
return read_flash_string(F_(summer));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::OFFSET:
|
case HeatingCircuit::Mode::OFFSET:
|
||||||
return read_flash_string(F_(offset));
|
return read_flash_string(F_(offset));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::DESIGN:
|
case HeatingCircuit::Mode::DESIGN:
|
||||||
return read_flash_string(F_(design));
|
return read_flash_string(F_(design));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::MINFLOW:
|
case HeatingCircuit::Mode::MINFLOW:
|
||||||
return read_flash_string(F_(minflow));
|
return read_flash_string(F_(minflow));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::MAXFLOW:
|
case HeatingCircuit::Mode::MAXFLOW:
|
||||||
return read_flash_string(F_(maxflow));
|
return read_flash_string(F_(maxflow));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::ROOMINFLUENCE:
|
case HeatingCircuit::Mode::ROOMINFLUENCE:
|
||||||
return read_flash_string(F_(roominfluence[0]));
|
return read_flash_string(F_(roominfluence[0]));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::FLOWOFFSET:
|
case HeatingCircuit::Mode::FLOWOFFSET:
|
||||||
return read_flash_string(F_(flowtempoffset[0]));
|
return read_flash_string(F_(flowtempoffset[0]));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::TEMPAUTO:
|
case HeatingCircuit::Mode::TEMPAUTO:
|
||||||
return read_flash_string(F_(tempauto));
|
return read_flash_string(F_(tempauto));
|
||||||
break;
|
|
||||||
case HeatingCircuit::Mode::NOREDUCE:
|
case HeatingCircuit::Mode::NOREDUCE:
|
||||||
return read_flash_string(F_(noreduce));
|
return read_flash_string(F_(noreduce));
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
case HeatingCircuit::Mode::UNKNOWN:
|
|
||||||
return read_flash_string(F_(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
|
// data: displaycode(2), errornumber(2), year, month, hour, day, minute, duration(2), src-addr
|
||||||
if (telegram->message_data[4] & 0x80) { // valid date
|
if (telegram->message_data[4] & 0x80) { // valid date
|
||||||
char code[sizeof(lastCode_)];
|
char code[sizeof(lastCode_)] = {0};
|
||||||
uint16_t codeNo = EMS_VALUE_USHORT_NOTSET;
|
uint16_t codeNo = EMS_VALUE_USHORT_NOTSET;
|
||||||
code[0] = telegram->message_data[0];
|
code[0] = telegram->message_data[0];
|
||||||
code[1] = telegram->message_data[1];
|
code[1] = telegram->message_data[1];
|
||||||
code[2] = 0;
|
code[2] = 0;
|
||||||
telegram->read_value(codeNo, 2);
|
telegram->read_value(codeNo, 2);
|
||||||
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
|
uint16_t year = (telegram->message_data[4] & 0x7F) + 2000;
|
||||||
uint8_t month = telegram->message_data[5];
|
uint8_t month = telegram->message_data[5];
|
||||||
uint8_t day = telegram->message_data[7];
|
uint8_t day = telegram->message_data[7];
|
||||||
uint8_t hour = telegram->message_data[6];
|
uint8_t hour = telegram->message_data[6];
|
||||||
uint8_t min = telegram->message_data[8];
|
uint8_t min = telegram->message_data[8];
|
||||||
uint16_t duration;
|
uint16_t duration = EMS_VALUE_SHORT_NOTSET;
|
||||||
telegram->read_value(duration, 9);
|
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);
|
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_));
|
has_update(lastCode_, code, sizeof(lastCode_));
|
||||||
@@ -1292,7 +1271,7 @@ bool Thermostat::set_calinttemp(const char * value, const int8_t id) {
|
|||||||
return false;
|
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);
|
LOG_DEBUG(F("Calibrating internal temperature to %d.%d C"), t / 10, t < 0 ? -t % 10 : t % 10);
|
||||||
|
|
||||||
if (model() == EMS_DEVICE_FLAG_RC10) {
|
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) {
|
bool Thermostat::set_holiday(const char * value, const int8_t id, const bool vacation) {
|
||||||
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
uint8_t hc_num = (id == -1) ? AUTO_HEATING_CIRCUIT : id;
|
||||||
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
std::shared_ptr<Thermostat::HeatingCircuit> hc = heating_circuit(hc_num);
|
||||||
if (hc == nullptr) {
|
|
||||||
|
if ((hc == nullptr) || (value == nullptr)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen(value) != 21) {
|
if (strlen(value) != 21) {
|
||||||
return false;
|
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
|
// sets the thermostat working mode, where mode is a string
|
||||||
// converts string mode to HeatingCircuit::Mode
|
// converts string mode to HeatingCircuit::Mode
|
||||||
bool Thermostat::set_mode(const char * value, const int8_t id) {
|
bool Thermostat::set_mode(const char * value, const int8_t id) {
|
||||||
if (strlen(value) >= 20) {
|
if ((value == nullptr) || (strlen(value) >= 20)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1907,9 +1888,7 @@ bool Thermostat::set_mode_n(const uint8_t mode, const uint8_t hc_num) {
|
|||||||
set_mode_value = 1;
|
set_mode_value = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default: // AUTO & ECO
|
||||||
case HeatingCircuit::Mode::AUTO:
|
|
||||||
case HeatingCircuit::Mode::ECO:
|
|
||||||
set_mode_value = 2;
|
set_mode_value = 2;
|
||||||
break;
|
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_mode = doc["mode"];
|
||||||
const char * s_time = doc["time"];
|
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;
|
bool b;
|
||||||
if (Helpers::value2bool(s_mode, b)) {
|
if (Helpers::value2bool(s_mode, b)) {
|
||||||
on = b ? 1 : 0;
|
on = b ? 1 : 0;
|
||||||
@@ -2348,6 +2327,8 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
|||||||
offset = 4;
|
offset = 4;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else if (model == EMS_DEVICE_FLAG_RC20) {
|
} else if (model == EMS_DEVICE_FLAG_RC20) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@@ -2381,6 +2362,8 @@ bool Thermostat::set_temperature(const float temperature, const uint8_t mode, co
|
|||||||
offset = EMS_OFFSET_RC20Set_temp_auto;
|
offset = EMS_OFFSET_RC20Set_temp_auto;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (model == EMS_DEVICE_FLAG_RC30) {
|
} 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;
|
factor = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case HeatingCircuit::Mode::AUTO:
|
// HeatingCircuit::Mode::AUTO:
|
||||||
uint8_t mode_ = hc->get_mode();
|
uint8_t mode_ = hc->get_mode();
|
||||||
if (mode_ == HeatingCircuit::Mode::MANUAL) {
|
if (mode_ == HeatingCircuit::Mode::MANUAL) {
|
||||||
offset = 0x0A; // manual offset
|
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;
|
offset = EMS_OFFSET_RC20_2_Set_temp_day;
|
||||||
break;
|
break;
|
||||||
default:
|
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();
|
uint8_t mode_ = hc->get_mode();
|
||||||
if (mode_ == HeatingCircuit::Mode::NIGHT) {
|
if (mode_ == HeatingCircuit::Mode::NIGHT) {
|
||||||
offset = EMS_OFFSET_RC20_2_Set_temp_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;
|
factor = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
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
|
validate_typeid = monitor_typeids[hc->hc()]; //get setpoint roomtemp back
|
||||||
if (model == EMS_DEVICE_FLAG_RC35) {
|
if (model == EMS_DEVICE_FLAG_RC35) {
|
||||||
uint8_t mode_ = hc->get_mode();
|
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;
|
offset = EMS_OFFSET_JunkersSetMessage_day_temp;
|
||||||
break;
|
break;
|
||||||
default:
|
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();
|
uint8_t modetype = hc->get_mode_type();
|
||||||
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
|
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
|
||||||
offset = EMS_OFFSET_JunkersSetMessage_night_temp;
|
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;
|
offset = EMS_OFFSET_JunkersSetMessage2_heat_temp;
|
||||||
break;
|
break;
|
||||||
default:
|
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();
|
uint8_t modetype = hc->get_mode_type();
|
||||||
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
|
if (modetype == HeatingCircuit::Mode::NIGHT || modetype == HeatingCircuit::Mode::ECO) {
|
||||||
offset = EMS_OFFSET_JunkersSetMessage2_eco_temp;
|
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) {
|
if (offset != -1) {
|
||||||
// add the write command to the Tx queue. value is *2
|
// add the write command to the Tx queue. value is *2
|
||||||
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
// post validate is the corresponding monitor or set type IDs as they can differ per model
|
||||||
write_command(set_typeid, offset, (uint8_t)((float)temperature * (float)factor), validate_typeid);
|
write_command(set_typeid, offset, (uint8_t)(temperature * (float)factor), validate_typeid);
|
||||||
return true;
|
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->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);
|
register_device_value(tag, &hc->remotetemp, DeviceValueType::SHORT, FL_(div10), FL_(remotetemp), DeviceValueUOM::DEGREES);
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class Thermostat : public EMSdevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// determines if the heating circuit is actually present and has data
|
// determines if the heating circuit is actually present and has data
|
||||||
bool is_active() {
|
bool is_active() const {
|
||||||
return Helpers::hasValue(selTemp);
|
return Helpers::hasValue(selTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,7 +292,7 @@ class Thermostat : public EMSdevice {
|
|||||||
|
|
||||||
void register_device_values_hc(std::shared_ptr<Thermostat::HeatingCircuit> hc);
|
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_RCOutdoorTemp(std::shared_ptr<const Telegram> telegram);
|
||||||
void process_IBASettings(std::shared_ptr<const Telegram> telegram);
|
void process_IBASettings(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ uint8_t EMSdevice::count_entities() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// see if there are entities, excluding any commands
|
// see if there are entities, excluding any commands
|
||||||
bool EMSdevice::has_entities() {
|
bool EMSdevice::has_entities() const {
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv.type != DeviceValueType::CMD) {
|
if (dv.type != DeviceValueType::CMD) {
|
||||||
return true;
|
return true;
|
||||||
@@ -43,107 +43,71 @@ bool EMSdevice::has_entities() {
|
|||||||
return false;
|
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]);
|
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]);
|
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)) {
|
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[DeviceValueUOM::FAHRENHEIT]);
|
||||||
}
|
}
|
||||||
return read_flash_string(DeviceValue::DeviceValueUOM_s[uom]);
|
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_) {
|
switch (brand_) {
|
||||||
case EMSdevice::Brand::BOSCH:
|
case EMSdevice::Brand::BOSCH:
|
||||||
return read_flash_string(F("Bosch"));
|
return read_flash_string(F("Bosch"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::JUNKERS:
|
case EMSdevice::Brand::JUNKERS:
|
||||||
return read_flash_string(F("Junkers"));
|
return read_flash_string(F("Junkers"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::BUDERUS:
|
case EMSdevice::Brand::BUDERUS:
|
||||||
return read_flash_string(F("Buderus"));
|
return read_flash_string(F("Buderus"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::NEFIT:
|
case EMSdevice::Brand::NEFIT:
|
||||||
return read_flash_string(F("Nefit"));
|
return read_flash_string(F("Nefit"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::SIEGER:
|
case EMSdevice::Brand::SIEGER:
|
||||||
return read_flash_string(F("Sieger"));
|
return read_flash_string(F("Sieger"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::WORCESTER:
|
case EMSdevice::Brand::WORCESTER:
|
||||||
return read_flash_string(F("Worcester"));
|
return read_flash_string(F("Worcester"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::IVT:
|
case EMSdevice::Brand::IVT:
|
||||||
return read_flash_string(F("IVT"));
|
return read_flash_string(F("IVT"));
|
||||||
break;
|
|
||||||
case EMSdevice::Brand::NO_BRAND:
|
|
||||||
default:
|
default:
|
||||||
return read_flash_string(F(""));
|
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
|
// 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) {
|
switch (device_type) {
|
||||||
case DeviceType::SYSTEM:
|
case DeviceType::SYSTEM:
|
||||||
return read_flash_string(F_(system));
|
return read_flash_string(F_(system));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::BOILER:
|
case DeviceType::BOILER:
|
||||||
return read_flash_string(F_(boiler));
|
return read_flash_string(F_(boiler));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::THERMOSTAT:
|
case DeviceType::THERMOSTAT:
|
||||||
return read_flash_string(F_(thermostat));
|
return read_flash_string(F_(thermostat));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::HEATPUMP:
|
case DeviceType::HEATPUMP:
|
||||||
return read_flash_string(F_(heatpump));
|
return read_flash_string(F_(heatpump));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::SOLAR:
|
case DeviceType::SOLAR:
|
||||||
return read_flash_string(F_(solar));
|
return read_flash_string(F_(solar));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::CONNECT:
|
case DeviceType::CONNECT:
|
||||||
return read_flash_string(F_(connect));
|
return read_flash_string(F_(connect));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::MIXER:
|
case DeviceType::MIXER:
|
||||||
return read_flash_string(F_(mixer));
|
return read_flash_string(F_(mixer));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::DALLASSENSOR:
|
case DeviceType::DALLASSENSOR:
|
||||||
return read_flash_string(F_(dallassensor));
|
return read_flash_string(F_(dallassensor));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::ANALOGSENSOR:
|
case DeviceType::ANALOGSENSOR:
|
||||||
return read_flash_string(F_(analogsensor));
|
return read_flash_string(F_(analogsensor));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::CONTROLLER:
|
case DeviceType::CONTROLLER:
|
||||||
return read_flash_string(F_(controller));
|
return read_flash_string(F_(controller));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::SWITCH:
|
case DeviceType::SWITCH:
|
||||||
return read_flash_string(F_(switch));
|
return read_flash_string(F_(switch));
|
||||||
break;
|
|
||||||
|
|
||||||
case DeviceType::GATEWAY:
|
case DeviceType::GATEWAY:
|
||||||
return read_flash_string(F_(gateway));
|
return read_flash_string(F_(gateway));
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return read_flash_string(F_(unknown));
|
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
|
// 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_);
|
std::string s = device_type_2_device_name(device_type_);
|
||||||
s[0] = toupper(s[0]);
|
s[0] = toupper(s[0]);
|
||||||
return s;
|
return s;
|
||||||
@@ -207,34 +171,25 @@ uint8_t EMSdevice::decode_brand(uint8_t value) {
|
|||||||
switch (value) {
|
switch (value) {
|
||||||
case 1:
|
case 1:
|
||||||
return EMSdevice::Brand::BOSCH;
|
return EMSdevice::Brand::BOSCH;
|
||||||
break;
|
|
||||||
case 2:
|
case 2:
|
||||||
return EMSdevice::Brand::JUNKERS;
|
return EMSdevice::Brand::JUNKERS;
|
||||||
break;
|
|
||||||
case 3:
|
case 3:
|
||||||
return EMSdevice::Brand::BUDERUS;
|
return EMSdevice::Brand::BUDERUS;
|
||||||
break;
|
|
||||||
case 4:
|
case 4:
|
||||||
return EMSdevice::Brand::NEFIT;
|
return EMSdevice::Brand::NEFIT;
|
||||||
break;
|
|
||||||
case 5:
|
case 5:
|
||||||
return EMSdevice::Brand::SIEGER;
|
return EMSdevice::Brand::SIEGER;
|
||||||
break;
|
|
||||||
case 11:
|
case 11:
|
||||||
return EMSdevice::Brand::WORCESTER;
|
return EMSdevice::Brand::WORCESTER;
|
||||||
break;
|
|
||||||
case 13:
|
case 13:
|
||||||
return EMSdevice::Brand::IVT;
|
return EMSdevice::Brand::IVT;
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
default:
|
default:
|
||||||
return EMSdevice::Brand::NO_BRAND;
|
return EMSdevice::Brand::NO_BRAND;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns string of a human friendly description of the EMS device
|
// 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
|
// for devices that haven't been lookup yet, don't show all details
|
||||||
if (product_id_ == 0) {
|
if (product_id_ == 0) {
|
||||||
return name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
|
return name_ + " (DeviceID:" + Helpers::hextoa(device_id_) + ")";
|
||||||
@@ -249,7 +204,7 @@ const std::string EMSdevice::to_string() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns out brand + device name
|
// 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) {
|
if (brand_ == Brand::NO_BRAND) {
|
||||||
return device_type_name() + ": " + name_;
|
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
|
// get status of automatic fetch for a telegramID
|
||||||
bool EMSdevice::is_fetch(uint16_t telegram_id) {
|
bool EMSdevice::is_fetch(uint16_t telegram_id) const {
|
||||||
for (auto & tf : telegram_functions_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if (tf.telegram_type_id_ == telegram_id) {
|
if (tf.telegram_type_id_ == telegram_id) {
|
||||||
return tf.fetch_;
|
return tf.fetch_;
|
||||||
}
|
}
|
||||||
@@ -301,7 +256,7 @@ bool EMSdevice::has_tag(const uint8_t tag) {
|
|||||||
|
|
||||||
// list of registered device entries
|
// list of registered device entries
|
||||||
// called from the command 'entities'
|
// 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_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD && dv.full_name) {
|
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.type != DeviceValueType::CMD && dv.full_name) {
|
||||||
// if we have a tag prefix it
|
// 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
|
// list all the telegram type IDs for this device
|
||||||
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) {
|
void EMSdevice::show_telegram_handlers(uuid::console::Shell & shell) const {
|
||||||
if (telegram_functions_.size() == 0) {
|
if (telegram_functions_.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -393,7 +348,7 @@ char * EMSdevice::show_telegram_handlers(char * result, uint8_t handlers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// list all the mqtt handlers for this device
|
// 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_);
|
Mqtt::show_topic_handlers(shell, device_type_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,7 +381,7 @@ void EMSdevice::register_device_value(uint8_t tag,
|
|||||||
uint16_t max) {
|
uint16_t max) {
|
||||||
// initialize the device value depending on it's type
|
// initialize the device value depending on it's type
|
||||||
if (type == DeviceValueType::STRING) {
|
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) {
|
} else if (type == DeviceValueType::INT) {
|
||||||
*(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET;
|
*(int8_t *)(value_p) = EMS_VALUE_INT_NOTSET;
|
||||||
} else if (type == DeviceValueType::SHORT) {
|
} else if (type == DeviceValueType::SHORT) {
|
||||||
@@ -447,7 +402,7 @@ void EMSdevice::register_device_value(uint8_t tag,
|
|||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
while (options[i++]) {
|
while (options[i++]) {
|
||||||
options_size++;
|
options_size++;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is the unique id set for the device entity. it's a simple sequence number
|
// 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
|
// determine state
|
||||||
uint8_t state = DeviceValueState::DV_VISIBLE; // default to visible
|
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
|
// scan through customizations to see if it's on the exclusion list by matching the productID and deviceID
|
||||||
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
EMSESP::webCustomizationService.read([&](WebCustomization & settings) {
|
||||||
for (EntityCustomization entityCustomization : settings.entityCustomizations) {
|
for (EntityCustomization entityCustomization : settings.entityCustomizations) {
|
||||||
@@ -472,7 +424,6 @@ void EMSdevice::register_device_value(uint8_t tag,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// }
|
|
||||||
|
|
||||||
// add the device
|
// 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);
|
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
|
// 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_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv.value_p == value_p) {
|
if (dv.value_p == value_p) {
|
||||||
return dv.has_state(DeviceValueState::DV_VISIBLE);
|
return dv.has_state(DeviceValueState::DV_VISIBLE);
|
||||||
@@ -546,10 +497,11 @@ bool EMSdevice::is_visible(void * value_p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// publish a single value on change
|
// 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) {
|
if (!Mqtt::publish_single() || value_p == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) {
|
if (dv.value_p == value_p && dv.has_state(DeviceValueState::DV_VISIBLE)) {
|
||||||
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
@@ -593,7 +545,6 @@ void EMSdevice::publish_value(void * value_p) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DeviceValueType::USHORT:
|
case DeviceValueType::USHORT:
|
||||||
Helpers::render_value(payload, *(uint16_t *)(value_p), divider, fahrenheit);
|
Helpers::render_value(payload, *(uint16_t *)(value_p), divider, fahrenheit);
|
||||||
break;
|
break;
|
||||||
@@ -617,11 +568,12 @@ void EMSdevice::publish_value(void * value_p) {
|
|||||||
Helpers::render_value(payload, *(uint32_t *)(value_p), divider);
|
Helpers::render_value(payload, *(uint32_t *)(value_p), divider);
|
||||||
break;
|
break;
|
||||||
case DeviceValueType::STRING:
|
case DeviceValueType::STRING:
|
||||||
default:
|
|
||||||
if (Helpers::hasValue((char *)(value_p))) {
|
if (Helpers::hasValue((char *)(value_p))) {
|
||||||
strlcpy(payload, (char *)(value_p), sizeof(payload));
|
strlcpy(payload, (char *)(value_p), sizeof(payload));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload[0] != '\0') {
|
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
|
// 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
|
// the key may have a TAG string prefixed at the beginning. If so, remove it
|
||||||
char new_key[80];
|
char new_key[80];
|
||||||
strlcpy(new_key, key, sizeof(new_key));
|
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
|
// look up key in our device value list
|
||||||
for (const auto & dv : devicevalues_) {
|
for (const auto & dv : devicevalues_) {
|
||||||
if (dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) {
|
if ((dv.has_state(DeviceValueState::DV_VISIBLE) && dv.full_name) && (read_flash_string(dv.full_name) == key_p)) {
|
||||||
if (read_flash_string(dv.full_name) == key_p) {
|
// ignore TIME since "minutes" is already added to the string value
|
||||||
// ignore TIME since "minutes" is already added to the string value
|
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
|
||||||
if ((dv.uom == DeviceValueUOM::NONE) || (dv.uom == DeviceValueUOM::MINUTES)) {
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
return EMSdevice::uom_to_string(dv.uom);
|
|
||||||
}
|
}
|
||||||
|
return EMSdevice::uom_to_string(dv.uom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,9 +635,9 @@ void EMSdevice::generate_values_web(JsonObject & output) {
|
|||||||
// handle Booleans (true, false)
|
// handle Booleans (true, false)
|
||||||
if (dv.type == DeviceValueType::BOOL) {
|
if (dv.type == DeviceValueType::BOOL) {
|
||||||
bool value_b = *(bool *)(dv.value_p);
|
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";
|
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;
|
obj["v"] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
char s[7];
|
char s[7];
|
||||||
@@ -816,9 +766,9 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
|
|||||||
// handle Booleans (true, false)
|
// handle Booleans (true, false)
|
||||||
if (dv.type == DeviceValueType::BOOL) {
|
if (dv.type == DeviceValueType::BOOL) {
|
||||||
bool value_b = *(bool *)(dv.value_p);
|
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;
|
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;
|
obj["v"] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
char s[7];
|
char s[7];
|
||||||
@@ -844,7 +794,8 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
|
|||||||
uint8_t divider = 0;
|
uint8_t divider = 0;
|
||||||
uint8_t factor = 1;
|
uint8_t factor = 1;
|
||||||
if (dv.options_size == 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] == '*') {
|
if (s[0] == '*') {
|
||||||
factor = Helpers::atoint(&s[1]);
|
factor = Helpers::atoint(&s[1]);
|
||||||
} else {
|
} else {
|
||||||
@@ -853,13 +804,13 @@ void EMSdevice::generate_values_web_all(JsonArray & output) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dv.type == DeviceValueType::INT) {
|
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) {
|
} 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) {
|
} 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) {
|
} 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) {
|
} else if (dv.type == DeviceValueType::ULONG) {
|
||||||
obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor;
|
obj["v"] = divider ? Helpers::round2(*(uint32_t *)(dv.value_p), divider) : *(uint32_t *)(dv.value_p) * factor;
|
||||||
} else if (dv.type == DeviceValueType::TIME) {
|
} 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:
|
case DeviceValueType::BOOL:
|
||||||
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
if (Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
||||||
bool value_b = (bool)(*(uint8_t *)(dv.value_p));
|
auto value_b = (bool)(*(uint8_t *)(dv.value_p));
|
||||||
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
json[value] = value_b;
|
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;
|
json[value] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
char s[7];
|
char s[7];
|
||||||
@@ -1106,10 +1057,10 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
|
|||||||
if (have_tag) {
|
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
|
snprintf(name, 80, "%s %s", tag_to_string(dv.tag).c_str(), read_flash_string(dv.full_name).c_str()); // prefix the tag
|
||||||
} else {
|
} 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 {
|
} 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 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) {
|
if (dv.tag != old_tag) {
|
||||||
@@ -1123,14 +1074,14 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
|
|||||||
// handle Booleans
|
// handle Booleans
|
||||||
if (dv.type == DeviceValueType::BOOL && Helpers::hasValue(*(uint8_t *)(dv.value_p), EMS_VALUE_BOOL)) {
|
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
|
// 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)) {
|
if (Mqtt::ha_enabled() && (output_target == OUTPUT_TARGET::MQTT)) {
|
||||||
char s[7];
|
char s[7];
|
||||||
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
|
json[name] = Helpers::render_boolean(s, value_b); // for HA always render as string
|
||||||
} else {
|
} else {
|
||||||
if ((EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE)) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
json[name] = value_b;
|
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;
|
json[name] = value_b ? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
char s[7];
|
char s[7];
|
||||||
@@ -1147,7 +1098,7 @@ bool EMSdevice::generate_values(JsonObject & output, const uint8_t tag_filter, c
|
|||||||
// handle ENUMs
|
// handle ENUMs
|
||||||
else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) {
|
else if ((dv.type == DeviceValueType::ENUM) && (*(uint8_t *)(dv.value_p) < dv.options_size)) {
|
||||||
// check for numeric enum-format
|
// 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));
|
json[name] = (uint8_t)(*(uint8_t *)(dv.value_p));
|
||||||
} else {
|
} else {
|
||||||
json[name] = dv.options[*(uint8_t *)(dv.value_p)];
|
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 divider = 0;
|
||||||
uint8_t factor = 1;
|
uint8_t factor = 1;
|
||||||
if (dv.options_size == 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] == '*') {
|
if (s[0] == '*') {
|
||||||
factor = Helpers::atoint(&s[1]);
|
factor = Helpers::atoint(&s[1]);
|
||||||
} else {
|
} 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
|
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_) {
|
for (const auto & tf : telegram_functions_) {
|
||||||
if (tf.telegram_type_id_ == id) {
|
if (tf.telegram_type_id_ == id) {
|
||||||
return true;
|
return true;
|
||||||
@@ -1310,7 +1262,7 @@ bool EMSdevice::has_telegram_id(uint16_t id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return the name of the telegram type
|
// 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
|
// see if it's one of the common ones, like Version
|
||||||
if (telegram->type_id == EMS_TYPE_VERSION) {
|
if (telegram->type_id == EMS_TYPE_VERSION) {
|
||||||
return read_flash_string(F("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
|
// 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);
|
EMSESP::send_write_request(type_id, device_id(), offset, message_data, message_length, validate_typeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx write with a single value
|
// send Tx write with a single value
|
||||||
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) {
|
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value, const uint16_t validate_typeid) const {
|
||||||
EMSESP::send_write_request(type_id, device_id(), offset, value, validate_typeid);
|
EMSESP::send_write_request(type_id, device_id(), offset, value, validate_typeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx write with a single value, with no post validation
|
// send Tx write with a single value, with no post validation
|
||||||
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) {
|
void EMSdevice::write_command(const uint16_t type_id, const uint8_t offset, const uint8_t value) const {
|
||||||
EMSESP::send_write_request(type_id, device_id(), offset, value, 0);
|
EMSESP::send_write_request(type_id, device_id(), offset, value, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send Tx read command to the device
|
// send Tx read command to the device
|
||||||
void EMSdevice::read_command(const uint16_t type_id, 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);
|
EMSESP::send_read_request(type_id, device_id(), offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ class EMSdevice {
|
|||||||
strlcpy(version_, version, sizeof(version_));
|
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 std::string device_type_2_device_name(const uint8_t device_type);
|
||||||
static uint8_t device_name_2_device_type(const char * topic);
|
static uint8_t device_name_2_device_type(const char * topic);
|
||||||
static const std::string uom_to_string(uint8_t uom);
|
static std::string uom_to_string(uint8_t uom);
|
||||||
static const std::string tag_to_string(uint8_t tag);
|
static std::string tag_to_string(uint8_t tag);
|
||||||
static const std::string tag_to_mqtt(uint8_t tag);
|
static std::string tag_to_mqtt(uint8_t tag);
|
||||||
|
|
||||||
bool has_tag(const uint8_t tag);
|
bool has_tag(const uint8_t tag);
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ class EMSdevice {
|
|||||||
product_id_ = product_id;
|
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));
|
return ((device_id & 0x7F) == (device_id_ & 0x7F));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ class EMSdevice {
|
|||||||
strlcpy(version_, version, sizeof(version_));
|
strlcpy(version_, version, sizeof(version_));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const char * version() {
|
inline const char * version() const {
|
||||||
return version_;
|
return version_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ class EMSdevice {
|
|||||||
publish_value(value);
|
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) {
|
if (strcmp(value, newvalue) != 0) {
|
||||||
strlcpy(value, newvalue, len);
|
strlcpy(value, newvalue, len);
|
||||||
has_update_ = true;
|
has_update_ = true;
|
||||||
@@ -173,18 +173,18 @@ class EMSdevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string brand_to_string() const;
|
std::string brand_to_string() const;
|
||||||
static uint8_t decode_brand(uint8_t value);
|
static uint8_t decode_brand(uint8_t value);
|
||||||
|
|
||||||
const std::string to_string() const;
|
std::string to_string() const;
|
||||||
const std::string to_string_short() const;
|
std::string to_string_short() const;
|
||||||
|
|
||||||
enum Handlers : uint8_t { ALL, RECEIVED, FETCHED, PENDING };
|
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);
|
char * show_telegram_handlers(char * result, uint8_t handlers);
|
||||||
void show_mqtt_handlers(uuid::console::Shell & shell);
|
void show_mqtt_handlers(uuid::console::Shell & shell) const;
|
||||||
void list_device_entries(JsonObject & output);
|
void list_device_entries(JsonObject & output) const;
|
||||||
void exclude_entity(uint8_t entity_id);
|
void exclude_entity(uint8_t entity_id);
|
||||||
void reset_exclude_entities();
|
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);
|
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);
|
bool handle_telegram(std::shared_ptr<const Telegram> telegram);
|
||||||
|
|
||||||
const std::string get_value_uom(const char * key);
|
std::string get_value_uom(const char * key) const;
|
||||||
bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
|
bool get_value_info(JsonObject & root, const char * cmd, const int8_t id);
|
||||||
void get_dv_info(JsonObject & json);
|
void get_dv_info(JsonObject & json);
|
||||||
|
|
||||||
enum OUTPUT_TARGET : uint8_t { API_VERBOSE, API_SHORTNAMES, MQTT };
|
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);
|
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,
|
const __FlashStringHelper * const * name,
|
||||||
uint8_t uom);
|
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, 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);
|
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);
|
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);
|
bool is_visible(const void * value_p) const;
|
||||||
void publish_value(void * value_p);
|
void publish_value(void * value_p) const;
|
||||||
void publish_all_values();
|
void publish_all_values();
|
||||||
|
|
||||||
void mqtt_ha_entity_config_create();
|
void mqtt_ha_entity_config_create();
|
||||||
void mqtt_ha_entity_config_remove();
|
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 fetch_values();
|
||||||
void toggle_fetch(uint16_t telegram_id, bool toggle);
|
void toggle_fetch(uint16_t telegram_id, bool toggle);
|
||||||
bool is_fetch(uint16_t telegram_id);
|
bool is_fetch(uint16_t telegram_id) const;
|
||||||
bool has_telegram_id(uint16_t id);
|
bool has_telegram_id(uint16_t id) const;
|
||||||
void ha_config_clear();
|
void ha_config_clear();
|
||||||
|
|
||||||
bool ha_config_done() const {
|
bool ha_config_done() const {
|
||||||
@@ -347,7 +347,7 @@ class EMSdevice {
|
|||||||
static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 12; // CRF200 only monitor
|
static constexpr uint8_t EMS_DEVICE_FLAG_CRF = 12; // CRF200 only monitor
|
||||||
|
|
||||||
uint8_t count_entities();
|
uint8_t count_entities();
|
||||||
bool has_entities();
|
bool has_entities() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t unique_id_;
|
uint8_t unique_id_;
|
||||||
|
|||||||
140
src/emsesp.cpp
140
src/emsesp.cpp
@@ -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
|
// 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) {
|
void EMSESP::fetch_device_values(const uint8_t device_id) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if ((device_id == 0) || emsdevice->is_device_id(device_id)) {
|
||||||
if ((device_id == 0) || emsdevice->is_device_id(device_id)) {
|
emsdevice->fetch_values();
|
||||||
emsdevice->fetch_values();
|
if (device_id != 0) {
|
||||||
if (device_id != 0) {
|
return; // quit, we only want to return the selected device
|
||||||
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
|
// see if the deviceID exists
|
||||||
bool EMSESP::valid_device(const uint8_t device_id) {
|
bool EMSESP::valid_device(const uint8_t device_id) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice && emsdevice->is_device_id(device_id)) {
|
||||||
if (emsdevice->is_device_id(device_id)) {
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false; // can't find it
|
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
|
// for a specific EMS device type go and request data values
|
||||||
void EMSESP::fetch_device_values_type(const uint8_t device_type) {
|
void EMSESP::fetch_device_values_type(const uint8_t device_type) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
|
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||||
emsdevice->fetch_values();
|
emsdevice->fetch_values();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,9 +166,9 @@ void EMSESP::watch_id(uint16_t watch_id) {
|
|||||||
// resets all counters and bumps the UART
|
// 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
|
// this is called when the tx_mode is persisted in the FS either via Web UI or the console
|
||||||
void EMSESP::uart_init() {
|
void EMSESP::uart_init() {
|
||||||
uint8_t tx_mode;
|
uint8_t tx_mode = 0;
|
||||||
uint8_t rx_gpio;
|
uint8_t rx_gpio = 0;
|
||||||
uint8_t tx_gpio;
|
uint8_t tx_gpio = 0;
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
tx_mode = settings.tx_mode;
|
tx_mode = settings.tx_mode;
|
||||||
rx_gpio = settings.rx_gpio;
|
rx_gpio = settings.rx_gpio;
|
||||||
@@ -217,10 +213,8 @@ uint8_t EMSESP::bus_status() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tx Failure rate > 10%
|
// Tx Failure rate > 10%
|
||||||
if (total_fail < total_sent) {
|
if ((total_fail < total_sent) && (((total_fail * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT)) {
|
||||||
if (((total_fail * 100) / total_sent) > EMSbus::EMS_TX_ERROR_LIMIT) {
|
return BUS_STATUS_TX_ERRORS;
|
||||||
return BUS_STATUS_TX_ERRORS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return BUS_STATUS_CONNECTED;
|
return BUS_STATUS_CONNECTED;
|
||||||
@@ -236,7 +230,6 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
|
|||||||
case BUS_STATUS_TX_ERRORS:
|
case BUS_STATUS_TX_ERRORS:
|
||||||
shell.printfln(F("EMS Bus is connected, but Tx is not stable."));
|
shell.printfln(F("EMS Bus is connected, but Tx is not stable."));
|
||||||
break;
|
break;
|
||||||
case BUS_STATUS_CONNECTED:
|
|
||||||
default:
|
default:
|
||||||
shell.printfln(F("EMS Bus is connected."));
|
shell.printfln(F("EMS Bus is connected."));
|
||||||
break;
|
break;
|
||||||
@@ -248,7 +241,7 @@ void EMSESP::show_ems(uuid::console::Shell & shell) {
|
|||||||
shell.printfln(F("EMS Bus info:"));
|
shell.printfln(F("EMS Bus info:"));
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) { shell.printfln(F(" Tx mode: %d"), settings.tx_mode); });
|
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(" 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(" #telegrams received: %d"), rxservice_.telegram_count());
|
||||||
shell.printfln(F(" #read requests sent: %d"), txservice_.telegram_read_count());
|
shell.printfln(F(" #read requests sent: %d"), txservice_.telegram_read_count());
|
||||||
shell.printfln(F(" #write requests sent: %d"), txservice_.telegram_write_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
|
// 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 & device_class : EMSFactory::device_handlers()) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
|
||||||
// print header
|
// print header
|
||||||
shell.printfln(F("%s: %s (%d)"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str(), emsdevice->count_entities());
|
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>());
|
shell.print(data.as<int>());
|
||||||
} else if (data.is<float>()) {
|
} else if (data.is<float>()) {
|
||||||
char s[10];
|
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>()) {
|
} else if (data.is<bool>()) {
|
||||||
shell.print(data.as<bool>() ? F_(on) : F_(off));
|
shell.print(data.as<bool>() ? F_(on) : F_(off));
|
||||||
}
|
}
|
||||||
@@ -400,8 +393,8 @@ void EMSESP::show_sensor_values(uuid::console::Shell & shell) {
|
|||||||
sensor.offset());
|
sensor.offset());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case AnalogSensor::AnalogType::DIGITAL_IN:
|
// case AnalogSensor::AnalogType::DIGITAL_IN:
|
||||||
case AnalogSensor::AnalogType::COUNTER:
|
// case AnalogSensor::AnalogType::COUNTER:
|
||||||
shell.printfln(F(" %s: %s%d%s (Type: %s)"),
|
shell.printfln(F(" %s: %s%d%s (Type: %s)"),
|
||||||
sensor.name().c_str(),
|
sensor.name().c_str(),
|
||||||
COLOR_BRIGHT_GREEN,
|
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["dest"] = Helpers::hextoa(buffer, telegram->dest);
|
||||||
doc["type"] = Helpers::hextoa(buffer, telegram->type_id);
|
doc["type"] = Helpers::hextoa(buffer, telegram->type_id);
|
||||||
doc["offset"] = Helpers::hextoa(buffer, telegram->offset);
|
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;
|
doc["data"] = buffer;
|
||||||
|
|
||||||
if (telegram->message_length <= 4) {
|
if (telegram->message_length <= 4) {
|
||||||
@@ -830,31 +823,29 @@ bool EMSESP::process_telegram(std::shared_ptr<const Telegram> telegram) {
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
bool knowndevice = false;
|
bool knowndevice = false;
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
|
||||||
if (emsdevice->is_device_id(telegram->src) || emsdevice->is_device_id(telegram->dest)) {
|
knowndevice = true;
|
||||||
knowndevice = true;
|
found = emsdevice->handle_telegram(telegram);
|
||||||
found = emsdevice->handle_telegram(telegram);
|
if (found && emsdevice->is_device_id(telegram->dest)) {
|
||||||
if (found && emsdevice->is_device_id(telegram->dest)) {
|
LOG_DEBUG(F("Process setting 0x%02X for device 0x%02X"), telegram->type_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 we correctly processed the telegram then follow up with sending it via MQTT (if enabled)
|
if (found && Mqtt::connected()) {
|
||||||
if (found && Mqtt::connected()) {
|
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
|
||||||
if ((mqtt_.get_publish_onchange(emsdevice->device_type()) && emsdevice->has_update())
|
|| (telegram->type_id == publish_id_ && telegram->dest == txservice_.ems_bus_id())) {
|
||||||
|| (telegram->type_id == publish_id_ && telegram->dest == txservice_.ems_bus_id())) {
|
if (telegram->type_id == publish_id_) {
|
||||||
if (telegram->type_id == publish_id_) {
|
publish_id_ = 0;
|
||||||
publish_id_ = 0;
|
}
|
||||||
}
|
emsdevice->has_update(false); // reset flag
|
||||||
emsdevice->has_update(false); // reset flag
|
if (!Mqtt::publish_single()) {
|
||||||
if (!Mqtt::publish_single()) {
|
publish_device_values(emsdevice->device_type()); // publish to MQTT if we explicitly have too
|
||||||
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
|
// return true if we have this device already registered
|
||||||
bool EMSESP::device_exists(const uint8_t device_id) {
|
bool EMSESP::device_exists(const uint8_t device_id) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice && emsdevice->is_device_id(device_id)) {
|
||||||
if (emsdevice->is_device_id(device_id)) {
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -898,7 +887,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
|||||||
// count the number of thermostats
|
// count the number of thermostats
|
||||||
uint8_t num_thermostats = 0;
|
uint8_t num_thermostats = 0;
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == DeviceType::THERMOSTAT)) {
|
if (emsdevice && (emsdevice->device_type() == DeviceType::THERMOSTAT)) {
|
||||||
num_thermostats++;
|
num_thermostats++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -907,7 +896,7 @@ void EMSESP::show_devices(uuid::console::Shell & shell) {
|
|||||||
// so we keep a consistent order
|
// so we keep a consistent order
|
||||||
for (const auto & device_class : EMSFactory::device_handlers()) {
|
for (const auto & device_class : EMSFactory::device_handlers()) {
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_class.first)) {
|
if (emsdevice && (emsdevice->device_type() == device_class.first)) {
|
||||||
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
|
shell.printf(F("%s: %s"), emsdevice->device_type_name().c_str(), emsdevice->to_string().c_str());
|
||||||
shell.println();
|
shell.println();
|
||||||
emsdevice->show_telegram_handlers(shell);
|
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
|
// first check to see if we already have it, if so update the record
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice && emsdevice->is_device_id(device_id)) {
|
||||||
if (emsdevice->is_device_id(device_id)) {
|
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
|
||||||
LOG_DEBUG(F("Updating details for already active deviceID 0x%02X"), device_id);
|
emsdevice->product_id(product_id);
|
||||||
emsdevice->product_id(product_id);
|
emsdevice->version(version);
|
||||||
emsdevice->version(version);
|
// only set brand if it doesn't already exist
|
||||||
// only set brand if it doesn't already exist
|
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
|
||||||
if (emsdevice->brand() == EMSdevice::Brand::NO_BRAND) {
|
emsdevice->brand(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
|
|
||||||
}
|
}
|
||||||
|
// 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;
|
JsonObject node;
|
||||||
|
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if ((emsdevice) && (emsdevice->device_type() == device_type)) {
|
if (emsdevice && (emsdevice->device_type() == device_type)) {
|
||||||
emsdevice->list_device_entries(output);
|
emsdevice->list_device_entries(output);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1213,11 +1200,10 @@ void EMSESP::incoming_telegram(uint8_t * data, const uint8_t length) {
|
|||||||
txservice_.send_poll(); // close the bus
|
txservice_.send_poll(); // close the bus
|
||||||
txservice_.reset_retry_count();
|
txservice_.reset_retry_count();
|
||||||
tx_successful = true;
|
tx_successful = true;
|
||||||
|
|
||||||
// if telegram is longer read next part with offset +25 for ems+ or +27 for ems1.0
|
// if telegram is longer read next part with offset +25 for ems+ or +27 for ems1.0
|
||||||
if (length == 32) {
|
if ((length == 32) && (txservice_.read_next_tx(data[3]) == read_id_)) {
|
||||||
if (txservice_.read_next_tx(data[3]) == read_id_) {
|
read_next_ = true;
|
||||||
read_next_ = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1341,7 +1327,7 @@ void EMSESP::scheduled_fetch_values() {
|
|||||||
if (txservice_.tx_queue_empty()) {
|
if (txservice_.tx_queue_empty()) {
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
for (const auto & emsdevice : emsdevices) {
|
for (const auto & emsdevice : emsdevices) {
|
||||||
if (emsdevice && ++i >= no) {
|
if (++i >= no) {
|
||||||
emsdevice->fetch_values();
|
emsdevice->fetch_values();
|
||||||
no++;
|
no++;
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ std::string Helpers::hextoa(const uint16_t value, bool prefix) {
|
|||||||
#ifdef EMSESP_STANDALONE
|
#ifdef EMSESP_STANDALONE
|
||||||
// special function to work outside of ESP's libraries
|
// special function to work outside of ESP's libraries
|
||||||
char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) {
|
char * Helpers::ultostr(char * ptr, uint32_t value, const uint8_t base) {
|
||||||
if (NULL == ptr) {
|
if (nullptr == ptr) {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long t = 0;
|
unsigned long t = 0;
|
||||||
@@ -191,7 +191,7 @@ char * Helpers::render_boolean(char * result, bool value) {
|
|||||||
|
|
||||||
// render for native char strings
|
// render for native char strings
|
||||||
char * Helpers::render_value(char * result, const char * value, const int8_t format __attribute__((unused))) {
|
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;
|
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};
|
uint32_t p[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
|
||||||
|
|
||||||
char * ret = result;
|
char * ret = result;
|
||||||
int32_t whole = (int32_t)value;
|
auto whole = (int32_t)value;
|
||||||
|
|
||||||
itoa(whole, result, 10);
|
itoa(whole, result, 10);
|
||||||
|
|
||||||
@@ -356,12 +356,11 @@ char * Helpers::render_value(char * result, const uint32_t value, const int8_t f
|
|||||||
} else {
|
} else {
|
||||||
strlcpy(result, ltoa(new_value * format * -1, s, 10), sizeof(s));
|
strlcpy(result, ltoa(new_value * format * -1, s, 10), sizeof(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
if (!format) {
|
if (!format) {
|
||||||
strlcpy(result, ultostr(s, new_value, 10), sizeof(s)); // format is 0
|
strlcpy(result, ultostr(s, new_value, 10), sizeof(s)); // format is 0
|
||||||
} else {
|
} 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));
|
strlcat(result, ".", sizeof(s));
|
||||||
strncat(result, ultostr(s, new_value % format, 10), 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);
|
return (v != EMS_VALUE_INT_NOTSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Helpers::hasValue(char * v) {
|
bool Helpers::hasValue(const char * v) {
|
||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -508,7 +507,8 @@ bool Helpers::value2number(const char * v, int & value, const int min, const int
|
|||||||
value = 0;
|
value = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
value = atoi((char *)v);
|
|
||||||
|
value = atoi(v);
|
||||||
if (value >= min && value <= max) {
|
if (value >= min && value <= max) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -521,12 +521,14 @@ bool Helpers::value2float(const char * v, float & value) {
|
|||||||
if ((v == nullptr) || (strlen(v) == 0)) {
|
if ((v == nullptr) || (strlen(v) == 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v[0] == '-' || v[0] == '.' || (v[0] >= '0' && v[0] <= '9')) {
|
if (v[0] == '-' || v[0] == '.' || (v[0] >= '0' && v[0] <= '9')) {
|
||||||
value = atof((char *)v);
|
value = atof(v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v[0] == '+' && (v[1] == '.' || (v[1] >= '0' && v[1] <= '9'))) {
|
if (v[0] == '+' && (v[1] == '.' || (v[1] >= '0' && v[1] <= '9'))) {
|
||||||
value = atof((char *)(v + 1));
|
value = atof(v + 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -584,12 +586,12 @@ bool Helpers::value2bool(const char * v, bool & value) {
|
|||||||
|
|
||||||
std::string bool_str = toLower(v); // convert to lower case
|
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;
|
value = true;
|
||||||
return true; // is a bool
|
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;
|
value = false;
|
||||||
return true; // is a bool
|
return true; // is a bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Helpers {
|
|||||||
static bool hasValue(const int16_t & v);
|
static bool hasValue(const int16_t & v);
|
||||||
static bool hasValue(const uint16_t & v);
|
static bool hasValue(const uint16_t & v);
|
||||||
static bool hasValue(const uint32_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 value2number(const char * v, int & value, const int min = -2147483648, const int max = 2147483647);
|
||||||
static bool value2float(const char * v, float & value);
|
static bool value2float(const char * v, float & value);
|
||||||
|
|||||||
@@ -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_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_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_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_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"))
|
MAKE_PSTR_LIST(enum_progMode4, F("prog_a"), F("prog_b"), F("prog_c"), F("prog_d"), F("prog_e"), F("prog_f"))
|
||||||
|
|
||||||
|
|||||||
28
src/mqtt.cpp
28
src/mqtt.cpp
@@ -244,14 +244,16 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
|
|||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
// simulate receiving a MQTT message, used only for testing
|
// simulate receiving a MQTT message, used only for testing
|
||||||
void Mqtt::incoming(const char * topic, const char * payload) {
|
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
|
#endif
|
||||||
|
|
||||||
// received an MQTT message that we subscribed too
|
// received an MQTT message that we subscribed too
|
||||||
// topic is the full path
|
// topic is the full path
|
||||||
// payload is json or a single string and converted to a json with key 'value'
|
// 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
|
// sometimes the payload is not terminated correctly, so make a copy
|
||||||
// convert payload to a null-terminated char string
|
// convert payload to a null-terminated char string
|
||||||
char message[len + 2];
|
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
|
// add the base back
|
||||||
char full_topic[MQTT_TOPIC_MAX_SIZE];
|
char full_topic[MQTT_TOPIC_MAX_SIZE];
|
||||||
snprintf(full_topic, sizeof(full_topic), "%s/%s", mqtt_base_.c_str(), mf.topic_.c_str());
|
snprintf(full_topic, sizeof(full_topic), "%s/%s", mqtt_base_.c_str(), mf.topic_.c_str());
|
||||||
if (!strcmp(topic, full_topic)) {
|
if ((!strcmp(topic, full_topic)) && (mf.mqtt_subfunction_)) {
|
||||||
if (mf.mqtt_subfunction_) {
|
if (!(mf.mqtt_subfunction_)(message)) {
|
||||||
if (!(mf.mqtt_subfunction_)(message)) {
|
LOG_ERROR(F("error: invalid payload %s for this topic %s"), message, topic);
|
||||||
LOG_ERROR(F("error: invalid payload %s for this topic %s"), message, topic);
|
if (send_response_) {
|
||||||
if (send_response_) {
|
Mqtt::publish(F_(response), "error: invalid data");
|
||||||
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
|
// 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
|
// 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
|
// 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
|
// find the MQTT message in the queue and remove it
|
||||||
if (mqtt_messages_.empty()) {
|
if (mqtt_messages_.empty()) {
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
@@ -462,7 +462,7 @@ void Mqtt::start() {
|
|||||||
snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "%s/status", mqtt_base_.c_str());
|
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_->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
|
on_message(topic, payload, len); // receiving mqtt
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -804,7 +804,7 @@ void Mqtt::process_queue() {
|
|||||||
char topic[MQTT_TOPIC_MAX_SIZE];
|
char topic[MQTT_TOPIC_MAX_SIZE];
|
||||||
|
|
||||||
if (message->topic.find(discovery_prefix_) == 0) {
|
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 {
|
} else {
|
||||||
snprintf(topic, MQTT_TOPIC_MAX_SIZE, "%s/%s", mqtt_base_.c_str(), message->topic.c_str());
|
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)
|
// based on the device and tag, create the MQTT topic name (without the basename)
|
||||||
// differs based on whether MQTT nested is enabled
|
// differs based on whether MQTT nested is enabled
|
||||||
// tag = EMSdevice::DeviceValueTAG
|
// 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
|
// the system device is treated differently. The topic is 'heartbeat' and doesn't follow the usual convention
|
||||||
if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
if (device_type == EMSdevice::DeviceType::SYSTEM) {
|
||||||
return EMSdevice::tag_to_mqtt(tag);
|
return EMSdevice::tag_to_mqtt(tag);
|
||||||
|
|||||||
18
src/mqtt.h
18
src/mqtt.h
@@ -30,7 +30,7 @@
|
|||||||
using uuid::console::Shell;
|
using uuid::console::Shell;
|
||||||
|
|
||||||
// size of queue
|
// size of queue
|
||||||
#define MAX_MQTT_MESSAGES 300
|
static constexpr uint16_t MAX_MQTT_MESSAGES = 300;
|
||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
@@ -208,11 +208,11 @@ class Mqtt {
|
|||||||
send_response_ = send_response;
|
send_response_ = send_response;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_qos(uint8_t mqtt_qos) {
|
void set_qos(uint8_t mqtt_qos) const {
|
||||||
mqtt_qos_ = mqtt_qos;
|
mqtt_qos_ = mqtt_qos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_retain(bool mqtt_retain) {
|
void set_retain(bool mqtt_retain) const {
|
||||||
mqtt_retain_ = mqtt_retain;
|
mqtt_retain_ = mqtt_retain;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,20 +220,18 @@ class Mqtt {
|
|||||||
return mqtt_messages_.empty();
|
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 {
|
struct QueuedMqttMessage {
|
||||||
const uint32_t id_;
|
const uint32_t id_;
|
||||||
const std::shared_ptr<const MqttMessage> content_;
|
const std::shared_ptr<const MqttMessage> content_;
|
||||||
uint8_t retry_count_;
|
uint8_t retry_count_ = 0;
|
||||||
uint16_t packet_id_;
|
uint16_t packet_id_ = 0;
|
||||||
|
|
||||||
~QueuedMqttMessage() = default;
|
~QueuedMqttMessage() = default;
|
||||||
QueuedMqttMessage(uint32_t id, std::shared_ptr<MqttMessage> && content)
|
QueuedMqttMessage(uint32_t id, std::shared_ptr<MqttMessage> && content)
|
||||||
: id_(id)
|
: id_(id)
|
||||||
, content_(std::move(content)) {
|
, content_(std::move(content)) {
|
||||||
retry_count_ = 0;
|
|
||||||
packet_id_ = 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static std::deque<QueuedMqttMessage> mqtt_messages_;
|
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_subscribe_message(const std::string & topic);
|
||||||
static std::shared_ptr<const MqttMessage> queue_unsubscribe_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_publish(uint16_t packetId) const;
|
||||||
void on_message(const char * topic, const char * payload, size_t len);
|
void on_message(const char * topic, const char * payload, size_t len) const;
|
||||||
void process_queue();
|
void process_queue();
|
||||||
|
|
||||||
// function handlers for MQTT subscriptions
|
// function handlers for MQTT subscriptions
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ void Shower::loop() {
|
|||||||
}
|
}
|
||||||
} else { // hot water is off
|
} else { // hot water is off
|
||||||
// if it just turned off, record the time as it could be a short pause
|
// 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;
|
timer_pause_ = time_now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if shower has been off for longer than the wait time
|
// 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
|
// 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
|
// 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) {
|
if ((timer_pause_ - timer_start_) > SHOWER_OFFSET_TIME) {
|
||||||
@@ -121,7 +121,7 @@ void Shower::shower_alert_start() {
|
|||||||
// Publish to the shower_data topic
|
// Publish to the shower_data topic
|
||||||
// showing whether the shower timer and alert are enabled or disabled
|
// showing whether the shower timer and alert are enabled or disabled
|
||||||
// and the duration of the last shower
|
// and the duration of the last shower
|
||||||
void Shower::publish_shower_data() {
|
void Shower::publish_shower_data() const {
|
||||||
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
|
||||||
|
|
||||||
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
if (EMSESP::system_.bool_format() == BOOL_FORMAT_TRUEFALSE) {
|
||||||
|
|||||||
@@ -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_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
|
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_start();
|
||||||
void shower_alert_stop();
|
void shower_alert_stop();
|
||||||
|
|
||||||
|
|||||||
@@ -484,7 +484,7 @@ bool System::upload_status() {
|
|||||||
|
|
||||||
void System::upload_status(bool in_progress) {
|
void System::upload_status(bool in_progress) {
|
||||||
// if we've just started an upload
|
// if we've just started an upload
|
||||||
if ((!upload_status_) && (in_progress)) {
|
if (!upload_status_ && in_progress) {
|
||||||
EMSuart::stop();
|
EMSuart::stop();
|
||||||
}
|
}
|
||||||
upload_status_ = in_progress;
|
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_GPIO0_OUT = 1 RMII clock output from GPIO0
|
||||||
// ETH_CLOCK_GPIO16_OUT = 2 RMII clock output from GPIO16
|
// 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_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);
|
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"));
|
node["bus status"] = (F("connected, tx issues - try a different tx-mode"));
|
||||||
break;
|
break;
|
||||||
case EMSESP::BUS_STATUS_CONNECTED:
|
case EMSESP::BUS_STATUS_CONNECTED:
|
||||||
default:
|
|
||||||
node["bus status"] = (F("connected"));
|
node["bus status"] = (F("connected"));
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
node["bus status"] = (F("unknown"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMSESP::bus_status() != EMSESP::BUS_STATUS_OFFLINE) {
|
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");
|
JsonArray devices = output.createNestedArray("Devices");
|
||||||
for (const auto & device_class : EMSFactory::device_handlers()) {
|
for (const auto & device_class : EMSFactory::device_handlers()) {
|
||||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
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();
|
JsonObject obj = devices.createNestedObject();
|
||||||
obj["type"] = emsdevice->device_type_name();
|
obj["type"] = emsdevice->device_type_name();
|
||||||
// obj["name"] = emsdevice->to_string();
|
// obj["name"] = emsdevice->to_string();
|
||||||
@@ -1278,7 +1280,7 @@ bool System::command_restart(const char * value, const int8_t id) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string System::reset_reason(uint8_t cpu) {
|
std::string System::reset_reason(uint8_t cpu) const {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
switch (rtc_get_reset_reason(cpu)) {
|
switch (rtc_get_reset_reason(cpu)) {
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ class System {
|
|||||||
static bool command_customizations(const char * value, const int8_t id, JsonObject & output);
|
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);
|
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 system_restart();
|
||||||
void format(uuid::console::Shell & shell);
|
void format(uuid::console::Shell & shell);
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ void TxService::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sends a 1 byte poll which is our own deviceID
|
// 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());
|
//LOG_DEBUG(F("Ack %02X"),ems_bus_id() ^ ems_mask());
|
||||||
if (tx_mode()) {
|
if (tx_mode()) {
|
||||||
EMSuart::send_poll(ems_bus_id() ^ ems_mask());
|
EMSuart::send_poll(ems_bus_id() ^ ems_mask());
|
||||||
@@ -568,7 +568,7 @@ void TxService::send_raw(const char * telegram_data) {
|
|||||||
while (p != 0) {
|
while (p != 0) {
|
||||||
if ((p = strtok(nullptr, " ,"))) {
|
if ((p = strtok(nullptr, " ,"))) {
|
||||||
strlcpy(value, p, sizeof(value));
|
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;
|
data[++count] = val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,11 +87,12 @@ class Telegram {
|
|||||||
// reads a bit value from a given telegram position
|
// reads a bit value from a given telegram position
|
||||||
bool read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
bool read_bitvalue(uint8_t & value, const uint8_t index, const uint8_t bit) const {
|
||||||
uint8_t abs_index = (index - this->offset);
|
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
|
return false; // out of bounds
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t val = value;
|
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);
|
return (val != value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,14 +106,17 @@ class Telegram {
|
|||||||
bool read_value(Value & value, const uint8_t index, uint8_t s = 0) const {
|
bool read_value(Value & value, const uint8_t index, uint8_t s = 0) const {
|
||||||
uint8_t num_bytes = (!s) ? sizeof(Value) : s;
|
uint8_t num_bytes = (!s) ? sizeof(Value) : s;
|
||||||
// check for out of bounds, if so don't modify the value
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
auto val = value;
|
|
||||||
value = 0;
|
Value val = value;
|
||||||
|
value = 0;
|
||||||
for (uint8_t i = 0; i < num_bytes; i++) {
|
for (uint8_t i = 0; i < num_bytes; i++) {
|
||||||
value = (value << 8) + this->message_data[index - this->offset + i]; // shift by byte
|
value = (value << 8) + this->message_data[index - this->offset + i]; // shift by byte
|
||||||
}
|
}
|
||||||
|
|
||||||
return (val != value);
|
return (val != value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +124,7 @@ class Telegram {
|
|||||||
if ((index < this->offset) || ((index - this->offset) >= this->message_length)) {
|
if ((index < this->offset) || ((index - this->offset) >= this->message_length)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t val = value;
|
uint8_t val = value;
|
||||||
value = this->message_data[index - this->offset] - start;
|
value = this->message_data[index - this->offset] - start;
|
||||||
return (val != value);
|
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_;
|
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 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 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_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);
|
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;
|
bool is_last_tx(const uint8_t src, const uint8_t dest) const;
|
||||||
uint16_t post_send_query();
|
uint16_t post_send_query();
|
||||||
@@ -318,7 +323,7 @@ class TxService : public EMSbus {
|
|||||||
telegram_last_post_send_query_ = type_id;
|
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_;
|
return telegram_last_post_send_query_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,14 +367,14 @@ class TxService : public EMSbus {
|
|||||||
if (telegram_read_fail_count_ == 0) {
|
if (telegram_read_fail_count_ == 0) {
|
||||||
return 100; // all good, 100%
|
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 {
|
uint8_t write_quality() const {
|
||||||
if (telegram_write_fail_count_ == 0) {
|
if (telegram_write_fail_count_ == 0) {
|
||||||
return 100; // all good, 100%
|
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() {
|
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_;
|
return tx_telegrams_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tx_queue_empty() {
|
bool tx_queue_empty() const {
|
||||||
return tx_telegrams_.size() == 0;
|
return tx_telegrams_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(EMSESP_DEBUG)
|
#if defined(EMSESP_DEBUG)
|
||||||
|
|||||||
@@ -804,28 +804,28 @@ void Test::run_test(uuid::console::Shell & shell, const std::string & cmd, const
|
|||||||
|
|
||||||
// test command parse
|
// test command parse
|
||||||
int8_t id_n;
|
int8_t id_n;
|
||||||
const char * cmd;
|
const char * ncmd;
|
||||||
char command_s[100];
|
char command_s[100];
|
||||||
id_n = -1;
|
id_n = -1;
|
||||||
strcpy(command_s, "hc2/seltemp");
|
strlcpy(command_s, "hc2/seltemp", sizeof(command_s));
|
||||||
cmd = Command::parse_command_string(command_s, id_n);
|
ncmd = Command::parse_command_string(command_s, id_n);
|
||||||
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
|
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
|
||||||
id_n = -1;
|
id_n = -1;
|
||||||
strcpy(command_s, "seltemp");
|
strlcpy(command_s, "seltemp", sizeof(command_s));
|
||||||
cmd = Command::parse_command_string(command_s, id_n);
|
ncmd = Command::parse_command_string(command_s, id_n);
|
||||||
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
|
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
|
||||||
id_n = -1;
|
id_n = -1;
|
||||||
strcpy(command_s, "xyz/seltemp");
|
strlcpy(command_s, "xyz/seltemp", sizeof(command_s));
|
||||||
cmd = Command::parse_command_string(command_s, id_n);
|
ncmd = Command::parse_command_string(command_s, id_n);
|
||||||
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
|
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
|
||||||
id_n = -1;
|
id_n = -1;
|
||||||
strcpy(command_s, "wwc4/seltemp");
|
strlcpy(command_s, "wwc4/seltemp", sizeof(command_s));
|
||||||
cmd = Command::parse_command_string(command_s, id_n);
|
ncmd = Command::parse_command_string(command_s, id_n);
|
||||||
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
|
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
|
||||||
id_n = -1;
|
id_n = -1;
|
||||||
strcpy(command_s, "hc3_seltemp");
|
strlcpy(command_s, "hc3_seltemp", sizeof(command_s));
|
||||||
cmd = Command::parse_command_string(command_s, id_n);
|
ncmd = Command::parse_command_string(command_s, id_n);
|
||||||
shell.printfln("test cmd parse cmd=%s id=%d", cmd, id_n);
|
shell.printfln("test cmd parse cmd=%s id=%d", ncmd, id_n);
|
||||||
|
|
||||||
#endif
|
#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];
|
char system_topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
|
||||||
Mqtt::show_mqtt(shell); // show queue
|
Mqtt::show_mqtt(shell); // show queue
|
||||||
|
|
||||||
strcpy(boiler_topic, "ems-esp/boiler");
|
strlcpy(boiler_topic, "ems-esp/boiler", sizeof(boiler_topic));
|
||||||
strcpy(thermostat_topic, "ems-esp/thermostat");
|
strlcpy(thermostat_topic, "ems-esp/thermostat", sizeof(thermostat_topic));
|
||||||
strcpy(system_topic, "ems-esp/system");
|
strlcpy(system_topic, "ems-esp/system", sizeof(system_topic));
|
||||||
|
|
||||||
// test publishing
|
// test publishing
|
||||||
EMSESP::EMSESP::mqtt_.publish(boiler_topic, "test me");
|
EMSESP::mqtt_.publish(boiler_topic, "test me");
|
||||||
|
|
||||||
// test receiving
|
// test receiving
|
||||||
EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads, should return values
|
EMSESP::mqtt_.incoming(boiler_topic, ""); // test if ignore empty payloads, should return values
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ void WebAPIService::webAPIService_get(AsyncWebServerRequest * request) {
|
|||||||
// POST /{device}[/{hc|id}][/{name}]
|
// POST /{device}[/{hc|id}][/{name}]
|
||||||
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
// if no body then treat it as a secure GET
|
// if no body then treat it as a secure GET
|
||||||
if (not json.is<JsonObject>()) {
|
if (!json.is<JsonObject>()) {
|
||||||
webAPIService_get(request);
|
webAPIService_get(request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -63,10 +63,10 @@ void WebAPIService::webAPIService_post(AsyncWebServerRequest * request, JsonVari
|
|||||||
// reporting back any errors
|
// reporting back any errors
|
||||||
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
||||||
// check if the user has admin privileges (token is included and authorized)
|
// check if the user has admin privileges (token is included and authorized)
|
||||||
bool is_admin;
|
bool is_admin = false;
|
||||||
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
EMSESP::webSettingsService.read([&](WebSettings & settings) {
|
||||||
Authentication authentication = _securityManager->authenticateRequest(request);
|
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
|
// check for query parameters first, the old style from v2
|
||||||
@@ -97,8 +97,8 @@ void WebAPIService::parse(AsyncWebServerRequest * request, JsonObject & input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// output json buffer
|
// output json buffer
|
||||||
PrettyAsyncJsonResponse * response = new PrettyAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
|
auto * response = new PrettyAsyncJsonResponse(false, EMSESP_JSON_SIZE_XXLARGE_DYN);
|
||||||
JsonObject output = response->getRoot();
|
JsonObject output = response->getRoot();
|
||||||
|
|
||||||
// call command
|
// call command
|
||||||
uint8_t return_code = Command::process(request->url().c_str(), is_admin, input, output);
|
uint8_t return_code = Command::process(request->url().c_str(), is_admin, input, output);
|
||||||
|
|||||||
@@ -99,10 +99,10 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
if (root["sensors"].is<JsonArray>()) {
|
if (root["sensors"].is<JsonArray>()) {
|
||||||
for (const JsonObject sensorJson : root["sensors"].as<JsonArray>()) {
|
for (const JsonObject sensorJson : root["sensors"].as<JsonArray>()) {
|
||||||
// create each of the sensor, overwritting any previous settings
|
// create each of the sensor, overwritting any previous settings
|
||||||
SensorCustomization sensor = SensorCustomization();
|
auto sensor = SensorCustomization();
|
||||||
sensor.id_str = sensorJson["id_str"].as<std::string>();
|
sensor.id_str = sensorJson["id_str"].as<std::string>();
|
||||||
sensor.name = sensorJson["name"].as<std::string>();
|
sensor.name = sensorJson["name"].as<std::string>();
|
||||||
sensor.offset = sensorJson["offset"];
|
sensor.offset = sensorJson["offset"];
|
||||||
settings.sensorCustomizations.push_back(sensor); // add to list
|
settings.sensorCustomizations.push_back(sensor); // add to list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,13 +112,13 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
if (root["analogs"].is<JsonArray>()) {
|
if (root["analogs"].is<JsonArray>()) {
|
||||||
for (const JsonObject analogJson : root["analogs"].as<JsonArray>()) {
|
for (const JsonObject analogJson : root["analogs"].as<JsonArray>()) {
|
||||||
// create each of the sensor, overwritting any previous settings
|
// create each of the sensor, overwritting any previous settings
|
||||||
AnalogCustomization sensor = AnalogCustomization();
|
auto sensor = AnalogCustomization();
|
||||||
sensor.id = analogJson["id"];
|
sensor.id = analogJson["id"];
|
||||||
sensor.name = analogJson["name"].as<std::string>();
|
sensor.name = analogJson["name"].as<std::string>();
|
||||||
sensor.offset = analogJson["offset"];
|
sensor.offset = analogJson["offset"];
|
||||||
sensor.factor = analogJson["factor"];
|
sensor.factor = analogJson["factor"];
|
||||||
sensor.uom = analogJson["uom"];
|
sensor.uom = analogJson["uom"];
|
||||||
sensor.type = analogJson["type"];
|
sensor.type = analogJson["type"];
|
||||||
settings.analogCustomizations.push_back(sensor); // add to list
|
settings.analogCustomizations.push_back(sensor); // add to list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,9 +127,9 @@ StateUpdateResult WebCustomization::update(JsonObject & root, WebCustomization &
|
|||||||
settings.entityCustomizations.clear();
|
settings.entityCustomizations.clear();
|
||||||
if (root["exclude_entities"].is<JsonArray>()) {
|
if (root["exclude_entities"].is<JsonArray>()) {
|
||||||
for (const JsonObject exclude_entities : root["exclude_entities"].as<JsonArray>()) {
|
for (const JsonObject exclude_entities : root["exclude_entities"].as<JsonArray>()) {
|
||||||
EntityCustomization new_entry = EntityCustomization();
|
auto new_entry = EntityCustomization();
|
||||||
new_entry.product_id = exclude_entities["product_id"];
|
new_entry.product_id = exclude_entities["product_id"];
|
||||||
new_entry.device_id = exclude_entities["device_id"];
|
new_entry.device_id = exclude_entities["device_id"];
|
||||||
|
|
||||||
for (const JsonVariant exclude_entity_id : exclude_entities["entity_ids"].as<JsonArray>()) {
|
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
|
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
|
// send back a short list devices used in the customization page
|
||||||
void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
JsonArray devices = root.createNestedArray("devices");
|
JsonArray devices = root.createNestedArray("devices");
|
||||||
for (auto & emsdevice : EMSESP::emsdevices) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice->has_entities()) {
|
if (emsdevice->has_entities()) {
|
||||||
JsonObject obj = devices.createNestedObject();
|
JsonObject obj = devices.createNestedObject();
|
||||||
obj["i"] = emsdevice->unique_id(); // a unique id
|
obj["i"] = emsdevice->unique_id(); // a unique id
|
||||||
@@ -185,18 +185,16 @@ void WebCustomizationService::devices(AsyncWebServerRequest * request) {
|
|||||||
// send back list device entities
|
// send back list device entities
|
||||||
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebCustomizationService::device_entities(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
if (json.is<JsonObject>()) {
|
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) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice->unique_id() == json["id"]) {
|
||||||
if (emsdevice->unique_id() == json["id"]) {
|
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
JsonArray output = response->getRoot();
|
JsonArray output = response->getRoot();
|
||||||
emsdevice->generate_values_web_all(output);
|
emsdevice->generate_values_web_all(output);
|
||||||
#endif
|
#endif
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,13 +70,13 @@ void WebDataService::scan_devices(AsyncWebServerRequest * request) {
|
|||||||
// this is used in the dashboard and contains all ems device information
|
// this is used in the dashboard and contains all ems device information
|
||||||
// /coreData endpoint
|
// /coreData endpoint
|
||||||
void WebDataService::core_data(AsyncWebServerRequest * request) {
|
void WebDataService::core_data(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
// list is already sorted by device type
|
// list is already sorted by device type
|
||||||
// Ignore Contoller
|
// Ignore Contoller
|
||||||
JsonArray devices = root.createNestedArray("devices");
|
JsonArray devices = root.createNestedArray("devices");
|
||||||
for (auto & emsdevice : EMSESP::emsdevices) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice && emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER) {
|
if (emsdevice && emsdevice->device_type() != EMSdevice::DeviceType::CONTROLLER) {
|
||||||
JsonObject obj = devices.createNestedObject();
|
JsonObject obj = devices.createNestedObject();
|
||||||
obj["i"] = emsdevice->unique_id(); // a unique id
|
obj["i"] = emsdevice->unique_id(); // a unique id
|
||||||
@@ -102,8 +102,8 @@ void WebDataService::core_data(AsyncWebServerRequest * request) {
|
|||||||
// /sensorData endpoint
|
// /sensorData endpoint
|
||||||
// the "sensors" and "analogs" are arrays and must exist
|
// the "sensors" and "analogs" are arrays and must exist
|
||||||
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
void WebDataService::sensor_data(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_XLARGE_DYN);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
// dallas sensors
|
// dallas sensors
|
||||||
JsonArray sensors = root.createNestedArray("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
|
// Compresses the JSON using MsgPack https://msgpack.org/index.html
|
||||||
void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebDataService::device_data(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
if (json.is<JsonObject>()) {
|
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) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice->unique_id() == json["id"]) {
|
||||||
if (emsdevice->unique_id() == json["id"]) {
|
// wait max 2.5 sec for updated data (post_send_delay is 2 sec)
|
||||||
// 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++) {
|
||||||
for (uint16_t i = 0; i < (emsesp::TxService::POST_SEND_DELAY + 500) && EMSESP::wait_validate(); i++) {
|
delay(1);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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
|
// using the unique ID from the web find the real device type
|
||||||
// id is the selected device
|
// id is the selected device
|
||||||
for (const auto & emsdevice : EMSESP::emsdevices) {
|
for (const auto & emsdevice : EMSESP::emsdevices) {
|
||||||
if (emsdevice) {
|
if (emsdevice->unique_id() == unique_id) {
|
||||||
if (emsdevice->unique_id() == unique_id) {
|
// parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp
|
||||||
// parse the command as it could have a hc or wwc prefixed, e.g. hc2/seltemp
|
const char * cmd = dv["c"]; // the command
|
||||||
const char * cmd = dv["c"]; // the command
|
int8_t id = -1; // default
|
||||||
int8_t id = -1; // default
|
cmd = Command::parse_command_string(cmd, id); // extract hc or wwc
|
||||||
cmd = Command::parse_command_string(cmd, id); // extract hc or wwc
|
|
||||||
|
|
||||||
// create JSON for output
|
// create JSON for output
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
||||||
JsonObject output = response->getRoot();
|
JsonObject output = response->getRoot();
|
||||||
|
|
||||||
// the data could be in any format, but we need string
|
// the data could be in any format, but we need string
|
||||||
// authenticated is always true
|
// authenticated is always true
|
||||||
JsonVariant data = dv["v"]; // the value in any format
|
JsonVariant data = dv["v"]; // the value in any format
|
||||||
uint8_t return_code = CommandRet::OK;
|
uint8_t return_code = CommandRet::OK;
|
||||||
uint8_t device_type = emsdevice->device_type();
|
uint8_t device_type = emsdevice->device_type();
|
||||||
if (data.is<const char *>()) {
|
if (data.is<const char *>()) {
|
||||||
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
|
return_code = Command::call(device_type, cmd, data.as<const char *>(), true, id, output);
|
||||||
} else if (data.is<int>()) {
|
} else if (data.is<int>()) {
|
||||||
char s[10];
|
char s[10];
|
||||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int16_t>(), 0), true, id, output);
|
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<int16_t>(), 0), true, id, output);
|
||||||
} else if (data.is<float>()) {
|
} else if (data.is<float>()) {
|
||||||
char s[10];
|
char s[10];
|
||||||
return_code = Command::call(device_type, cmd, Helpers::render_value(s, (float)data.as<float>(), 1), true, id, output);
|
return_code = Command::call(device_type, cmd, Helpers::render_value(s, data.as<float>(), 1), true, id, output);
|
||||||
} else if (data.is<bool>()) {
|
} else if (data.is<bool>()) {
|
||||||
return_code = Command::call(device_type, cmd, data.as<bool>() ? "true" : "false", true, id, output);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void WebLogService::maximum_log_messages(size_t count) {
|
|||||||
"local");
|
"local");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WebLogService::compact() {
|
bool WebLogService::compact() const {
|
||||||
return compact_;
|
return compact_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,24 +156,24 @@ void WebLogService::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert time to real offset
|
// 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_) {
|
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 {
|
} else {
|
||||||
time_t t1 = time_offset_ + t / 1000ULL;
|
time_t t1 = time_offset_ + t / 1000ULL;
|
||||||
strftime(out, 25, "%F %T", localtime(&t1));
|
strftime(out, bufsize, "%F %T", localtime(&t1));
|
||||||
snprintf(out, 25, "%s.%03d", out, (uint16_t)(t % 1000));
|
snprintf(out, bufsize, "%s.%03d", out, (uint16_t)(t % 1000));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send to web eventsource
|
// send to web eventsource
|
||||||
void WebLogService::transmit(const QueuedLogMessage & message) {
|
void WebLogService::transmit(const QueuedLogMessage & message) {
|
||||||
DynamicJsonDocument jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
|
auto jsonDocument = DynamicJsonDocument(EMSESP_JSON_SIZE_MEDIUM);
|
||||||
JsonObject logEvent = jsonDocument.to<JsonObject>();
|
JsonObject logEvent = jsonDocument.to<JsonObject>();
|
||||||
char time_string[25];
|
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["l"] = message.content_->level;
|
||||||
logEvent["i"] = message.id_;
|
logEvent["i"] = message.id_;
|
||||||
logEvent["n"] = message.content_->name;
|
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
|
// send the complete log buffer to the API, not filtering on log level
|
||||||
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
||||||
MsgpackAsyncJsonResponse * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
|
auto * response = new MsgpackAsyncJsonResponse(false, EMSESP_JSON_SIZE_LARGE_DYN + 192 * log_messages_.size());
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
JsonArray log = root.createNestedArray("events");
|
JsonArray log = root.createNestedArray("events");
|
||||||
|
|
||||||
log_message_id_tail_ = log_messages_.back().id_;
|
log_message_id_tail_ = log_messages_.back().id_;
|
||||||
last_transmit_ = uuid::get_uptime_ms();
|
last_transmit_ = uuid::get_uptime_ms();
|
||||||
@@ -200,7 +200,7 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
|||||||
JsonObject logEvent = log.createNestedObject();
|
JsonObject logEvent = log.createNestedObject();
|
||||||
char time_string[25];
|
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["l"] = message.content_->level;
|
||||||
logEvent["i"] = message.id_;
|
logEvent["i"] = message.id_;
|
||||||
logEvent["n"] = message.content_->name;
|
logEvent["n"] = message.content_->name;
|
||||||
@@ -213,7 +213,7 @@ void WebLogService::fetchLog(AsyncWebServerRequest * request) {
|
|||||||
|
|
||||||
// sets the values like level after a POST
|
// sets the values like level after a POST
|
||||||
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
if (not json.is<JsonObject>()) {
|
if (!json.is<JsonObject>()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,11 +233,11 @@ void WebLogService::setValues(AsyncWebServerRequest * request, JsonVariant & jso
|
|||||||
|
|
||||||
// return the current value settings after a GET
|
// return the current value settings after a GET
|
||||||
void WebLogService::getValues(AsyncWebServerRequest * request) {
|
void WebLogService::getValues(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_SMALL);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
root["level"] = log_level();
|
root["level"] = log_level();
|
||||||
root["max_messages"] = maximum_log_messages();
|
root["max_messages"] = maximum_log_messages();
|
||||||
root["compact"] = compact();
|
root["compact"] = compact();
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class WebLogService : public uuid::log::Handler {
|
|||||||
void log_level(uuid::log::Level level);
|
void log_level(uuid::log::Level level);
|
||||||
size_t maximum_log_messages() const;
|
size_t maximum_log_messages() const;
|
||||||
void maximum_log_messages(size_t count);
|
void maximum_log_messages(size_t count);
|
||||||
bool compact();
|
bool compact() const;
|
||||||
void compact(bool compact);
|
void compact(bool compact);
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
@@ -62,9 +62,10 @@ class WebLogService : public uuid::log::Handler {
|
|||||||
void fetchLog(AsyncWebServerRequest * request);
|
void fetchLog(AsyncWebServerRequest * request);
|
||||||
void getValues(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
|
AsyncCallbackJsonWebHandler setValues_; // for POSTs
|
||||||
|
|
||||||
uint64_t last_transmit_ = 0; // Last transmit time
|
uint64_t last_transmit_ = 0; // Last transmit time
|
||||||
|
|||||||
@@ -271,8 +271,8 @@ void WebSettingsService::save() {
|
|||||||
// build the json profile to send back
|
// build the json profile to send back
|
||||||
void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVariant & json) {
|
void WebSettingsService::board_profile(AsyncWebServerRequest * request, JsonVariant & json) {
|
||||||
if (json.is<JsonObject>()) {
|
if (json.is<JsonObject>()) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
if (json.containsKey("board_profile")) {
|
if (json.containsKey("board_profile")) {
|
||||||
String board_profile = json["board_profile"];
|
String board_profile = json["board_profile"];
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
|
||||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM_DYN);
|
auto * response = new AsyncJsonResponse(false, EMSESP_JSON_SIZE_MEDIUM_DYN);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
|
|
||||||
root["status"] = EMSESP::bus_status(); // 0, 1 or 2
|
root["status"] = EMSESP::bus_status(); // 0, 1 or 2
|
||||||
root["num_devices"] = EMSESP::count_devices(); // excluding Controller
|
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
|
// start the multicast UDP service so EMS-ESP is discoverable via .local
|
||||||
void WebStatusService::mDNS_start() {
|
void WebStatusService::mDNS_start() const {
|
||||||
#ifndef EMSESP_STANDALONE
|
#ifndef EMSESP_STANDALONE
|
||||||
MDNS.end();
|
MDNS.end();
|
||||||
if (!MDNS.begin(EMSESP::system_.hostname().c_str())) {
|
if (!MDNS.begin(EMSESP::system_.hostname().c_str())) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ class WebStatusService {
|
|||||||
private:
|
private:
|
||||||
void webStatusService(AsyncWebServerRequest * request);
|
void webStatusService(AsyncWebServerRequest * request);
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
void mDNS_start();
|
void mDNS_start() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emsesp
|
} // namespace emsesp
|
||||||
|
|||||||
Reference in New Issue
Block a user