This commit is contained in:
MichaelDvP
2024-02-15 09:08:01 +01:00
110 changed files with 1942 additions and 1923 deletions

View File

@@ -324,37 +324,35 @@ void AnalogSensor::loop() {
bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset, double factor, uint8_t uom, int8_t type, bool deleted) {
// first see if we can find the sensor in our customization list
bool found_sensor = false;
EMSESP::webCustomizationService.update(
[&](WebCustomization & settings) {
for (auto & AnalogCustomization : settings.analogCustomizations) {
if (AnalogCustomization.type == AnalogType::COUNTER || AnalogCustomization.type >= AnalogType::DIGITAL_OUT) {
Command::erase_command(EMSdevice::DeviceType::ANALOGSENSOR, AnalogCustomization.name.c_str());
}
if (AnalogCustomization.gpio == gpio) {
found_sensor = true; // found the record
// see if it's marked for deletion
if (deleted) {
EMSESP::nvs_.remove(AnalogCustomization.name.c_str());
LOG_DEBUG("Removing analog sensor GPIO %02d", gpio);
settings.analogCustomizations.remove(AnalogCustomization);
} else {
// update existing record
if (name != AnalogCustomization.name) {
EMSESP::nvs_.remove(AnalogCustomization.name.c_str());
}
AnalogCustomization.name = name;
AnalogCustomization.offset = offset;
AnalogCustomization.factor = factor;
AnalogCustomization.uom = uom;
AnalogCustomization.type = type;
LOG_DEBUG("Customizing existing analog GPIO %02d", gpio);
}
return StateUpdateResult::CHANGED; // persist the change
}
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
for (auto & AnalogCustomization : settings.analogCustomizations) {
if (AnalogCustomization.type == AnalogType::COUNTER || AnalogCustomization.type >= AnalogType::DIGITAL_OUT) {
Command::erase_command(EMSdevice::DeviceType::ANALOGSENSOR, AnalogCustomization.name.c_str());
}
return StateUpdateResult::UNCHANGED;
},
"local");
if (AnalogCustomization.gpio == gpio) {
found_sensor = true; // found the record
// see if it's marked for deletion
if (deleted) {
EMSESP::nvs_.remove(AnalogCustomization.name.c_str());
LOG_DEBUG("Removing analog sensor GPIO %02d", gpio);
settings.analogCustomizations.remove(AnalogCustomization);
} else {
// update existing record
if (name != AnalogCustomization.name) {
EMSESP::nvs_.remove(AnalogCustomization.name.c_str());
}
AnalogCustomization.name = name;
AnalogCustomization.offset = offset;
AnalogCustomization.factor = factor;
AnalogCustomization.uom = uom;
AnalogCustomization.type = type;
LOG_DEBUG("Customizing existing analog GPIO %02d", gpio);
}
return StateUpdateResult::CHANGED; // persist the change
}
}
return StateUpdateResult::UNCHANGED;
});
// if the sensor exists and we're using HA, delete the old HA record
if (found_sensor && Mqtt::ha_enabled()) {
@@ -363,20 +361,18 @@ bool AnalogSensor::update(uint8_t gpio, const std::string & name, double offset,
// we didn't find it, it's new, so create and store it in the customization list
if (!found_sensor) {
EMSESP::webCustomizationService.update(
[&](WebCustomization & settings) {
auto newSensor = AnalogCustomization();
newSensor.gpio = gpio;
newSensor.name = name;
newSensor.offset = offset;
newSensor.factor = factor;
newSensor.uom = uom;
newSensor.type = type;
settings.analogCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for analog sensor GPIO %02d", gpio);
return StateUpdateResult::CHANGED; // persist the change
},
"local");
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
auto newSensor = AnalogCustomization();
newSensor.gpio = gpio;
newSensor.name = name;
newSensor.offset = offset;
newSensor.factor = factor;
newSensor.uom = uom;
newSensor.type = type;
settings.analogCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for analog sensor GPIO %02d", gpio);
return StateUpdateResult::CHANGED; // persist the change
});
}
// reloads the sensors in the customizations file into the sensors list
@@ -819,20 +815,18 @@ bool AnalogSensor::command_setvalue(const char * value, const int8_t gpio) {
return false;
}
if (oldoffset != sensor.offset()) {
EMSESP::webCustomizationService.update(
[&](WebCustomization & settings) {
for (auto & AnalogCustomization : settings.analogCustomizations) {
if (AnalogCustomization.gpio == sensor.gpio() && AnalogCustomization.type == sensor.type()) {
AnalogCustomization.offset = sensor.offset();
}
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
for (auto & AnalogCustomization : settings.analogCustomizations) {
if (AnalogCustomization.gpio == sensor.gpio() && AnalogCustomization.type == sensor.type()) {
AnalogCustomization.offset = sensor.offset();
}
if (sensor.type() == AnalogType::COUNTER || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.uom() > 0)) {
return StateUpdateResult::UNCHANGED; // temporary change
} else {
return StateUpdateResult::CHANGED; // persist the change
}
},
"local");
}
if (sensor.type() == AnalogType::COUNTER || (sensor.type() == AnalogType::DIGITAL_OUT && sensor.uom() > 0)) {
return StateUpdateResult::UNCHANGED; // temporary change
} else {
return StateUpdateResult::CHANGED; // persist the change
}
});
publish_sensor(sensor);
changed_ = true;
}

View File

