diff --git a/interface/src/framework/mqtt/MqttSettingsForm.tsx b/interface/src/framework/mqtt/MqttSettingsForm.tsx index ddcd28fcf..d9e49ab95 100644 --- a/interface/src/framework/mqtt/MqttSettingsForm.tsx +++ b/interface/src/framework/mqtt/MqttSettingsForm.tsx @@ -168,6 +168,19 @@ const MqttSettingsForm: FC = () => { 2 + {data.rootCA !== undefined && ( + + + + )} { return 'WPA2 Enterprise'; case WiFiEncryptionType.WIFI_AUTH_OPEN: return 'None'; + case WiFiEncryptionType.WIFI_AUTH_WPA3_PSK: + return 'WPA3'; + case WiFiEncryptionType.WIFI_AUTH_WPA2_WPA3_PSK: + return 'WPA2/WPA3'; default: - return 'Unknown'; + return 'Unknown: ' + encryption_type; } }; diff --git a/interface/src/i18n/de/index.ts b/interface/src/i18n/de/index.ts index 3acac78c8..dfbab3705 100644 --- a/interface/src/i18n/de/index.ts +++ b/interface/src/i18n/de/index.ts @@ -45,9 +45,9 @@ const de: Translation = { CHANGE_VALUE: 'Wert ändern', CANCEL: 'Abbrechen', RESET: 'Zurücksetzen', - APPLY_CHANGES: 'Apply Changes ({0})', // TODO translate - UPDATE: 'Update', // TODO translate - EXECUTE: 'Execute', // TODO translate + APPLY_CHANGES: 'Änderungen anwenden ({0})', + UPDATE: 'Update', + EXECUTE: 'Ausführen', REMOVE: 'Entfernen', PROBLEM_UPDATING: 'Problem beim Aktualisieren', PROBLEM_LOADING: 'Problem beim Laden', @@ -180,7 +180,7 @@ const de: Translation = { LOG_OF: '{0} Log', STATUS_OF: '{0} Status', UPLOAD_DOWNLOAD: 'Hoch-/Herunterladen', - VERSION_ON: 'You are currently on', // TODO translate + VERSION_ON: 'Sie verwenden derzeit', SYSTEM_APPLY_FIRMWARE: 'um die neue Firmware anzuwenden', CLOSE: 'Schließen', USE: 'Verwenden Sie', @@ -240,7 +240,7 @@ const de: Translation = { MQTT_PUBLISH_TEXT_2: 'Veröffentliche als Kommando-Topic (ioBroker)', MQTT_PUBLISH_TEXT_3: 'Aktiviere `MQTT Discovery`', MQTT_PUBLISH_TEXT_4: 'Prefix für die `Discovery`-Topics', - MQTT_PUBLISH_TEXT_5: 'Discovery type', // TODO translate + MQTT_PUBLISH_TEXT_5: 'Discovery Typ', MQTT_PUBLISH_INTERVALS: 'Veröffentlichungs-Intervalle', MQTT_INT_BOILER: 'Boiler und Wärmepumpen', MQTT_INT_THERMOSTATS: 'Thermostate', @@ -282,7 +282,7 @@ const de: Translation = { SCAN_AGAIN: 'Erneute Suche', NETWORK_SCANNER: 'Netzwerk Suche', NETWORK_NO_WIFI: 'Keine WiFi Netzwerke gefunden', - NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren', + NETWORK_BLANK_SSID: 'Freilassen um WiFi zu deaktivieren und ETH zu aktivieren', TX_POWER: 'Tx Leistung', HOSTNAME: 'Hostname', NETWORK_DISABLE_SLEEP: 'Deaktiviere WiFi Schlafmodus', @@ -319,10 +319,11 @@ const de: Translation = { SCHEDULE_TIMER_3: 'jede Stunde', CUSTOM_ENTITIES: 'Individuelle Entitäten', ENTITIES_HELP_1: 'Abfrage von Werten auf dem EMS-Bus', - ENTITIES_UPDATED: 'Entities Updated', // TODO translate + ENTITIES_UPDATED: 'Entitäten gespeichert', WRITEABLE: 'Schreibbar', - SHOWING: 'Showing', // TODO translate - SEARCH: 'Search' // TODO translate + SHOWING: 'Anzeigen von', + SEARCH: 'Suche', + CERT: 'TSL Zertifikat (Freilassen um TSL zu deaktivieren)' }; export default de; diff --git a/interface/src/i18n/en/index.ts b/interface/src/i18n/en/index.ts index 83d123376..4a2486a55 100644 --- a/interface/src/i18n/en/index.ts +++ b/interface/src/i18n/en/index.ts @@ -282,7 +282,7 @@ const en: Translation = { SCAN_AGAIN: 'Scan again', NETWORK_SCANNER: 'Network Scanner', NETWORK_NO_WIFI: 'No WiFi networks found', - NETWORK_BLANK_SSID: 'leave blank to disable WiFi', + NETWORK_BLANK_SSID: 'leave blank to disable WiFi and enable ETH', TX_POWER: 'Tx Power', HOSTNAME: 'Hostname', NETWORK_DISABLE_SLEEP: 'Disable WiFi Sleep Mode', @@ -322,8 +322,8 @@ const en: Translation = { ENTITIES_UPDATED: 'Entities Updated', WRITEABLE: 'Writeable', SHOWING: 'Showing', - SEARCH: 'Search' - + SEARCH: 'Search', + CERT: 'TSL root certificate (leave blank to disable TSL)' }; export default en; diff --git a/interface/src/i18n/fr/index.ts b/interface/src/i18n/fr/index.ts index 390407573..965803614 100644 --- a/interface/src/i18n/fr/index.ts +++ b/interface/src/i18n/fr/index.ts @@ -282,7 +282,7 @@ const fr: Translation = { SCAN_AGAIN: 'Rescanner', NETWORK_SCANNER: 'Scan réseau', NETWORK_NO_WIFI: 'Pas de réseau WiFi trouvé', - NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', + NETWORK_BLANK_SSID: 'laisser vide pour désactiver le WiFi', // and enable ETH // TODO translate TX_POWER: 'Puissance Tx', HOSTNAME: 'Nom d\'hôte', NETWORK_DISABLE_SLEEP: 'Désactiver le mode veille du WiFi', @@ -322,7 +322,8 @@ const fr: Translation = { ENTITIES_UPDATED: 'Entities Updated', // TODO translate WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate - SEARCH: 'Search' // TODO translate + SEARCH: 'Search', // TODO translate + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default fr; diff --git a/interface/src/i18n/it/index.ts b/interface/src/i18n/it/index.ts index c9719e10e..f122a8fec 100644 --- a/interface/src/i18n/it/index.ts +++ b/interface/src/i18n/it/index.ts @@ -324,8 +324,8 @@ const it: Translation = { ENTITIES_UPDATED: 'Entità aggiornate', WRITEABLE: 'Scrivibile', SHOWING: 'Visualizza', - SEARCH: 'Ricerca' - + SEARCH: 'Ricerca', + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default it; diff --git a/interface/src/i18n/nl/index.ts b/interface/src/i18n/nl/index.ts index 80957c9e0..1464dfcb5 100644 --- a/interface/src/i18n/nl/index.ts +++ b/interface/src/i18n/nl/index.ts @@ -282,7 +282,7 @@ const nl: Translation = { SCAN_AGAIN: 'Opnieuw scannen', NETWORK_SCANNER: 'Netwerk Scanner', NETWORK_NO_WIFI: 'Geen WiFi networken gevonden', - NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen', + NETWORK_BLANK_SSID: 'laat leeg om WiFi uit te schakelen', // and enable ETH // TODO translate TX_POWER: 'Tx Vermogen', HOSTNAME: 'Hostname', NETWORK_DISABLE_SLEEP: 'WiFi Sleep Mode uitzetten', @@ -322,7 +322,8 @@ const nl: Translation = { ENTITIES_UPDATED: 'Entiteiten bijgewerkt', WRITEABLE: 'Beschrijfbare', SHOWING: 'Tonen', - SEARCH: 'Zoek' + SEARCH: 'Zoek', + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default nl; diff --git a/interface/src/i18n/no/index.ts b/interface/src/i18n/no/index.ts index 21bc1346a..dcec7796c 100644 --- a/interface/src/i18n/no/index.ts +++ b/interface/src/i18n/no/index.ts @@ -282,7 +282,7 @@ const no: Translation = { SCAN_AGAIN: 'Søk igjen', NETWORK_SCANNER: 'Nettverk Scanner', NETWORK_NO_WIFI: 'Ingen trådløse nett funnet', - NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', + NETWORK_BLANK_SSID: 'la feltet være blankt for å deaktivisere trådløst nettverk', // and enable ETH // TODO translate TX_POWER: 'Tx Effekt', HOSTNAME: 'Hostname', NETWORK_DISABLE_SLEEP: 'Hindre at trådløst nettverk går i Sleep Mode', @@ -322,8 +322,8 @@ const no: Translation = { ENTITIES_UPDATED: 'Entities Updated', // TODO translate WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate - SEARCH: 'Search' // TODO translate - + SEARCH: 'Search', // TODO translate + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default no; diff --git a/interface/src/i18n/pl/index.ts b/interface/src/i18n/pl/index.ts index 5d46e4c4b..2073acb1f 100644 --- a/interface/src/i18n/pl/index.ts +++ b/interface/src/i18n/pl/index.ts @@ -282,7 +282,7 @@ const pl: BaseTranslation = { SCAN_AGAIN: 'Skanuj ponownie', NETWORK_SCANNER: 'Skaner sieci WiFi', NETWORK_NO_WIFI: 'Brak sieci WiFi w zasięgu', - NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi', + NETWORK_BLANK_SSID: 'pozostaw puste aby wyłączyć WiFi', // and enable ETH // TODO translate TX_POWER: 'Moc nadawania', HOSTNAME: 'Nazwa w sieci', NETWORK_DISABLE_SLEEP: 'Wyłącz tryb uśpienia WiFi', @@ -322,8 +322,8 @@ const pl: BaseTranslation = { ENTITIES_UPDATED: 'Niestandardowe encje zostały uaktualnione.', WRITEABLE: 'zapisywalna', SHOWING: 'Wyświetlane', - SEARCH: 'Szukaj' - + SEARCH: 'Szukaj', + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default pl; diff --git a/interface/src/i18n/sv/index.ts b/interface/src/i18n/sv/index.ts index e34ddba92..2f6e27381 100644 --- a/interface/src/i18n/sv/index.ts +++ b/interface/src/i18n/sv/index.ts @@ -282,7 +282,7 @@ const sv: Translation = { SCAN_AGAIN: 'Sök igen', NETWORK_SCANNER: 'Hittade nätverk', NETWORK_NO_WIFI: 'Inga WiFi-nätverk hittades', - NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', + NETWORK_BLANK_SSID: 'lämna blankt för att inaktivera WiFi', // and enable ETH // TODO translate TX_POWER: 'Tx Effekt', HOSTNAME: 'Värdnamn', NETWORK_DISABLE_SLEEP: 'Inaktivera sömnläge', @@ -322,8 +322,8 @@ const sv: Translation = { ENTITIES_UPDATED: 'Entities Updated', // TODO translate WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate - SEARCH: 'Search' // TODO translate - + SEARCH: 'Search', // TODO translate + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default sv; diff --git a/interface/src/i18n/tr/index.ts b/interface/src/i18n/tr/index.ts index 44a5dab43..93055252f 100644 --- a/interface/src/i18n/tr/index.ts +++ b/interface/src/i18n/tr/index.ts @@ -282,7 +282,7 @@ const tr: Translation = { SCAN_AGAIN: 'Tekrar tara', NETWORK_SCANNER: 'Ağ Tarayıcısı', NETWORK_NO_WIFI: 'Hiçbir Kablosuz Ağ bulunamadı', - NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın', + NETWORK_BLANK_SSID: 'Kablosuz ağı devre dışı bırakmak için boş bırakın', // and enable ETH // TODO translate TX_POWER: 'Aktarım gücü', HOSTNAME: 'Ana Makine Adı', NETWORK_DISABLE_SLEEP: 'Kablosuz uyku modunu devre dışına al', @@ -322,8 +322,8 @@ const tr: Translation = { ENTITIES_UPDATED: 'Entities Updated', // TODO translate WRITEABLE: 'Writeable', // TODO translate SHOWING: 'Showing', // TODO translate - SEARCH: 'Search' // TODO translate - + SEARCH: 'Search', // TODO translate + CERT: 'TSL root certificate (leave blank to disable TSL)' // TODO translate }; export default tr; diff --git a/interface/src/types/mqtt.ts b/interface/src/types/mqtt.ts index f82fa6c26..32eb5ea66 100644 --- a/interface/src/types/mqtt.ts +++ b/interface/src/types/mqtt.ts @@ -24,6 +24,7 @@ export interface MqttSettings { host: string; port: number; base: string; + rootCA?: string; username: string; password: string; client_id: string; diff --git a/interface/src/types/network.ts b/interface/src/types/network.ts index a0de253f0..ec93ad757 100644 --- a/interface/src/types/network.ts +++ b/interface/src/types/network.ts @@ -15,7 +15,9 @@ export enum WiFiEncryptionType { WIFI_AUTH_WPA_PSK = 2, WIFI_AUTH_WPA2_PSK = 3, WIFI_AUTH_WPA_WPA2_PSK = 4, - WIFI_AUTH_WPA2_ENTERPRISE = 5 + WIFI_AUTH_WPA2_ENTERPRISE = 5, + WIFI_AUTH_WPA3_PSK = 6, + WIFI_AUTH_WPA2_WPA3_PSK = 7 } export interface NetworkStatus { diff --git a/lib/framework/ESP8266React.h b/lib/framework/ESP8266React.h index 32ca0f55c..e44397c9e 100644 --- a/lib/framework/ESP8266React.h +++ b/lib/framework/ESP8266React.h @@ -59,10 +59,17 @@ class ESP8266React { return &_mqttSettingsService; } - espMqttClient * getMqttClient() { + MqttClient * getMqttClient() { return _mqttSettingsService.getMqttClient(); } + void setWill(const char * will_topic) { + _mqttSettingsService.setWill(will_topic); + } + void onMessage(espMqttClientTypes::OnMessageCallback callback) { + _mqttSettingsService.onMessage(callback); + } + void factoryReset() { _factoryResetService.factoryReset(); } diff --git a/lib/framework/MqttSettingsService.cpp b/lib/framework/MqttSettingsService.cpp index 59b5c0f43..1135525b7 100644 --- a/lib/framework/MqttSettingsService.cpp +++ b/lib/framework/MqttSettingsService.cpp @@ -2,7 +2,7 @@ #include "../../src/emsesp_stub.hpp" // proddy added -using namespace std::placeholders; // for `_1` etc +using namespace std::placeholders; // for `_1` etc /** * Retains a copy of the cstr provided in the pointer provided using dynamic allocation. @@ -34,10 +34,8 @@ MqttSettingsService::MqttSettingsService(AsyncWebServer * server, FS * fs, Secur , _reconfigureMqtt(false) , _disconnectedAt(0) , _disconnectReason(espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED) - , _mqttClient(espMqttClientTypes::UseInternalTask::NO) { + , _mqttClient(nullptr) { WiFi.onEvent(std::bind(&MqttSettingsService::WiFiEvent, this, _1, _2)); - _mqttClient.onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1)); - _mqttClient.onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1)); addUpdateHandler([&](const String & originId) { onConfigUpdated(); }, false); } @@ -46,18 +44,46 @@ MqttSettingsService::~MqttSettingsService() { void MqttSettingsService::begin() { _fsPersistence.readFromFS(); + startClient(); +} + +void MqttSettingsService::startClient() { + static bool isSecure = false; + if (_mqttClient != nullptr) { + // do we need to change the client? + if ((isSecure && _state.rootCA.length() > 0) || (!isSecure && _state.rootCA.length() == 0)) { + return; + } + delete _mqttClient; + } +#if CONFIG_IDF_TARGET_ESP32S3 + if (_state.rootCA.length() > 0) { + isSecure = true; + _mqttClient = static_cast(new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO)); + if (_state.rootCA == "insecure") { + static_cast(_mqttClient)->setInsecure(); + } else { + String certificate = "-----BEGIN CERTIFICATE-----\n" + _state.rootCA + "\n-----END CERTIFICATE-----\n"; + static_cast(_mqttClient)->setCACert(retainCstr(certificate.c_str(), &_retainedRootCA)); + } + static_cast(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1)); + static_cast(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1)); + return; + } +#endif + isSecure = false; + _mqttClient = static_cast(new espMqttClient(espMqttClientTypes::UseInternalTask::NO)); + static_cast(_mqttClient)->onConnect(std::bind(&MqttSettingsService::onMqttConnect, this, _1)); + static_cast(_mqttClient)->onDisconnect(std::bind(&MqttSettingsService::onMqttDisconnect, this, _1)); } void MqttSettingsService::loop() { if (_reconfigureMqtt || (_disconnectedAt && (uint32_t)(uuid::get_uptime() - _disconnectedAt) >= MQTT_RECONNECTION_DELAY)) { // reconfigure MQTT client - _disconnectedAt = uuid::get_uptime(); - if (configureMqtt()) { - _disconnectedAt = 0; - } + _disconnectedAt = configureMqtt() ? 0 : uuid::get_uptime(); _reconfigureMqtt = false; } - _mqttClient.loop(); + _mqttClient->loop(); } bool MqttSettingsService::isEnabled() { @@ -65,19 +91,39 @@ bool MqttSettingsService::isEnabled() { } bool MqttSettingsService::isConnected() { - return _mqttClient.connected(); + return _mqttClient->connected(); } const char * MqttSettingsService::getClientId() { - return _mqttClient.getClientId(); + return _mqttClient->getClientId(); +} + +void MqttSettingsService::setWill(const char * topic) { +#if CONFIG_IDF_TARGET_ESP32S3 + if (_state.rootCA.length() > 0) { + static_cast(_mqttClient)->setWill(topic, 1, true, "offline"); + return; + } +#endif + static_cast(_mqttClient)->setWill(topic, 1, true, "offline"); +} + +void MqttSettingsService::onMessage(espMqttClientTypes::OnMessageCallback callback) { +#if CONFIG_IDF_TARGET_ESP32S3 + if (_state.rootCA.length() > 0) { + static_cast(_mqttClient)->onMessage(callback); + return; + } +#endif + static_cast(_mqttClient)->onMessage(callback); } espMqttClientTypes::DisconnectReason MqttSettingsService::getDisconnectReason() { return _disconnectReason; } -espMqttClient * MqttSettingsService::getMqttClient() { - return &_mqttClient; +MqttClient * MqttSettingsService::getMqttClient() { + return _mqttClient; } void MqttSettingsService::onMqttConnect(bool sessionPresent) { @@ -87,7 +133,6 @@ void MqttSettingsService::onMqttConnect(bool sessionPresent) { } void MqttSettingsService::onMqttDisconnect(espMqttClientTypes::DisconnectReason reason) { - // emsesp::EMSESP::logger().info("Disconnected from MQTT reason: %d", (uint8_t)reason); _disconnectReason = reason; if (!_disconnectedAt) { _disconnectedAt = uuid::get_uptime(); @@ -100,6 +145,7 @@ void MqttSettingsService::onConfigUpdated() { _disconnectedAt = 0; // added by proddy + startClient(); emsesp::EMSESP::mqtt_.start(); // reload EMS-ESP MQTT settings } @@ -110,15 +156,13 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { case ARDUINO_EVENT_ETH_GOT_IP6: case ARDUINO_EVENT_WIFI_STA_GOT_IP6: if (_state.enabled) { - // emsesp::EMSESP::logger().info("IPv4 Network connection found, starting MQTT client"); onConfigUpdated(); } break; case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: case ARDUINO_EVENT_ETH_DISCONNECTED: if (_state.enabled) { - // emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client"); - _mqttClient.disconnect(true); + _mqttClient->disconnect(true); } break; @@ -129,28 +173,52 @@ void MqttSettingsService::WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) { bool MqttSettingsService::configureMqtt() { // disconnect if connected - _mqttClient.disconnect(true); + if (_mqttClient->connected()) { + emsesp::EMSESP::logger().info("Disconneting to configure"); + _mqttClient->disconnect(true); + } // only connect if WiFi is connected and MQTT is enabled if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) { - // emsesp::EMSESP::logger().info("Configuring MQTT client"); - _mqttClient.setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port); - if (_state.username.length() > 0) { - _mqttClient.setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), - retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword)); - } else { - _mqttClient.setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword)); + // if (_state.enabled && !_state.host.isEmpty()) { + _reconfigureMqtt = false; +#if CONFIG_IDF_TARGET_ESP32S3 + if (_state.rootCA.length() > 0) { + // emsesp::EMSESP::logger().info("Start secure MQTT with rootCA"); + static_cast(_mqttClient)->setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port); + if (_state.username.length() > 0) { + static_cast(_mqttClient) + ->setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), + retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword)); + } else { + static_cast(_mqttClient)->setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword)); + } + static_cast(_mqttClient)->setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId)); + static_cast(_mqttClient)->setKeepAlive(_state.keepAlive); + static_cast(_mqttClient)->setCleanSession(_state.cleanSession); + return _mqttClient->connect(); } - _mqttClient.setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId)); - _mqttClient.setKeepAlive(_state.keepAlive); - _mqttClient.setCleanSession(_state.cleanSession); - return _mqttClient.connect(); - // } else { - // emsesp::EMSESP::logger().info("Error configuring MQTT client"); +#endif + // emsesp::EMSESP::logger().info("Configuring MQTT client"); + static_cast(_mqttClient)->setServer(retainCstr(_state.host.c_str(), &_retainedHost), _state.port); + if (_state.username.length() > 0) { + static_cast(_mqttClient) + ->setCredentials(retainCstr(_state.username.c_str(), &_retainedUsername), + retainCstr(_state.password.length() > 0 ? _state.password.c_str() : nullptr, &_retainedPassword)); + } else { + static_cast(_mqttClient)->setCredentials(retainCstr(nullptr, &_retainedUsername), retainCstr(nullptr, &_retainedPassword)); + } + static_cast(_mqttClient)->setClientId(retainCstr(_state.clientId.c_str(), &_retainedClientId)); + static_cast(_mqttClient)->setKeepAlive(_state.keepAlive); + static_cast(_mqttClient)->setCleanSession(_state.cleanSession); + return _mqttClient->connect(); } return false; } void MqttSettings::read(MqttSettings & settings, JsonObject & root) { +#if CONFIG_IDF_TARGET_ESP32S3 + root["rootCA"] = settings.rootCA; +#endif root["enabled"] = settings.enabled; root["host"] = settings.host; root["port"] = settings.port; @@ -185,6 +253,9 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting MqttSettings newSettings = {}; bool changed = false; +#if CONFIG_IDF_TARGET_ESP32S3 + newSettings.rootCA = root["rootCA"] | ""; +#endif newSettings.enabled = root["enabled"] | FACTORY_MQTT_ENABLED; newSettings.host = root["host"] | FACTORY_MQTT_HOST; newSettings.port = root["port"] | FACTORY_MQTT_PORT; @@ -300,6 +371,20 @@ StateUpdateResult MqttSettings::update(JsonObject & root, MqttSettings & setting emsesp::EMSESP::mqtt_.set_publish_time_heartbeat(newSettings.publish_time_heartbeat); } +#if CONFIG_IDF_TARGET_ESP32S3 + // strip down to certificate only + newSettings.rootCA.replace("\r", ""); + newSettings.rootCA.replace("\n", ""); + newSettings.rootCA.replace("-----BEGIN CERTIFICATE-----", ""); + newSettings.rootCA.replace("-----END CERTIFICATE-----", ""); + newSettings.rootCA.replace(" ", ""); + if (newSettings.rootCA.length() == 0 && newSettings.port > 8800) { + newSettings.rootCA = "insecure"; + } + if (newSettings.rootCA != settings.rootCA) { + changed = true; + } +#endif // save the new settings settings = newSettings; diff --git a/lib/framework/MqttSettingsService.h b/lib/framework/MqttSettingsService.h index 1db25c0d4..e13b4f4c8 100644 --- a/lib/framework/MqttSettingsService.h +++ b/lib/framework/MqttSettingsService.h @@ -63,6 +63,7 @@ class MqttSettings { bool enabled; String host; uint16_t port; + String rootCA; // username and password String username; @@ -105,12 +106,15 @@ class MqttSettingsService : public StatefulService { ~MqttSettingsService(); void begin(); + void startClient(); void loop(); bool isEnabled(); bool isConnected(); const char * getClientId(); espMqttClientTypes::DisconnectReason getDisconnectReason(); - espMqttClient * getMqttClient(); + MqttClient * getMqttClient(); + void setWill(const char * topic); + void onMessage(espMqttClientTypes::OnMessageCallback callback); protected: void onConfigUpdated(); @@ -125,6 +129,7 @@ class MqttSettingsService : public StatefulService { char * _retainedClientId; char * _retainedUsername; char * _retainedPassword; + char * _retainedRootCA; // variable to help manage connection bool _reconfigureMqtt; @@ -134,7 +139,7 @@ class MqttSettingsService : public StatefulService { espMqttClientTypes::DisconnectReason _disconnectReason; // the MQTT client instance - espMqttClient _mqttClient; + MqttClient * _mqttClient; void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info); void onMqttConnect(bool sessionPresent); diff --git a/src/devices/boiler.cpp b/src/devices/boiler.cpp index 30da339f8..028d84d17 100644 --- a/src/devices/boiler.cpp +++ b/src/devices/boiler.cpp @@ -590,7 +590,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(tempDiffHeat), DeviceValueUOM::K, MAKE_CF_CB(set_tempDiffHeat), - 3, + 2, 10); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &tempDiffCool_, @@ -599,7 +599,7 @@ Boiler::Boiler(uint8_t device_type, int8_t device_id, uint8_t product_id, const FL_(tempDiffCool), DeviceValueUOM::K, MAKE_CF_CB(set_tempDiffCool), - 3, + 2, 10); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &vp_cooling_, DeviceValueType::BOOL, FL_(vp_cooling), DeviceValueUOM::NONE, MAKE_CF_CB(set_vp_cooling)); register_device_value(DeviceValueTAG::TAG_DEVICE_DATA, &heatCable_, DeviceValueType::BOOL, FL_(heatCable), DeviceValueUOM::NONE, MAKE_CF_CB(set_heatCable)); diff --git a/src/devices/thermostat.cpp b/src/devices/thermostat.cpp index 97b9086aa..5f6bae89b 100644 --- a/src/devices/thermostat.cpp +++ b/src/devices/thermostat.cpp @@ -4196,7 +4196,7 @@ void Thermostat::register_device_values_hc(std::shared_ptrcooling, DeviceValueType::BOOL, FL_(hpcooling), DeviceValueUOM::NONE, MAKE_CF_CB(set_cooling)); register_device_value(tag, &hc->hpmode, DeviceValueType::ENUM, FL_(enum_hpmode), FL_(hpmode), DeviceValueUOM::NONE, MAKE_CF_CB(set_hpmode)); - register_device_value(tag, &hc->dewoffset, DeviceValueType::UINT, FL_(dewoffset), DeviceValueUOM::K, MAKE_CF_CB(set_dewoffset)); + register_device_value(tag, &hc->dewoffset, DeviceValueType::UINT, FL_(dewoffset), DeviceValueUOM::K, MAKE_CF_CB(set_dewoffset), 2, 10); register_device_value(tag, &hc->roomtempdiff, DeviceValueType::UINT, FL_(roomtempdiff), DeviceValueUOM::K, MAKE_CF_CB(set_roomtempdiff)); register_device_value(tag, &hc->hpminflowtemp, DeviceValueType::UINT, FL_(hpminflowtemp), DeviceValueUOM::DEGREES, MAKE_CF_CB(set_hpminflowtemp)); diff --git a/src/helpers.cpp b/src/helpers.cpp index 692c82513..e6de1c060 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -277,7 +277,7 @@ char * Helpers::render_value(char * result, const double value, const int8_t for // format: 0=no division, other divide by the value given and render with a decimal point char * Helpers::render_value(char * result, const int32_t value, const int8_t format, const uint8_t fahrenheit) { int32_t new_value = fahrenheit ? format ? value * 1.8 + 32 * format * (fahrenheit - 1) : value * 1.8 + 32 * (fahrenheit - 1) : value; - char s[10] = {0}; + char s[13] = {0}; // just print it if no conversion required (format = 0) if (!format) { strlcpy(result, itoa(new_value, s, 10), sizeof(s)); // format is 0 diff --git a/src/mqtt.cpp b/src/mqtt.cpp index 609a82fa9..99f7c1886 100644 --- a/src/mqtt.cpp +++ b/src/mqtt.cpp @@ -23,7 +23,7 @@ namespace emsesp { -espMqttClient * Mqtt::mqttClient_; +MqttClient * Mqtt::mqttClient_; // static parameters we make global std::string Mqtt::mqtt_base_; @@ -387,9 +387,9 @@ void Mqtt::start() { snprintf(will_topic, MQTT_TOPIC_MAX_SIZE, "status"); } - mqttClient_->setWill(will_topic, 1, true, "offline"); // with qos 1, retain true + EMSESP::esp8266React.setWill(will_topic); // with qos 1, retain true - mqttClient_->onMessage( + EMSESP::esp8266React.onMessage( [this](const espMqttClientTypes::MessageProperties & properties, const char * topic, const uint8_t * payload, size_t len, size_t index, size_t total) { on_message(topic, (const char *)payload, len); // receiving mqtt }); diff --git a/src/mqtt.h b/src/mqtt.h index a6f54ee8d..ac3c1effe 100644 --- a/src/mqtt.h +++ b/src/mqtt.h @@ -111,7 +111,7 @@ class Mqtt { #endif } - static espMqttClient * client() { + static MqttClient * client() { return mqttClient_; } @@ -229,8 +229,8 @@ class Mqtt { private: static uuid::log::Logger logger_; - static espMqttClient * mqttClient_; - static uint32_t mqtt_message_id_; + static MqttClient * mqttClient_; + static uint32_t mqtt_message_id_; static bool queue_message(const uint8_t operation, const std::string & topic, const std::string & payload, const bool retain); static bool queue_publish_message(const std::string & topic, const std::string & payload, const bool retain);