Merge branch 'dev' into core3

This commit is contained in:
MichaelDvP
2026-05-07 12:10:53 +02:00
9 changed files with 84 additions and 40 deletions

View File

@@ -22,6 +22,7 @@ For more details go to [emsesp.org](https://emsesp.org/).
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960) - SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
- missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015) - missing translations [#3015](https://github.com/emsesp/EMS-ESP32/issues/3015)
- custom entities check fetch length - custom entities check fetch length
- modbus initialization [#3064](https://github.com/emsesp/EMS-ESP32/issues/3064)
## Changed ## Changed

View File

@@ -167,10 +167,14 @@ bool MqttSettingsService::configureMqtt() {
#ifndef NO_TLS_SUPPORT #ifndef NO_TLS_SUPPORT
if (_state.enableTLS) { if (_state.enableTLS) {
if (_state.rootCA == "insecure") { if (_state.rootCA == "insecure") {
#if defined(EMSESP_DEBUG)
emsesp::EMSESP::logger().debug("Start insecure MQTT"); emsesp::EMSESP::logger().debug("Start insecure MQTT");
#endif
static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure(); static_cast<espMqttClientSecure *>(_mqttClient)->setInsecure();
} else { } else {
#if defined(EMSESP_DEBUG)
emsesp::EMSESP::logger().debug("Start secure MQTT with rootCA"); emsesp::EMSESP::logger().debug("Start secure MQTT with rootCA");
#endif
String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n"; String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n";
static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(certificate.c_str()); static_cast<espMqttClientSecure *>(_mqttClient)->setCACert(certificate.c_str());
} }

View File

@@ -637,6 +637,29 @@ void System::syslog_init() {
#endif #endif
} }
// start or reconfigure modbus
void System::modbus_init() {
EMSESP::webSettingsService.read([&](WebSettings & settings) {
if (settings.modbus_enabled) {
if (EMSESP::modbus_ == nullptr) {
EMSESP::modbus_ = new Modbus;
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
} else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) {
EMSESP::modbus_->stop();
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
}
} else if (EMSESP::modbus_ != nullptr) {
EMSESP::modbus_->stop();
delete EMSESP::modbus_;
EMSESP::modbus_ = nullptr;
}
modbus_enabled_ = settings.modbus_enabled;
modbus_port_ = settings.modbus_port;
modbus_max_clients_ = settings.modbus_max_clients;
modbus_timeout_ = settings.modbus_timeout;
});
}
// read specific major system settings to store locally for faster access // read specific major system settings to store locally for faster access
void System::store_settings(WebSettings & settings) { void System::store_settings(WebSettings & settings) {
version_ = settings.version; version_ = settings.version;
@@ -668,25 +691,6 @@ void System::store_settings(WebSettings & settings) {
readonly_mode_ = settings.readonly_mode; readonly_mode_ = settings.readonly_mode;
locale_ = settings.locale; locale_ = settings.locale;
developer_mode_ = settings.developer_mode; developer_mode_ = settings.developer_mode;
// start services
if (settings.modbus_enabled) {
if (EMSESP::modbus_ == nullptr) {
EMSESP::modbus_ = new Modbus;
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
} else if (settings.modbus_port != modbus_port_ || settings.modbus_max_clients != modbus_max_clients_ || settings.modbus_timeout != modbus_timeout_) {
EMSESP::modbus_->stop();
EMSESP::modbus_->start(1, settings.modbus_port, settings.modbus_max_clients, settings.modbus_timeout * 1000);
}
} else if (EMSESP::modbus_ != nullptr) {
EMSESP::modbus_->stop();
delete EMSESP::modbus_;
EMSESP::modbus_ = nullptr;
}
modbus_enabled_ = settings.modbus_enabled;
modbus_port_ = settings.modbus_port;
modbus_max_clients_ = settings.modbus_max_clients;
modbus_timeout_ = settings.modbus_timeout;
} }
// Starts up core services // Starts up core services
@@ -728,6 +732,7 @@ void System::start() {
last_system_check_ = 0; // force the LED to go from fast flash to pulse last_system_check_ = 0; // force the LED to go from fast flash to pulse
uart_init(); // start UART uart_init(); // start UART
syslog_init(); // start syslog syslog_init(); // start syslog
modbus_init(); // start modbus
} }
// button single click // button single click
@@ -3421,6 +3426,24 @@ void System::remove_gpio(uint8_t pin, bool also_system) {
} }
} }
// remove a gpio that has 0 for disable
void System::remove_optional_gpio(uint8_t pin) {
if (pin) {
remove_gpio(pin, false);
}
}
// set unused gpios to default state input high-Z
void System::reset_unused_gpios() {
for (const auto & pin : valid_system_gpios_) {
auto it = std::find_if(used_gpios_.begin(), used_gpios_.end(), [pin](const GpioUsage & usage) { return usage.pin == pin; });
if (it == used_gpios_.end()) {
LOG_DEBUG("reset pin %d", pin);
pinMode(pin, INPUT);
}
}
}
// return a list of GPIO's available for use // return a list of GPIO's available for use
std::vector<uint8_t> System::available_gpios() { std::vector<uint8_t> System::available_gpios() {
std::vector<uint8_t> gpios; std::vector<uint8_t> gpios;

View File

@@ -115,6 +115,7 @@ class System {
void show_mem(const char * note); void show_mem(const char * note);
void store_settings(class WebSettings & settings); void store_settings(class WebSettings & settings);
void syslog_init(); void syslog_init();
void modbus_init();
bool check_upgrade(); bool check_upgrade();
bool check_restore(); bool check_restore();
void heartbeat_json(JsonObject output); void heartbeat_json(JsonObject output);
@@ -342,6 +343,8 @@ class System {
#endif #endif
static void remove_gpio(uint8_t pin, bool also_system = false); // remove a gpio from both valid (optional) and used lists static void remove_gpio(uint8_t pin, bool also_system = false); // remove a gpio from both valid (optional) and used lists
static void remove_optional_gpio(uint8_t pin);
static void reset_unused_gpios();
// Partition info map: partition name -> {version, size, install_date} // Partition info map: partition name -> {version, size, install_date}
std::map<std::string, PartitionInfo, std::less<>, AllocatorPSRAM<std::pair<const std::string, PartitionInfo>>> partition_info_; std::map<std::string, PartitionInfo, std::less<>, AllocatorPSRAM<std::pair<const std::string, PartitionInfo>>> partition_info_;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.9.0-dev.3" #define EMSESP_APP_VERSION "3.9.0-dev.4"

View File

@@ -166,7 +166,9 @@ StateUpdateResult WebCustomEntity::update(JsonObject root, WebCustomEntity & web
bool WebCustomEntityService::command_setvalue(const char * value, const int8_t id, const char * name) { bool WebCustomEntityService::command_setvalue(const char * value, const int8_t id, const char * name) {
// don't write if there is no value, to prevent setting an empty value by mistake when parsing attributes // don't write if there is no value, to prevent setting an empty value by mistake when parsing attributes
if (!strlen(value)) { if (!strlen(value)) {
#if defined(EMSESP_DEBUG)
EMSESP::logger().debug("can't set empty value!"); EMSESP::logger().debug("can't set empty value!");
#endif
return false; return false;
} }

View File

@@ -563,7 +563,9 @@ void WebSchedulerService::condition() {
} else if (match.length() == 1 && match[0] == '0' && scheduleItem.retry_cnt == 1) { } else if (match.length() == 1 && match[0] == '0' && scheduleItem.retry_cnt == 1) {
scheduleItem.retry_cnt = 0xFF; scheduleItem.retry_cnt = 0xFF;
} else if (match.length() != 1) { // the match is not boolean } else if (match.length() != 1) { // the match is not boolean
#if defined(EMSESP_DEBUG)
EMSESP::logger().debug("condition result: %s", match.c_str()); EMSESP::logger().debug("condition result: %s", match.c_str());
#endif
} }
} }
} }

View File

@@ -20,7 +20,7 @@
namespace emsesp { namespace emsesp {
uint8_t WebSettings::flags_ = 0; uint16_t WebSettings::flags_ = 0;
WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager) WebSettingsService::WebSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
: _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager) : _httpEndpoint(WebSettings::read, WebSettings::update, this, server, EMSESP_SETTINGS_SERVICE_PATH, securityManager)
@@ -128,11 +128,11 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
reset_flags(); reset_flags();
// before loading new board profile free old gpios from used list to allow remapping // before loading new board profile free old gpios from used list to allow remapping
EMSESP::system_.remove_gpio(original_settings.led_gpio); EMSESP::system_.remove_optional_gpio(original_settings.led_gpio);
EMSESP::system_.remove_gpio(original_settings.dallas_gpio); EMSESP::system_.remove_optional_gpio(original_settings.dallas_gpio);
EMSESP::system_.remove_gpio(original_settings.pbutton_gpio); EMSESP::system_.remove_gpio(original_settings.pbutton_gpio);
EMSESP::system_.remove_gpio(original_settings.rx_gpio); EMSESP::system_.remove_optional_gpio(original_settings.rx_gpio);
EMSESP::system_.remove_gpio(original_settings.tx_gpio); EMSESP::system_.remove_optional_gpio(original_settings.tx_gpio);
// see if the user has changed the board profile // see if the user has changed the board profile
// this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type // this will set: led_gpio, dallas_gpio, rx_gpio, tx_gpio, pbutton_gpio, phy_type, eth_power, eth_phy_addr, eth_clock_mode, led_type
@@ -256,10 +256,14 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
check_flag(original_settings.low_clock, settings.low_clock, ChangeFlags::RESTART); check_flag(original_settings.low_clock, settings.low_clock, ChangeFlags::RESTART);
// Modbus settings // Modbus settings
settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED; settings.modbus_enabled = root["modbus_enabled"] | EMSESP_DEFAULT_MODBUS_ENABLED;
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT; check_flag(original_settings.modbus_enabled, settings.modbus_enabled, ChangeFlags::MODBUS);
settings.modbus_port = root["modbus_port"] | EMSESP_DEFAULT_MODBUS_PORT;
check_flag(original_settings.modbus_port, settings.modbus_port, ChangeFlags::MODBUS);
settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS; settings.modbus_max_clients = root["modbus_max_clients"] | EMSESP_DEFAULT_MODBUS_MAX_CLIENTS;
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT; check_flag(original_settings.modbus_max_clients, settings.modbus_max_clients, ChangeFlags::MODBUS);
settings.modbus_timeout = root["modbus_timeout"] | EMSESP_DEFAULT_MODBUS_TIMEOUT;
check_flag(original_settings.modbus_timeout, settings.modbus_timeout, ChangeFlags::MODBUS);
// //
// these may need mqtt restart to rebuild HA discovery topics // these may need mqtt restart to rebuild HA discovery topics
@@ -395,7 +399,11 @@ void WebSettingsService::onUpdate() {
Mqtt::reset_mqtt(); // reload MQTT, init HA etc Mqtt::reset_mqtt(); // reload MQTT, init HA etc
} }
if (WebSettings::has_flags(WebSettings::ChangeFlags::MODBUS)) {
EMSESP::system_.modbus_init();
}
WebSettings::reset_flags(); WebSettings::reset_flags();
EMSESP::system_.reset_unused_gpios();
} }
void WebSettingsService::begin() { void WebSettingsService::begin() {
@@ -537,7 +545,7 @@ void WebSettings::set_board_profile(WebSettings & settings) {
} }
// returns true if the value was changed // returns true if the value was changed
bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) { bool WebSettings::check_flag(int prev_v, int new_v, uint16_t flag) {
if (prev_v != new_v) { if (prev_v != new_v) {
add_flags(flag); add_flags(flag);
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
@@ -548,11 +556,11 @@ bool WebSettings::check_flag(int prev_v, int new_v, uint8_t flag) {
return false; return false;
} }
void WebSettings::add_flags(uint8_t flags) { void WebSettings::add_flags(uint16_t flags) {
flags_ |= flags; flags_ |= flags;
} }
bool WebSettings::has_flags(uint8_t flags) { bool WebSettings::has_flags(uint16_t flags) {
return (flags_ & flags) == flags; return (flags_ & flags) == flags;
} }
@@ -560,7 +568,7 @@ void WebSettings::reset_flags() {
flags_ = ChangeFlags::NONE; flags_ = ChangeFlags::NONE;
} }
uint8_t WebSettings::get_flags() { uint16_t WebSettings::get_flags() {
return flags_; return flags_;
} }

View File

@@ -128,7 +128,7 @@ class WebSettings {
static void read(WebSettings & settings, JsonObject root); static void read(WebSettings & settings, JsonObject root);
static StateUpdateResult update(JsonObject root, WebSettings & settings); static StateUpdateResult update(JsonObject root, WebSettings & settings);
enum ChangeFlags : uint8_t { enum ChangeFlags : uint16_t {
NONE = 0, NONE = 0,
UART = (1 << 0), // 1 - uart UART = (1 << 0), // 1 - uart
SYSLOG = (1 << 1), // 2 - syslog SYSLOG = (1 << 1), // 2 - syslog
@@ -138,19 +138,20 @@ class WebSettings {
LED = (1 << 5), // 32 - led LED = (1 << 5), // 32 - led
BUTTON = (1 << 6), // 64 - button BUTTON = (1 << 6), // 64 - button
MQTT = (1 << 7), // 128 - mqtt MQTT = (1 << 7), // 128 - mqtt
RESTART = 0xFF // 255 - restart request (all changes) MODBUS = (1 << 8), // 256 - modbus
RESTART = 0xFFFF // restart request (all changes)
}; };
static bool check_flag(int prev_v, int new_v, uint8_t flag); static bool check_flag(int prev_v, int new_v, uint16_t flag);
static void add_flags(uint8_t flags); static void add_flags(uint16_t flags);
static bool has_flags(uint8_t flags); static bool has_flags(uint16_t flags);
static void reset_flags(); static void reset_flags();
static uint8_t get_flags(); static uint16_t get_flags();
private: private:
static void set_board_profile(WebSettings & settings); static void set_board_profile(WebSettings & settings);
static uint8_t flags_; static uint16_t flags_;
}; };
class WebSettingsService : public StatefulService<WebSettings> { class WebSettingsService : public StatefulService<WebSettings> {