@@ -184,12 +184,10 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.enter_password(F_(new_password_prompt2), [password1](Shell & shell, bool completed, const std::string & password2) {
if (completed) {
if (password1 == password2) {
to_app(shell).esp8266React.getSecuritySettingsService()->update(
[&](SecuritySettings & securitySettings) {
securitySettings.jwtSecret = password2.c_str();
return StateUpdateResult::CHANGED;
},
"local");
to_app(shell).esp8266React.getSecuritySettingsService()->update([&](SecuritySettings & securitySettings) {
securitySettings.jwtSecret = password2.c_str();
return StateUpdateResult::CHANGED;
});
shell.println("Admin password updated");
} else {
shell.println("Passwords do not match");
@@ -258,12 +256,10 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
shell.println("The network connection will be reset...");
Shell::loop_all();
delay(1000); // wait a second
to_app(shell).esp8266React.getNetworkSettingsService()->update(
[&](NetworkSettings & networkSettings) {
networkSettings.hostname = arguments.front().c_str();
return StateUpdateResult::CHANGED;
},
"local");
to_app(shell).esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
networkSettings.hostname = arguments.front().c_str();
return StateUpdateResult::CHANGED;
});
});
commands->add_command(ShellContext::MAIN,
@@ -293,21 +289,19 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
if (arguments.size() == 2 && Helpers::toLower(arguments.back()) == "nvs") {
to_app(shell).nvs_.putString("boot", board_profile.c_str());
}
to_app(shell).webSettingsService.update(
[&](WebSettings & settings) {
settings.board_profile = board_profile.c_str();
settings.led_gpio = data[0];
settings.dallas_gpio = data[1];
settings.rx_gpio = data[2];
settings.tx_gpio = data[3];
settings.pbutton_gpio = data[4];
settings.phy_type = data[5];
settings.eth_power = data[6]; // can be -1
settings.eth_phy_addr = data[7];
settings.eth_clock_mode = data[8];
return StateUpdateResult::CHANGED;
},
"local");
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
settings.board_profile = board_profile.c_str();
settings.led_gpio = data[0];
settings.dallas_gpio = data[1];
settings.rx_gpio = data[2];
settings.tx_gpio = data[3];
settings.pbutton_gpio = data[4];
settings.phy_type = data[5];
settings.eth_power = data[6]; // can be -1
settings.eth_phy_addr = data[7];
settings.eth_clock_mode = data[8];
return StateUpdateResult::CHANGED;
});
shell.printfln("Loaded board profile %s", board_profile.c_str());
to_app(shell).system_.network_init(true);
});
@@ -320,13 +314,11 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t device_id = Helpers::hextoint(arguments.front().c_str());
if ((device_id == 0x0B) || (device_id == 0x0D) || (device_id == 0x0A) || (device_id == 0x0F) || (device_id == 0x12)) {
to_app(shell).webSettingsService.update(
[&](WebSettings & settings) {
settings.ems_bus_id = device_id;
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
return StateUpdateResult::CHANGED;
},
"local");
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
settings.ems_bus_id = device_id;
shell.printfln(F_(bus_id_fmt), settings.ems_bus_id);
return StateUpdateResult::CHANGED;
});
} else {
shell.println("Must be 0B, 0D, 0A, 0E, 0F, or 48 - 4D");
}
@@ -342,13 +334,11 @@ static void setup_commands(std::shared_ptr<Commands> & commands) {
[](Shell & shell, const std::vector<std::string> & arguments) {
uint8_t tx_mode = std::strtol(arguments[0].c_str(), nullptr, 10);
// save the tx_mode
to_app(shell).webSettingsService.update(
[&](WebSettings & settings) {
settings.tx_mode = tx_mode;
shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
return StateUpdateResult::CHANGED;
},
"local");
to_app(shell).webSettingsService.update([&](WebSettings & settings) {
settings.tx_mode = tx_mode;
shell.printfln(F_(tx_mode_fmt), settings.tx_mode);
return StateUpdateResult::CHANGED;
});
to_app(shell).uart_init();
});

View File

@@ -32,7 +32,7 @@ class EMSESPConsole : public EMSESPShell {
#endif
~EMSESPConsole() override;
std::string console_name();
std::string console_name() override;
private:
#ifndef EMSESP_STANDALONE

View File

@@ -884,12 +884,10 @@ bool Solar::set_SM10MaxFlow(const char * value, const int8_t id) {
return false;
}
maxFlow_ = (flow * 10);
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.solar_maxflow = maxFlow_;
return StateUpdateResult::CHANGED;
},
"local");
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.solar_maxflow = maxFlow_;
return StateUpdateResult::CHANGED;
});
return true;
}

View File

@@ -1492,8 +1492,10 @@ void EMSESP::start() {
bool factory_settings = false;
#endif
esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc)
webLogService.begin(); // start web log service. now we can start capturing logs to the web log
esp8266React.begin(); // loads core system services settings (network, mqtt, ap, ntp etc)
nvs_.begin("ems-esp", false, "nvs");
LOG_INFO("Starting EMS-ESP version %s", EMSESP_APP_VERSION); // welcome message

View File

@@ -38,8 +38,7 @@
#endif
#include <Preferences.h>
#include <ESP8266React.h>
#include "ESP8266React.h"
#include "web/WebStatusService.h"
#include "web/WebDataService.h"
#include "web/WebSettingsService.h"

View File

@@ -23,8 +23,8 @@
#include "temperaturesensor.h"
#include "version.h"
#include "default_settings.h"
#include <ESP8266React.h>
#include "helpers.h"
#include "ESP8266React.h"
#include <uuid/log.h>

View File

