Merge pull request #2963 from MichaelDvP/core3

Core3 network fixes
This commit is contained in:
Proddy
2026-02-16 18:12:33 +01:00
committed by GitHub
14 changed files with 120 additions and 105 deletions

View File

@@ -8,10 +8,11 @@ For more details go to [emsesp.org](https://emsesp.org/).
- comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935) - comfortpoint for BC400 [#2935](https://github.com/emsesp/EMS-ESP32/issues/2935)
- customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784) - customize device brand [#2784](https://github.com/emsesp/EMS-ESP32/issues/2784)
- set model for ems-esp devices temperature, analog, etc. [#2958](https://github.com/emsesp/EMS-ESP32/discussions/2958)
## Fixed ## Fixed
- SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) - SRC climate creation [#2936](https://github.com/emsesp/EMS-ESP32/issues/2936) and [#2960](https://github.com/emsesp/EMS-ESP32/issues/2960)
## Changed ## Changed

View File

@@ -10,7 +10,6 @@ APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityM
, _reconfigureAp(false) , _reconfigureAp(false)
, _connected(0) { , _connected(0) {
addUpdateHandler([this] { reconfigureAP(); }, false); addUpdateHandler([this] { reconfigureAP(); }, false);
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
} }
void APSettingsService::begin() { void APSettingsService::begin() {
@@ -19,39 +18,27 @@ void APSettingsService::begin() {
// reconfigureAP(); // reconfigureAP();
} }
// wait 10 sec on STA disconnect before starting AP
void APSettingsService::WiFiEvent(WiFiEvent_t event) {
const uint8_t was_connected = _connected;
switch (event) {
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
_connected &= ~1U;
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
_connected &= ~2U;
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
_connected |= 1U;
break;
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP6:
_connected |= 2U;
break;
default:
return;
}
// wait 10 sec before starting AP
if (was_connected && !_connected) {
_lastManaged = uuid::get_uptime();
}
}
void APSettingsService::reconfigureAP() { void APSettingsService::reconfigureAP() {
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY; _lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
_reconfigureAp = true; _reconfigureAp = true;
} }
void APSettingsService::loop() { void APSettingsService::loop() {
const uint8_t was_connected = _connected;
if (WiFi.isConnected()) {
_connected |= 1U;
} else {
_connected &= ~1U;
}
if (ETH.connected()) {
_connected |= 2U;
} else {
_connected &= ~2U;
}
// wait 10 sec before starting AP
if (was_connected && !_connected) {
_lastManaged = uuid::get_uptime();
}
const unsigned long currentMillis = uuid::get_uptime(); const unsigned long currentMillis = uuid::get_uptime();
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) { if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
_lastManaged = currentMillis; _lastManaged = currentMillis;

View File

@@ -104,7 +104,6 @@ class APSettingsService : public StatefulService<APSettings> {
void startAP(); void startAP();
void stopAP(); void stopAP();
void handleDNS(); void handleDNS();
void WiFiEvent(WiFiEvent_t event);
}; };
#endif #endif

View File

@@ -84,4 +84,5 @@ void ESP32React::loop() {
_networkSettingsService.loop(); _networkSettingsService.loop();
_apSettingsService.loop(); _apSettingsService.loop();
_mqttSettingsService.loop(); _mqttSettingsService.loop();
_ntpSettingsService.loop();
} }

View File

@@ -9,7 +9,6 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur
, _disconnectedAt(0) , _disconnectedAt(0)
, _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED) , _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED)
, _mqttClient(nullptr) { , _mqttClient(nullptr) {
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
addUpdateHandler([this] { onConfigUpdated(); }, false); addUpdateHandler([this] { onConfigUpdated(); }, false);
} }
@@ -29,6 +28,7 @@ MqttSettingsService::~MqttSettingsService() {
void MqttSettingsService::begin() { void MqttSettingsService::begin() {
_fsPersistence.readFromFS(); _fsPersistence.readFromFS();
startClient(); startClient();
_reconfigureMqtt = true;
} }
void MqttSettingsService::startClient() { void MqttSettingsService::startClient() {
@@ -79,6 +79,10 @@ void MqttSettingsService::startClient() {
} }
void MqttSettingsService::loop() { void MqttSettingsService::loop() {
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) {
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
_mqttClient->disconnect(true);
}
if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { if (_reconfigureMqtt || (_disconnectedAt && static_cast<uint32_t>(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) {
// reconfigure MQTT client // reconfigure MQTT client
_disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime(); _disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime();
@@ -142,28 +146,6 @@ void MqttSettingsService::onConfigUpdated() {
emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings
} }
void MqttSettingsService::WiFiEvent(WiFiEvent_t event) {
switch (event) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP6:
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
if (_state.enabled && !_mqttClient->connected()) {
onConfigUpdated();
}
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
case ARDUINO_EVENT_ETH_DISCONNECTED:
if (_state.enabled) {
_mqttClient->disconnect(true);
}
break;
default:
break;
}
}
bool MqttSettingsService::configureMqtt() { bool MqttSettingsService::configureMqtt() {
// disconnect if already connected // disconnect if already connected
if (_mqttClient->connected()) { if (_mqttClient->connected()) {
@@ -316,6 +298,10 @@ StateUpdateResult MqttSettings::update(JsonObject root, MqttSettings & settings)
changed = true; changed = true;
} }
if (newSettings.ha_number_mode != settings.ha_number_mode) {
changed = true;
}
if (newSettings.entity_format != settings.entity_format) { if (newSettings.entity_format != settings.entity_format) {
changed = true; changed = true;
} }

View File

@@ -134,7 +134,6 @@ class MqttSettingsService : public StatefulService<MqttSettings> {
// the MQTT client instance // the MQTT client instance
MqttClient * _mqttClient; MqttClient * _mqttClient;
void WiFiEvent(WiFiEvent_t event);
void onMqttConnect(bool sessionPresent); void onMqttConnect(bool sessionPresent);
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason); void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
void void

View File

@@ -11,7 +11,6 @@ NTPSettingsService::NTPSettingsService(AsyncWebServer * server, FS * fs, Securit
configureTime(request, json); configureTime(request, json);
}); });
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event); });
addUpdateHandler([this] { configureNTP(); }, false); addUpdateHandler([this] { configureNTP(); }, false);
} }
@@ -20,28 +19,11 @@ void NTPSettingsService::begin() {
configureNTP(); configureNTP();
} }
// handles both WiFI and Ethernet void NTPSettingsService::loop() {
void NTPSettingsService::WiFiEvent(WiFiEvent_t event) { if (_connected != emsesp::EMSESP::system_.network_connected()) {
switch (event) { _connected = emsesp::EMSESP::system_.network_connected();
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
case ARDUINO_EVENT_ETH_DISCONNECTED:
if (_connected && emsesp::EMSESP::system_.ntp_connected()) {
emsesp::EMSESP::logger().info("WiFi connection dropped, stopping NTP");
_connected = false;
configureNTP(); configureNTP();
} }
break;
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
case ARDUINO_EVENT_ETH_GOT_IP:
// emsesp::EMSESP::logger().info("Got IP address, starting NTP synchronization");
_connected = true;
configureNTP();
break;
default:
break;
}
} }
// https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm // https://werner.rothschopf.net/microcontroller/202103_arduino_esp32_ntp_en.htm
@@ -55,8 +37,10 @@ void NTPSettingsService::configureNTP() {
} else { } else {
setenv("TZ", _state.tzFormat.c_str(), 1); setenv("TZ", _state.tzFormat.c_str(), 1);
tzset(); tzset();
if (esp_sntp_enabled()) {
esp_sntp_stop(); esp_sntp_stop();
} }
}
} }
void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) { void NTPSettingsService::configureTime(AsyncWebServerRequest * request, JsonVariant json) {

View File

@@ -44,6 +44,7 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager); NTPSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
void begin(); void begin();
void loop();
static void ntp_received(struct timeval * tv); static void ntp_received(struct timeval * tv);
private: private:
@@ -51,7 +52,6 @@ class NTPSettingsService : public StatefulService<NTPSettings> {
FSPersistence<NTPSettings> _fsPersistence; FSPersistence<NTPSettings> _fsPersistence;
volatile bool _connected; volatile bool _connected;
void WiFiEvent(WiFiEvent_t event);
void configureNTP(); void configureNTP();
void configureTime(AsyncWebServerRequest * request, JsonVariant json); void configureTime(AsyncWebServerRequest * request, JsonVariant json);
}; };