@@ -69,7 +69,7 @@ MAKE_WORD_TRANSLATION(fetch_cmd, "refresh all EMS values", "Lese alle EMS-Werte
MAKE_WORD_TRANSLATION(restart_cmd, "restart EMS-ESP", "Neustart", "opnieuw opstarten", "", "uruchom ponownie EMS-ESP", "restart EMS-ESP", "redémarrer EMS-ESP", "EMS-ESPyi yeniden başlat", "riavvia EMS-ESP", "reštart EMS-ESP") // TODO translate
MAKE_WORD_TRANSLATION(watch_cmd, "watch incoming telegrams", "Watch auf eingehende Telegramme", "inkomende telegrammen bekijken", "", "obserwuj przyczodzące telegramy", "se innkommende telegrammer", "", "Gelen telegramları", "guardare i telegrammi in arrivo", "sledovať prichádzajúce telegramy") // TODO translate
MAKE_WORD_TRANSLATION(publish_cmd, "publish all to MQTT", "Publiziere MQTT", "publiceer alles naar MQTT", "", "opublikuj wszystko na MQTT", "Publiser alt til MQTT", "", "Hepsini MQTTye gönder", "pubblica tutto su MQTT", "zverejniť všetko na MQTT") // TODO translate
MAKE_WORD_TRANSLATION(system_info_cmd, "show system status", "Zeige System-Status", "toon systeemstatus", "", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému") // TODO translate
MAKE_WORD_TRANSLATION(system_info_cmd, "show system info", "Zeige System-Status", "toon systeemstatus", "", "pokaż status systemu", "vis system status", "", "Sistem Durumunu Göster", "visualizza stati di sistema", "zobraziť stav systému") // TODO translate
MAKE_WORD_TRANSLATION(schedule_cmd, "enable schedule item", "Aktiviere Zeitplan", "activeer tijdschema item", "", "aktywuj wybrany harmonogram", "", "", "program öğesini etkinleştir", "abilitare l'elemento programmato", "povoliť položku plánu") // TODO translate
MAKE_WORD_TRANSLATION(entity_cmd, "set custom value on ems", "Sende eigene Entitäten zu EMS", "verstuur custom waarde naar EMS", "", "wyślij własną wartość na EMS", "", "", "emp üzerinde özel değer ayarla", "imposta valori personalizzati su EMS", "nastaviť vlastnú hodnotu na ems") // TODO translate
MAKE_WORD_TRANSLATION(commands_response, "get response", "Hole Antwort", "Verzoek om antwoord", "", "uzyskaj odpowiedź", "", "", "gelen cevap", "", "získať odpoveď") // TODO translate

View File

@@ -201,9 +201,9 @@ void Mqtt::show_mqtt(uuid::console::Shell & shell) {
for (const auto & mqtt_subfunction : mqtt_subfunctions_) {
shell.printfln(" %s/%s", Mqtt::base().c_str(), mqtt_subfunction.topic_.c_str());
}
shell.println();
shell.println();
shell.println();
}
#if defined(EMSESP_TEST)
@@ -388,7 +388,7 @@ void Mqtt::start() {
// add the 'publish' command ('call system publish' in console or via API)
Command::add(EMSdevice::DeviceType::SYSTEM, F_(publish), System::command_publish, FL_(publish_cmd));
// create last will topic with the base prefixed. It has to be static because asyncmqttclient destroys the reference
// create last will topic with the base prefixed. It has to be static because the client destroys the reference
static char will_topic[MQTT_TOPIC_MAX_SIZE];
if (!Mqtt::base().empty()) {
snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "%s/status", Mqtt::base().c_str());
@@ -466,6 +466,7 @@ void Mqtt::on_disconnect(espMqttClientTypes::DisconnectReason reason) {
return;
}
connecting_ = false;
if (reason == espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED) {
LOG_WARNING("MQTT disconnected: TCP");
} else if (reason == espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION) {
@@ -483,6 +484,7 @@ void Mqtt::on_disconnect(espMqttClientTypes::DisconnectReason reason) {
} else {
LOG_WARNING("MQTT disconnected: code %d", reason);
}
mqttClient_->clearQueue(true);
}

View File

@@ -211,8 +211,7 @@ bool System::command_syslog_level(const char * value, const int8_t id) {
changed = true;
}
return StateUpdateResult::CHANGED;
},
"local");
});
if (changed) {
EMSESP::system_.syslog_init();
}
@@ -277,11 +276,12 @@ void System::system_restart() {
// saves all settings
void System::wifi_reconnect() {
LOG_INFO("WiFi reconnecting...");
EMSESP::esp8266React.getNetworkSettingsService()->read(
[](NetworkSettings & networkSettings) { LOG_INFO("WiFi reconnecting to SSID '%s'...", networkSettings.ssid.c_str()); });
Shell::loop_all();
delay(1000); // wait a second
EMSESP::webSettingsService.save(); // local settings
EMSESP::esp8266React.getNetworkSettingsService()->callUpdateHandlers("local"); // in case we've changed ssid or password
delay(1000); // wait a second
EMSESP::webSettingsService.save(); // save local settings
EMSESP::esp8266React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password
}
// format the FS. Wipes everything.
@@ -388,33 +388,6 @@ void System::reload_settings() {
});
}
// adjust WiFi settings
// this for problem solving mesh and connection issues, and also get EMS bus-powered more stable by lowering power
void System::wifi_tweak() {
#if defined(EMSESP_WIFI_TWEAK)
// Default Tx Power is 80 = 20dBm <-- default
// WIFI_POWER_19_5dBm = 78,// 19.5dBm
// WIFI_POWER_19dBm = 76,// 19dBm
// WIFI_POWER_18_5dBm = 74,// 18.5dBm
// WIFI_POWER_17dBm = 68,// 17dBm
// WIFI_POWER_15dBm = 60,// 15dBm
// WIFI_POWER_13dBm = 52,// 13dBm
// WIFI_POWER_11dBm = 44,// 11dBm
// WIFI_POWER_8_5dBm = 34,// 8.5dBm
// WIFI_POWER_7dBm = 28,// 7dBm
// WIFI_POWER_5dBm = 20,// 5dBm
// WIFI_POWER_2dBm = 8,// 2dBm
// WIFI_POWER_MINUS_1dBm = -4// -1dBm
wifi_power_t p1 = WiFi.getTxPower();
(void)WiFi.setTxPower(WIFI_POWER_17dBm);
wifi_power_t p2 = WiFi.getTxPower();
bool s1 = WiFi.getSleep();
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
bool s2 = WiFi.getSleep();
LOG_DEBUG("Adjusting WiFi - Tx power %d->%d, Sleep %d->%d", p1, p2, s1, s2);
#endif
}
// check for valid ESP32 pins. This is very dependent on which ESP32 board is being used.
// Typically you can't use 1, 6-11, 20, 24, 28-31 and 40+
// we allow 0 as it has a special function on the NodeMCU apparently
@@ -472,7 +445,7 @@ void System::start() {
// button single click
void System::button_OnClick(PButton & b) {
LOG_DEBUG("Button pressed - single click");
LOG_NOTICE("Button pressed - single click - show settings folders");
#if defined(EMSESP_TEST)
#ifndef EMSESP_STANDALONE
@@ -483,20 +456,19 @@ void System::button_OnClick(PButton & b) {
// button double click
void System::button_OnDblClick(PButton & b) {
LOG_DEBUG("Button pressed - double click - reconnect");
LOG_NOTICE("Button pressed - double click - wifi reconnect");
EMSESP::system_.wifi_reconnect();
}
// button long press
void System::button_OnLongPress(PButton & b) {
LOG_DEBUG("Button pressed - long press");
LOG_NOTICE("Button pressed - long press");
}
// button indefinite press
void System::button_OnVLongPress(PButton & b) {
LOG_DEBUG("Button pressed - very long press");
LOG_NOTICE("Button pressed - very long press - factory reset");
#ifndef EMSESP_STANDALONE
LOG_WARNING("Performing factory reset...");
EMSESP::esp8266React.factoryReset();
#endif
}
@@ -977,6 +949,8 @@ void System::show_system(uuid::console::Shell & shell) {
shell.printfln(" SSID: %s", WiFi.SSID().c_str());
shell.printfln(" BSSID: %s", WiFi.BSSIDstr().c_str());
shell.printfln(" RSSI: %d dBm (%d %%)", WiFi.RSSI(), wifi_quality(WiFi.RSSI()));
char result[10];
shell.printfln(" TxPower: %s dBm", emsesp::Helpers::render_value(result, (double)(WiFi.getTxPower() / 4), 1));
shell.printfln(" MAC address: %s", WiFi.macAddress().c_str());
shell.printfln(" Hostname: %s", WiFi.getHostname());
shell.printfln(" IPv4 address: %s/%s", uuid::printable_to_string(WiFi.localIP()).c_str(), uuid::printable_to_string(WiFi.subnetMask()).c_str());
@@ -1110,15 +1084,13 @@ bool System::check_upgrade(bool factory_settings) {
version::Semver200_version settings_version(settingsVersion);
#if defined(EMSESP_DEBUG)
if (!missing_version) {
LOG_INFO("Checking version (settings has %d.%d.%d-%s)...",
settings_version.major(),
settings_version.minor(),
settings_version.patch(),
settings_version.prerelease().c_str());
LOG_DEBUG("Checking version upgrade (settings file is v%d.%d.%d-%s)",
settings_version.major(),
settings_version.minor(),
settings_version.patch(),
settings_version.prerelease().c_str());
}
#endif
if (factory_settings) {
return false; // fresh install, do nothing
@@ -1135,14 +1107,23 @@ bool System::check_upgrade(bool factory_settings) {
// if we're coming from 3.4.4 or 3.5.0b14 which had no version stored then we need to apply new settings
if (missing_version) {
LOG_DEBUG("Setting MQTT Entity ID format to v3.4 format");
EMSESP::esp8266React.getMqttSettingsService()->update(
[&](MqttSettings & mqttSettings) {
mqttSettings.entity_format = 0; // use old Entity ID format from v3.4
return StateUpdateResult::CHANGED;
},
"local");
LOG_INFO("Setting MQTT Entity ID format to v3.4 format");
EMSESP::esp8266React.getMqttSettingsService()->update([&](MqttSettings & mqttSettings) {
mqttSettings.entity_format = 0; // use old Entity ID format from v3.4
return StateUpdateResult::CHANGED;
});
}
// Network Settings Wifi tx_power is now using the value * 4.
EMSESP::esp8266React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
if (networkSettings.tx_power == 20) {
networkSettings.tx_power = WIFI_POWER_19_5dBm; // use 19.5 as we don't have 20 anymore
LOG_INFO("Setting WiFi TX Power to Auto");
return StateUpdateResult::CHANGED;
}
return StateUpdateResult::UNCHANGED;
});
} else if (this_version < settings_version) {
// need downgrade
LOG_NOTICE("Downgrading to version %d.%d.%d-%s", this_version.major(), this_version.minor(), this_version.patch(), this_version.prerelease().c_str());
@@ -1153,12 +1134,10 @@ bool System::check_upgrade(bool factory_settings) {
// if we did a change, set the new version and reboot
if (save_version) {
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.version = EMSESP_APP_VERSION;
return StateUpdateResult::CHANGED;
},
"local");
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.version = EMSESP_APP_VERSION;
return StateUpdateResult::CHANGED;
});
return true; // need reboot
}
@@ -1257,6 +1236,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
if (WiFi.status() == WL_CONNECTED && !settings.bssid.isEmpty()) {
node["BSSID"] = "set";
}
node["TxPower setting"] = settings.tx_power;
node["static ip config"] = settings.staticIPConfig;
node["enable IPv6"] = settings.enableIPv6;
node["low bandwidth"] = settings.bandwidth20;
@@ -1580,8 +1560,8 @@ std::string System::reset_reason(uint8_t cpu) const {
// set NTP status
void System::ntp_connected(bool b) {
if (b != ntp_connected_) {
LOG_INFO(b ? "NTP connected" : "NTP disconnected"); // if changed report it
if (b != ntp_connected_ && !b) {
LOG_WARNING("NTP disconnected"); // if turned off report it
}
ntp_connected_ = b;

View File

@@ -75,7 +75,6 @@ class System {
bool upload_status();
void show_mem(const char * note);
void reload_settings();
void wifi_tweak();
void syslog_init();
bool check_upgrade(bool factory_settings);
bool check_restore();

View File

@@ -21,16 +21,15 @@
#include <string>
#include <deque>
#include <uuid/log.h>
// UART drivers
#if defined(ESP32)
#include "uart/emsuart_esp32.h"
#elif defined(EMSESP_STANDALONE)
#include <emsuart_standalone.h>
#include "emsuart_standalone.h"
#endif
#include <uuid/log.h>
#include "helpers.h"
#define MAX_RX_TELEGRAMS 10 // size of Rx queue

View File

@@ -302,31 +302,29 @@ bool TemperatureSensor::update(const std::string & id, const std::string & name,
sensor.set_offset(offset);
// store the new name and offset in our configuration
EMSESP::webCustomizationService.update(
[&](WebCustomization & settings) {
// look it up to see if it exists
bool found = false;
for (auto & SensorCustomization : settings.sensorCustomizations) {
if (SensorCustomization.id == id) {
SensorCustomization.name = name;
SensorCustomization.offset = offset;
found = true;
LOG_DEBUG("Customizing existing sensor ID %s", id.c_str());
break;
}
EMSESP::webCustomizationService.update([&](WebCustomization & settings) {
// look it up to see if it exists
bool found = false;
for (auto & SensorCustomization : settings.sensorCustomizations) {
if (SensorCustomization.id == id) {
SensorCustomization.name = name;
SensorCustomization.offset = offset;
found = true;
LOG_DEBUG("Customizing existing sensor ID %s", id.c_str());
break;
}
if (!found) {
SensorCustomization newSensor = SensorCustomization();
newSensor.id = id;
newSensor.name = name;
newSensor.offset = offset;
settings.sensorCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for sensor ID %s", id.c_str());
}
sensor.ha_registered = false; // it's changed so we may need to recreate the HA config
return StateUpdateResult::CHANGED;
},
"local");
}
if (!found) {
SensorCustomization newSensor = SensorCustomization();
newSensor.id = id;
newSensor.name = name;
newSensor.offset = offset;
settings.sensorCustomizations.push_back(newSensor);
LOG_DEBUG("Adding new customization for sensor ID %s", id.c_str());
}
sensor.ha_registered = false; // it's changed so we may need to recreate the HA config
return StateUpdateResult::CHANGED;
});
return true;
}
}

View File

@@ -1978,20 +1978,22 @@ void Test::listDir(fs::FS & fs, const char * dirname, uint8_t levels) {
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.print(" DIR: ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
Serial.println();
} else {
Serial.print(" FILE: ");
Serial.print(" ");
Serial.print(file.name());
Serial.print("\tSIZE: ");
Serial.println(file.size());
Serial.print(" (");
Serial.print(file.size());
Serial.println(" bytes)");
}
file = root.openNextFile();
}
Serial.println();
}
#endif
#endif

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.6.5-test.13"
#define EMSESP_APP_VERSION "3.6.5-test.14"

View File

@@ -18,8 +18,6 @@
#include "emsesp.h"
using namespace std::placeholders; // for `_1` etc
namespace emsesp {
uint32_t WebAPIService::api_count_ = 0;
@@ -27,17 +25,26 @@ uint16_t WebAPIService::api_fails_ = 0;
WebAPIService::WebAPIService(AsyncWebServer * server, SecurityManager * securityManager)
: _securityManager(securityManager)
, _apiHandler("/api", std::bind(&WebAPIService::webAPIService_post, this, _1, _2)) { // for POSTS, must use 'Content-Type: application/json' in header
server->on("/api", HTTP_GET, std::bind(&WebAPIService::webAPIService_get, this, _1)); // for GETS
, _apiHandler(EMSESP_API_SERVICE_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { webAPIService_post(request, json); }) { // for POSTs
server->on(EMSESP_API_SERVICE_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { webAPIService_get(request); }); // for GETs
server->addHandler(&_apiHandler);
// for settings
server->on(GET_SETTINGS_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSettings, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_SETTINGS_PATH,
HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSettings(request); }, AuthenticationPredicates::IS_ADMIN));
server->on(GET_CUSTOMIZATIONS_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebAPIService::getCustomizations, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_SCHEDULE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getSchedule, this, _1), AuthenticationPredicates::IS_ADMIN));
server->on(GET_ENTITIES_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&WebAPIService::getEntities, this, _1), AuthenticationPredicates::IS_ADMIN));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getCustomizations(request); }, AuthenticationPredicates::IS_ADMIN));
server->on(GET_SCHEDULE_PATH,
HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getSchedule(request); }, AuthenticationPredicates::IS_ADMIN));
server->on(GET_ENTITIES_PATH,
HTTP_GET,
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { getEntities(request); }, AuthenticationPredicates::IS_ADMIN));
}
// HTTP GET