View File

@@ -9,7 +9,7 @@ NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs,
, _stopping(false) { , _stopping(false) {
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false); addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
// Eth is also bound to the WifiGeneric event handler // Eth is also bound to the WifiGeneric event handler
WiFi.onEvent([this](WiFiEvent_t event, WiFiEventInfo_t info) { WiFiEvent(event, info); }); // Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); });
} }
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) { static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
@@ -62,14 +62,62 @@ void NetworkSettingsService::loop() {
_lastConnectionAttempt = currentMillis; _lastConnectionAttempt = currentMillis;
manageSTA(); manageSTA();
} }
static uint8_t connect = 0;
enum uint8_t { CONNECT_IDLE = 0, CONNECT_WAIT_ETH, CONNECT_ETH_ACTIVE, CONNECT_WIFI_ACTIVE };
switch (connect) {
default:
connect = CONNECT_IDLE;
break;
case CONNECT_IDLE:
if (ETH.started() && _state.ssid.length() == 0) {
emsesp::EMSESP::logger().info("ETH started");
connect = CONNECT_WAIT_ETH;
ETH.enableIPv6(true);
if (_state.staticIPConfig) {
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
}
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
}
if (WiFi.isConnected()) {
emsesp::EMSESP::logger().info("Wifi connected");
connect = CONNECT_WIFI_ACTIVE;
if (_state.tx_power == 0) {
setWiFiPowerOnRSSI();
}
mDNS_start();
}
break;
case CONNECT_WAIT_ETH:
if (ETH.connected()) {
emsesp::EMSESP::logger().info("ETH connected");
connect = CONNECT_ETH_ACTIVE;
emsesp::EMSESP::system_.ethernet_connected(true);
mDNS_start();
}
break;
case CONNECT_ETH_ACTIVE:
if (!ETH.connected()) {
emsesp::EMSESP::logger().info("ETH disconnected");
emsesp::EMSESP::system_.ethernet_connected(false);
connect = CONNECT_IDLE;
}
break;
case CONNECT_WIFI_ACTIVE:
if (!WiFi.isConnected()) {
emsesp::EMSESP::logger().info("WiFi disconnected");
connect = CONNECT_IDLE;
if (_stopping) {
_lastConnectionAttempt = 0;
_stopping = false;
}
}
break;
}
} }
void NetworkSettingsService::manageSTA() { void NetworkSettingsService::manageSTA() {
// Abort if already connected, or if we have no SSID // Abort if already connected, or if we have no SSID
if (WiFi.isConnected() || _state.ssid.length() == 0) { if (WiFi.isConnected() || _state.ssid.length() == 0) {
if (_state.ssid.length() == 0) {
ETH.enableIPv6(true);
}
return; return;
} }
@@ -289,7 +337,7 @@ const char * NetworkSettingsService::disconnectReason(uint8_t code) {
} }
// handles both WiFI and Ethernet // handles both WiFI and Ethernet
void NetworkSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) {
#ifndef EMSESP_STANDALONE #ifndef EMSESP_STANDALONE
switch (event) { switch (event) {

View File

@@ -107,7 +107,7 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
volatile uint16_t connectcount_ = 0; // number of wifi reconnects volatile uint16_t connectcount_ = 0; // number of wifi reconnects
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info);
void mDNS_start() const; void mDNS_start() const;
const char * disconnectReason(uint8_t code); const char * disconnectReason(uint8_t code);
void reconfigureWiFiConnection(); void reconfigureWiFiConnection();

View File

@@ -2135,7 +2135,7 @@ void EMSdevice::mqtt_ha_entity_config_create() {
if (needs_update) { if (needs_update) {
const char * const ** mode_options = nullptr; const char * const ** mode_options = nullptr;
for (auto & d : devicevalues_) { for (const auto & d : devicevalues_) {
// make sure mode in same circuit is DeviceValueType::ENUM // make sure mode in same circuit is DeviceValueType::ENUM
if ((d.tag == dv.tag) && (d.type == DeviceValueType::ENUM) && !strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) { if ((d.tag == dv.tag) && (d.type == DeviceValueType::ENUM) && !strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) {
// get options // get options
@@ -2167,19 +2167,25 @@ void EMSdevice::mqtt_ha_entity_config_create() {
} }
// SRC thermostats mapped to connect/src1/... always contains mode, seltemp, currtemp // SRC thermostats mapped to connect/src1/... always contains mode, seltemp, currtemp
if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(mode)[0])) { if (dv.tag >= DeviceValueTAG::TAG_SRC1 && dv.tag <= DeviceValueTAG::TAG_SRC16 && !strcmp(dv.short_name, FL_(seltemp)[0])) {
// add icon if we have one // add modes and icon if we have one
const char * icon = nullptr; const char * icon = nullptr;
for (auto & d : devicevalues_) { const char * const ** mode_options = nullptr;
if (d.tag == dv.tag && !strcmp(d.short_name, FL_(icon)[0]) && (dv.type == DeviceValueType::ENUM)) { for (const auto & d : devicevalues_) {
if ((d.tag != dv.tag) || (d.type != DeviceValueType::ENUM)) {
continue;
}
if (!strcmp(d.short_name, FL_(mode)[0]) && (d.options_size > 0)) {
mode_options = d.options;
}
if (!strcmp(d.short_name, FL_(icon)[0])) {
uint8_t val = *(uint8_t *)(d.value_p); uint8_t val = *(uint8_t *)(d.value_p);
if (val != 0 && val < d.options_size) { if (val != 0 && val < d.options_size) {
icon = d.options[val][0]; icon = d.options[val][0];
} }
break;
} }
} }
Mqtt::publish_ha_climate_config(dv, true, dv.options, false, icon); Mqtt::publish_ha_climate_config(dv, true, mode_options, false, icon);
count++; count++;
} }

View File

@@ -1545,9 +1545,7 @@ void Mqtt::add_ha_dev_section(JsonObject doc, const char * name, const bool crea
// add mf (manufacturer/brand), mdl (model), sw (software version) and via_device // add mf (manufacturer/brand), mdl (model), sw (software version) and via_device
dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP"; dev_json["mf"] = brand != nullptr ? brand : "EMS-ESP";
if (model != nullptr) { dev_json["mdl"] = model != nullptr ? model : "EMS-ESP";
dev_json["mdl"] = model;
}
dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION); dev_json["sw"] = version != nullptr ? version : "v" + std::string(EMSESP_APP_VERSION);
dev_json["via_device"] = Mqtt::basename(); dev_json["via_device"] = Mqtt::basename();
} }

View File

@@ -129,15 +129,20 @@ void Connect::process_roomThermostat(std::shared_ptr<const Telegram> telegram) {
} }
has_update(telegram, rc->temp_, 0); has_update(telegram, rc->temp_, 0);
has_update(telegram, rc->humidity_, 2); // could show -3 if not set has_update(telegram, rc->humidity_, 2); // could show -3 if not set
// make sure we have read mode and icon, needed for ha climate
if (!Mqtt::ha_enabled() || (Helpers::hasValue(rc->mode_) && Helpers::hasValue(rc->icon_))) {
has_update(telegram, rc->seltemp_, 3); has_update(telegram, rc->seltemp_, 3);
}
// calculate dew temperature // calculate dew temperature
if (rc->humidity_ >= 0 && rc->humidity_ <= 100) {
const float k2 = 17.62; const float k2 = 17.62;
const float k3 = 243.12; const float k3 = 243.12;
const float t = (float)rc->temp_ / 10; const float t = (float)rc->temp_ / 10;
const float h = (float)rc->humidity_ / 100; const float h = (float)rc->humidity_ / 100;
int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h))); int16_t dt = (10 * k3 * (((k2 * t) / (k3 + t)) + log(h)) / (((k2 * k3) / (k3 + t)) - log(h)));
has_update(rc->dewtemp_, dt); has_update(rc->dewtemp_, dt);
}
} }
// gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 // icon in offset 0 // gateway(0x48) W gateway(0x50), ?(0x0B42), data: 01 // icon in offset 0
@@ -221,8 +226,9 @@ bool Connect::set_seltemp(const char * value, const int8_t id) {
} }
float v; float v;
if (Helpers::value2float(value, v)) { if (Helpers::value2float(value, v)) {
// write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); // depends on mode, auto (2 for enum_mode2, 0 for enum_mode8) set in offset 1
write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2)); write_command(0xBB5 + rc->room(), rc->mode_ == 2 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
// write_command(0xBB5 + rc->room(), rc->mode_ == 0 ? 1 : 3, v == -1 ? 0xFF : uint8_t(v * 2));
return true; return true;
} }
return false; return false;

View File

@@ -1 +1 @@
#define EMSESP_APP_VERSION "3.8.2-dev.5" #define EMSESP_APP_VERSION "3.8.2-dev.6"