View File

@@ -20,8 +20,6 @@
namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebCustomEntityService::WebCustomEntityService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebCustomEntity::read,
WebCustomEntity::update,
@@ -628,52 +626,50 @@ bool WebCustomEntityService::get_value(std::shared_ptr<const Telegram> telegram)
// hard coded tests
#ifdef EMSESP_TEST
void WebCustomEntityService::test() {
update(
[&](WebCustomEntity & webCustomEntity) {
webCustomEntity.customEntityItems.clear();
// test 1
auto entityItem = CustomEntityItem();
entityItem.ram = 0;
entityItem.device_id = 8;
entityItem.type_id = 24;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_custom";
entityItem.uom = 1;
entityItem.value_type = 1;
entityItem.writeable = true;
entityItem.data = "70";
webCustomEntity.customEntityItems.push_back(entityItem);
update([&](WebCustomEntity & webCustomEntity) {
webCustomEntity.customEntityItems.clear();
// test 1
auto entityItem = CustomEntityItem();
entityItem.ram = 0;
entityItem.device_id = 8;
entityItem.type_id = 24;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_custom";
entityItem.uom = 1;
entityItem.value_type = 1;
entityItem.writeable = true;
entityItem.data = "70";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 0;
entityItem.device_id = 24;
entityItem.type_id = 677;
entityItem.offset = 3;
entityItem.factor = 1;
entityItem.name = "test_read_only";
entityItem.uom = 0;
entityItem.value_type = 2;
entityItem.writeable = false;
entityItem.data = "48";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 0;
entityItem.device_id = 24;
entityItem.type_id = 677;
entityItem.offset = 3;
entityItem.factor = 1;
entityItem.name = "test_read_only";
entityItem.uom = 0;
entityItem.value_type = 2;
entityItem.writeable = false;
entityItem.data = "48";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 1;
entityItem.device_id = 0;
entityItem.type_id = 0;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_ram";
entityItem.uom = 0;
entityItem.value_type = 8;
entityItem.writeable = true;
entityItem.data = "14";
webCustomEntity.customEntityItems.push_back(entityItem);
// test 2
entityItem.ram = 1;
entityItem.device_id = 0;
entityItem.type_id = 0;
entityItem.offset = 0;
entityItem.factor = 1;
entityItem.name = "test_ram";
entityItem.uom = 0;
entityItem.value_type = 8;
entityItem.writeable = true;
entityItem.data = "14";
webCustomEntity.customEntityItems.push_back(entityItem);
return StateUpdateResult::CHANGED; // persist the changes
},
"local");
return StateUpdateResult::CHANGED; // persist the changes
});
}
#endif

View File

@@ -20,27 +20,24 @@
namespace emsesp {
using namespace std::placeholders; // for `_1` etc
bool WebCustomization::_start = true;
WebCustomizationService::WebCustomizationService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _fsPersistence(WebCustomization::read, WebCustomization::update, this, fs, EMSESP_CUSTOMIZATION_FILE)
, _masked_entities_handler(CUSTOMIZATION_ENTITIES_PATH,
securityManager->wrapCallback(std::bind(&WebCustomizationService::customization_entities, this, _1, _2),
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { customization_entities(request, json); },
AuthenticationPredicates::IS_AUTHENTICATED)) {
server->on(DEVICE_ENTITIES_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebCustomizationService::device_entities, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_entities(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
server->on(DEVICES_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebCustomizationService::devices, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { devices(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
server->on(RESET_CUSTOMIZATION_SERVICE_PATH,
HTTP_POST,
securityManager->wrapRequest(std::bind(&WebCustomizationService::reset_customization, this, _1), AuthenticationPredicates::IS_ADMIN));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { reset_customization(request); }, AuthenticationPredicates::IS_ADMIN));
_masked_entities_handler.setMethod(HTTP_POST);
_masked_entities_handler.setMaxContentLength(2048);
@@ -276,30 +273,28 @@ void WebCustomizationService::customization_entities(AsyncWebServerRequest * req
emsdevice->getCustomizationEntities(entity_ids);
// Save the list to the customization file
update(
[&](WebCustomization & settings) {
// see if we already have a mask list for this device, if so remove it
for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) {
if ((*it).product_id == product_id && (*it).device_id == device_id) {
it = settings.entityCustomizations.erase(it);
break;
} else {
++it;
}
update([&](WebCustomization & settings) {
// see if we already have a mask list for this device, if so remove it
for (auto it = settings.entityCustomizations.begin(); it != settings.entityCustomizations.end();) {
if ((*it).product_id == product_id && (*it).device_id == device_id) {
it = settings.entityCustomizations.erase(it);
break;
} else {
++it;
}
}
// create a new entry for this device if there are values
EntityCustomization new_entry;
new_entry.product_id = product_id;
new_entry.device_id = device_id;
// create a new entry for this device if there are values
EntityCustomization new_entry;
new_entry.product_id = product_id;
new_entry.device_id = device_id;
new_entry.entity_ids = entity_ids;
new_entry.entity_ids = entity_ids;
// add the record and save
settings.entityCustomizations.push_back(new_entry);
return StateUpdateResult::CHANGED;
},
"local");
// add the record and save
settings.entityCustomizations.push_back(new_entry);
return StateUpdateResult::CHANGED;
});
break;
}
@@ -320,54 +315,52 @@ void WebCustomizationService::begin() {
// hard coded tests
#ifdef EMSESP_TEST
void WebCustomizationService::test() {
update(
[&](WebCustomization & webCustomization) {
// Temperature sensors
webCustomization.sensorCustomizations.clear();
auto sensor = SensorCustomization();
sensor.id = "01-0203-0405-0607";
sensor.name = "test_sensor1";
sensor.offset = 0;
webCustomization.sensorCustomizations.push_back(sensor);
update([&](WebCustomization & webCustomization) {
// Temperature sensors
webCustomization.sensorCustomizations.clear();
auto sensor = SensorCustomization();
sensor.id = "01-0203-0405-0607";
sensor.name = "test_sensor1";
sensor.offset = 0;
webCustomization.sensorCustomizations.push_back(sensor);
sensor = SensorCustomization();
sensor.id = "0B-0C0D-0E0F-1011";
sensor.name = "test_sensor2";
sensor.offset = 4;
webCustomization.sensorCustomizations.push_back(sensor);
sensor = SensorCustomization();
sensor.id = "0B-0C0D-0E0F-1011";
sensor.name = "test_sensor2";
sensor.offset = 4;
webCustomization.sensorCustomizations.push_back(sensor);
// Analog sensors
// This actually adds the sensors as we use customizations to store them
webCustomization.analogCustomizations.clear();
auto analog = AnalogCustomization();
analog.gpio = 36;
analog.name = "test_analog1";
analog.offset = 0;
analog.factor = 0.1;
analog.uom = 17;
analog.type = 3;
webCustomization.analogCustomizations.push_back(analog);
// Analog sensors
// This actually adds the sensors as we use customizations to store them
webCustomization.analogCustomizations.clear();
auto analog = AnalogCustomization();
analog.gpio = 36;
analog.name = "test_analog1";
analog.offset = 0;
analog.factor = 0.1;
analog.uom = 17;
analog.type = 3;
webCustomization.analogCustomizations.push_back(analog);
analog = AnalogCustomization();
analog.gpio = 37;
analog.name = "test_analog2";
analog.offset = 0;
analog.factor = 1;
analog.uom = 0;
analog.type = 1;
webCustomization.analogCustomizations.push_back(analog);
analog = AnalogCustomization();
analog.gpio = 37;
analog.name = "test_analog2";
analog.offset = 0;
analog.factor = 1;
analog.uom = 0;
analog.type = 1;
webCustomization.analogCustomizations.push_back(analog);
// EMS entities
webCustomization.entityCustomizations.clear();
auto emsEntity = EntityCustomization();
emsEntity.product_id = 123;
emsEntity.device_id = 8;
emsEntity.entity_ids.push_back("08heatingactive|is my heating on?");
webCustomization.entityCustomizations.push_back(emsEntity);
// EMS entities
webCustomization.entityCustomizations.clear();
auto emsEntity = EntityCustomization();
emsEntity.product_id = 123;
emsEntity.device_id = 8;
emsEntity.entity_ids.push_back("08heatingactive|is my heating on?");
webCustomization.entityCustomizations.push_back(emsEntity);
return StateUpdateResult::CHANGED; // persist the changes
},
"local");
return StateUpdateResult::CHANGED; // persist the changes
});
EMSESP::analogsensor_.reload(); // this is needed to active the analog sensors
}

View File

@@ -20,33 +20,36 @@
namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebDataService::WebDataService(AsyncWebServer * server, SecurityManager * securityManager)
: _write_value_handler(WRITE_DEVICE_VALUE_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_device_value, this, _1, _2), AuthenticationPredicates::IS_ADMIN))
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_device_value(request, json); },
AuthenticationPredicates::IS_ADMIN))
, _write_temperature_handler(WRITE_TEMPERATURE_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_temperature_sensor, this, _1, _2),
securityManager->wrapCallback([this](AsyncWebServerRequest * request,
JsonVariant json) { write_temperature_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN))
, _write_analog_handler(WRITE_ANALOG_SENSOR_SERVICE_PATH,
securityManager->wrapCallback(std::bind(&WebDataService::write_analog_sensor, this, _1, _2), AuthenticationPredicates::IS_ADMIN)) {
securityManager->wrapCallback([this](AsyncWebServerRequest * request, JsonVariant json) { write_analog_sensor(request, json); },
AuthenticationPredicates::IS_ADMIN)) {
// GET's
server->on(DEVICE_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::device_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { device_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
server->on(CORE_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::core_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { core_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
server->on(SENSOR_DATA_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebDataService::sensor_data, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { sensor_data(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
// POST's
server->on(SCAN_DEVICES_SERVICE_PATH,
HTTP_POST,
securityManager->wrapRequest(std::bind(&WebDataService::scan_devices, this, _1), AuthenticationPredicates::IS_ADMIN));
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { scan_devices(request); }, AuthenticationPredicates::IS_ADMIN));
_write_value_handler.setMethod(HTTP_POST);
_write_value_handler.setMaxContentLength(256);

View File

@@ -18,19 +18,18 @@
#include "emsesp.h"
using namespace std::placeholders;
namespace emsesp {
WebLogService::WebLogService(AsyncWebServer * server, SecurityManager * securityManager)
: events_(EVENT_SOURCE_LOG_PATH)
, setValues_(LOG_SETTINGS_PATH, std::bind(&WebLogService::setValues, this, _1, _2)) {
, setValues_(LOG_SETTINGS_PATH, [this](AsyncWebServerRequest * request, JsonVariant json) { setValues(request, json); }) {
events_.setFilter(securityManager->filterRequest(AuthenticationPredicates::IS_ADMIN));
server->on(LOG_SETTINGS_PATH, HTTP_GET, std::bind(&WebLogService::getValues, this, _1)); // get settings
// get settings
server->on(LOG_SETTINGS_PATH, HTTP_GET, [this](AsyncWebServerRequest * request) { getValues(request); });
// for bring back the whole log - is a command, hence a POST
server->on(FETCH_LOG_PATH, HTTP_POST, std::bind(&WebLogService::fetchLog, this, _1));
server->on(FETCH_LOG_PATH, HTTP_POST, [this](AsyncWebServerRequest * request) { fetchLog(request); });
server->addHandler(&setValues_);
server->addHandler(&events_);
@@ -59,12 +58,10 @@ uuid::log::Level WebLogService::log_level() const {
}
void WebLogService::log_level(uuid::log::Level level) {
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.weblog_level = level;
return StateUpdateResult::CHANGED;
},
"local");
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.weblog_level = level;
return StateUpdateResult::CHANGED;
});
uuid::log::Logger::register_handler(this, level);
if (level == uuid::log::Level::OFF) {
log_messages_.clear();
@@ -87,12 +84,10 @@ void WebLogService::maximum_log_messages(size_t count) {
while (log_messages_.size() > maximum_log_messages_) {
log_messages_.pop_front();
}
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.weblog_buffer = count;
return StateUpdateResult::CHANGED;
},
"local");
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.weblog_buffer = count;
return StateUpdateResult::CHANGED;
});
}
bool WebLogService::compact() const {
@@ -101,12 +96,10 @@ bool WebLogService::compact() const {
void WebLogService::compact(bool compact) {
compact_ = compact;
EMSESP::webSettingsService.update(
[&](WebSettings & settings) {
settings.weblog_compact = compact;
return StateUpdateResult::CHANGED;
},
"local");
EMSESP::webSettingsService.update([&](WebSettings & settings) {
settings.weblog_compact = compact;
return StateUpdateResult::CHANGED;
});
}
WebLogService::QueuedLogMessage::QueuedLogMessage(unsigned long id, std::shared_ptr<uuid::log::Message> && content)

View File

@@ -28,7 +28,7 @@ namespace emsesp {
class WebLogService : public uuid::log::Handler {
public:
static constexpr size_t MAX_LOG_MESSAGES = 50;
static constexpr size_t REFRESH_SYNC = 50;
static constexpr size_t REFRESH_SYNC = 30;
WebLogService(AsyncWebServer * server, SecurityManager * securityManager);

View File

@@ -21,8 +21,6 @@
namespace emsesp {
using namespace std::placeholders; // for `_1` etc
WebSchedulerService::WebSchedulerService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebScheduler::read, WebScheduler::update, this, server, EMSESP_SCHEDULER_SERVICE_PATH, securityManager, AuthenticationPredicates::IS_AUTHENTICATED)
, _fsPersistence(WebScheduler::read, WebScheduler::update, this, fs, EMSESP_SCHEDULER_FILE) {
@@ -432,25 +430,23 @@ void WebSchedulerService::loop() {
// hard coded tests
#if defined(EMSESP_TEST)
void WebSchedulerService::test() {
update(
[&](WebScheduler & webScheduler) {
webScheduler.scheduleItems.clear();
// test 1
auto si = ScheduleItem();
si.active = true;
si.flags = 1;
si.time = "12:00";
si.cmd = "system/fetch";
si.value = "10";
si.name = "test_scheduler";
si.elapsed_min = 0;
si.retry_cnt = 0xFF; // no startup retries
update([&](WebScheduler & webScheduler) {
webScheduler.scheduleItems.clear();
// test 1
auto si = ScheduleItem();
si.active = true;
si.flags = 1;
si.time = "12:00";
si.cmd = "system/fetch";
si.value = "10";
si.name = "test_scheduler";
si.elapsed_min = 0;
si.retry_cnt = 0xFF; // no startup retries
webScheduler.scheduleItems.push_back(si);
webScheduler.scheduleItems.push_back(si);
return StateUpdateResult::CHANGED; // persist the changes
},
"local");
return StateUpdateResult::CHANGED; // persist the changes
});
}
#endif

View File

@@ -22,17 +22,13 @@ namespace emsesp {
uint8_t WebSettings::flags_ = 0;
using namespace std::placeholders; // for `_1` etc
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
, _fsPersistence(WebSettings::read, WebSettings::update, this, fs, EMSESP_SETTINGS_FILE) {
// GET
server->on(EMSESP_BOARD_PROFILE_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebSettingsService::board_profile, this, _1), AuthenticationPredicates::IS_ADMIN));
addUpdateHandler([&](const String & originId) { onUpdate(); }, false);
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { board_profile(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
addUpdateHandler([this] { onUpdate(); }, false);
}
void WebSettings::read(WebSettings & settings, JsonObject root) {

View File

@@ -18,100 +18,12 @@
#include "emsesp.h"
using namespace std::placeholders; // for `_1` etc
namespace emsesp {
WebStatusService::WebStatusService(AsyncWebServer * server, SecurityManager * securityManager) {
// rest endpoint for web page
server->on(EMSESP_STATUS_SERVICE_PATH,
HTTP_GET,
securityManager->wrapRequest(std::bind(&WebStatusService::webStatusService, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
WiFi.onEvent(std::bind(&WebStatusService::WiFiEvent, this, _1, _2));
}
// handles both WiFI and Ethernet
void WebStatusService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
#ifndef EMSESP_STANDALONE
switch (event) {
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
EMSESP::logger().warning("WiFi disconnected. Reason: %s (%d)",
disconnectReason(info.wifi_sta_disconnected.reason),
info.wifi_sta_disconnected.reason); // IDF 4.0
EMSESP::system_.has_ipv6(false);
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
EMSESP::logger().info("WiFi connected with IP=%s, hostname=%s", WiFi.localIP().toString().c_str(), WiFi.getHostname());
mDNS_start();
break;
case ARDUINO_EVENT_ETH_START:
// EMSESP::logger().info("Ethernet initialized");
ETH.setHostname(EMSESP::system_.hostname().c_str());
// configure for static IP
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.staticIPConfig) {
ETH.config(networkSettings.localIP, networkSettings.gatewayIP, networkSettings.subnetMask, networkSettings.dnsIP1, networkSettings.dnsIP2);
}
});
break;
case ARDUINO_EVENT_ETH_GOT_IP:
// prevent double calls
if (!EMSESP::system_.ethernet_connected()) {
EMSESP::logger().info("Ethernet connected with IP=%s, speed %d Mbps", ETH.localIP().toString().c_str(), ETH.linkSpeed());
EMSESP::system_.ethernet_connected(true);
mDNS_start();
}
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
EMSESP::logger().warning("Ethernet disconnected");
EMSESP::system_.ethernet_connected(false);
EMSESP::system_.has_ipv6(false);
break;
case ARDUINO_EVENT_ETH_STOP:
EMSESP::logger().info("Ethernet stopped");
EMSESP::system_.ethernet_connected(false);
EMSESP::system_.has_ipv6(false);
break;
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableIPv6) {
WiFi.enableIpV6();
}
});
break;
case ARDUINO_EVENT_ETH_CONNECTED:
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableIPv6) {
ETH.enableIpV6();
}
});
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
case ARDUINO_EVENT_ETH_GOT_IP6:
if (EMSESP::system_.ethernet_connected()) {
EMSESP::logger().info("Ethernet connected with IPv6=%s, speed %d Mbps", ETH.localIPv6().toString().c_str(), ETH.linkSpeed());
} else {
EMSESP::logger().info("WiFi connected with IPv6=%s, hostname=%s", WiFi.localIPv6().toString().c_str(), WiFi.getHostname());
}
mDNS_start();
EMSESP::system_.has_ipv6(true);
break;
default:
break;
}
#endif
securityManager->wrapRequest([this](AsyncWebServerRequest * request) { webStatusService(request); }, AuthenticationPredicates::IS_AUTHENTICATED));
}
void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
@@ -193,112 +105,4 @@ void WebStatusService::webStatusService(AsyncWebServerRequest * request) {
request->send(response);
}
// start the multicast UDP service so EMS-ESP is discoverable via .local
void WebStatusService::mDNS_start() const {
#ifndef EMSESP_STANDALONE
MDNS.end();
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableMDNS) {
if (!MDNS.begin(EMSESP::system_.hostname().c_str())) {
EMSESP::logger().warning("Failed to start mDNS responder service");
return;
}
std::string address_s = EMSESP::system_.hostname() + ".local";
MDNS.addService("http", "tcp", 80); // add our web server and rest API
MDNS.addService("telnet", "tcp", 23); // add our telnet console
MDNS.addServiceTxt("http", "tcp", "version", EMSESP_APP_VERSION);
MDNS.addServiceTxt("http", "tcp", "address", address_s.c_str());
EMSESP::logger().info("mDNS responder service started");
}
});
#else
EMSESP::esp8266React.getNetworkSettingsService()->read([&](NetworkSettings & networkSettings) {
if (networkSettings.enableMDNS) {
EMSESP::logger().info("mDNS responder service started");
}
});
#endif
}
const char * WebStatusService::disconnectReason(uint8_t code) {
#ifndef EMSESP_STANDALONE
switch (code) {
case WIFI_REASON_UNSPECIFIED: // = 1,
return "unspecified";
case WIFI_REASON_AUTH_EXPIRE: // = 2,
return "auth expire";
case WIFI_REASON_AUTH_LEAVE: // = 3,
return "auth leave";
case WIFI_REASON_ASSOC_EXPIRE: // = 4,
return "assoc expired";
case WIFI_REASON_ASSOC_TOOMANY: // = 5,
return "assoc too many";
case WIFI_REASON_NOT_AUTHED: // = 6,
return "not authenticated";
case WIFI_REASON_NOT_ASSOCED: // = 7,
return "not assoc";
case WIFI_REASON_ASSOC_LEAVE: // = 8,
return "assoc leave";
case WIFI_REASON_ASSOC_NOT_AUTHED: // = 9,
return "assoc not authed";
case WIFI_REASON_DISASSOC_PWRCAP_BAD: // = 10,
return "disassoc powerCAP bad";
case WIFI_REASON_DISASSOC_SUPCHAN_BAD: // = 11,
return "disassoc supchan bad";
case WIFI_REASON_IE_INVALID: // = 13,
return "IE invalid";
case WIFI_REASON_MIC_FAILURE: // = 14,
return "MIC failure";
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: // = 15,
return "4way handshake timeout";
case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: // = 16,
return "group key-update timeout";
case WIFI_REASON_IE_IN_4WAY_DIFFERS: // = 17,
return "IE in 4way differs";
case WIFI_REASON_GROUP_CIPHER_INVALID: // = 18,
return "group cipher invalid";
case WIFI_REASON_PAIRWISE_CIPHER_INVALID: // = 19,
return "pairwise cipher invalid";
case WIFI_REASON_AKMP_INVALID: // = 20,
return "AKMP invalid";
case WIFI_REASON_UNSUPP_RSN_IE_VERSION: // = 21,
return "unsupported RSN_IE version";
case WIFI_REASON_INVALID_RSN_IE_CAP: // = 22,
return "invalid RSN_IE_CAP";
case WIFI_REASON_802_1X_AUTH_FAILED: // = 23,
return "802 X1 auth failed";
case WIFI_REASON_CIPHER_SUITE_REJECTED: // = 24,
return "cipher suite rejected";
case WIFI_REASON_BEACON_TIMEOUT: // = 200,
return "beacon timeout";
case WIFI_REASON_NO_AP_FOUND: // = 201,
return "no AP found";
case WIFI_REASON_AUTH_FAIL: // = 202,
return "auth fail";
case WIFI_REASON_ASSOC_FAIL: // = 203,
return "assoc fail";
case WIFI_REASON_HANDSHAKE_TIMEOUT: // = 204,
return "handshake timeout";
case WIFI_REASON_CONNECTION_FAIL: // 205,
return "connection fail";
case WIFI_REASON_AP_TSF_RESET: // 206,
return "AP tsf reset";
case WIFI_REASON_ROAMING: // 207,
return "roaming";
case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: // 208,
return "assoc comeback time too long";
case WIFI_REASON_SA_QUERY_TIMEOUT: // 209,
return "sa query timeout";
default:
return "unknown";
}
#endif
return "";
}
} // namespace emsesp

View File

@@ -19,8 +19,6 @@
#ifndef WebStatusService_h
#define WebStatusService_h
#include <ESPmDNS.h>
#define EMSESP_STATUS_SERVICE_PATH "/rest/status"
namespace emsesp {
@@ -30,10 +28,7 @@ class WebStatusService {
WebStatusService(AsyncWebServer * server, SecurityManager * securityManager);
private:
void webStatusService(AsyncWebServerRequest * request);
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
void mDNS_start() const;
const char * disconnectReason(uint8_t code);
void webStatusService(AsyncWebServerRequest * request);
};
} // namespace emsesp