diff --git a/include/Configuration.h b/include/Configuration.h index 0ad2cb39..4a802e4e 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -16,6 +16,7 @@ #define NTP_MAX_TIMEZONEDESCR_STRLEN 50 #define MQTT_MAX_HOSTNAME_STRLEN 128 +#define MQTT_MAX_CLIENTID_STRLEN 64 #define MQTT_MAX_USERNAME_STRLEN 64 #define MQTT_MAX_PASSWORD_STRLEN 64 #define MQTT_MAX_TOPIC_STRLEN 32 @@ -88,6 +89,7 @@ struct CONFIG_T { bool Enabled; char Hostname[MQTT_MAX_HOSTNAME_STRLEN + 1]; uint32_t Port; + char ClientId[MQTT_MAX_CLIENTID_STRLEN + 1]; char Username[MQTT_MAX_USERNAME_STRLEN + 1]; char Password[MQTT_MAX_PASSWORD_STRLEN + 1]; char Topic[MQTT_MAX_TOPIC_STRLEN + 1]; diff --git a/include/WebApi_errors.h b/include/WebApi_errors.h index 97d61b22..0da8d3d9 100644 --- a/include/WebApi_errors.h +++ b/include/WebApi_errors.h @@ -60,6 +60,7 @@ enum WebApiError { MqttHassTopicLength, MqttHassTopicCharacter, MqttLwtQos, + MqttClientIdLength, NetworkBase = 8000, NetworkIpInvalid, diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 780abb8f..db47d9c8 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -4,6 +4,7 @@ */ #include "Configuration.h" #include "MessageOutput.h" +#include "NetworkSettings.h" #include "Utils.h" #include "defaults.h" #include @@ -58,6 +59,7 @@ bool ConfigurationClass::write() mqtt["enabled"] = config.Mqtt.Enabled; mqtt["hostname"] = config.Mqtt.Hostname; mqtt["port"] = config.Mqtt.Port; + mqtt["clientid"] = config.Mqtt.ClientId; mqtt["username"] = config.Mqtt.Username; mqtt["password"] = config.Mqtt.Password; mqtt["topic"] = config.Mqtt.Topic; @@ -232,6 +234,7 @@ bool ConfigurationClass::read() config.Mqtt.Enabled = mqtt["enabled"] | MQTT_ENABLED; strlcpy(config.Mqtt.Hostname, mqtt["hostname"] | MQTT_HOST, sizeof(config.Mqtt.Hostname)); config.Mqtt.Port = mqtt["port"] | MQTT_PORT; + strlcpy(config.Mqtt.ClientId, mqtt["clientid"] | NetworkSettings.getApName().c_str(), sizeof(config.Mqtt.ClientId)); strlcpy(config.Mqtt.Username, mqtt["username"] | MQTT_USER, sizeof(config.Mqtt.Username)); strlcpy(config.Mqtt.Password, mqtt["password"] | MQTT_PASSWORD, sizeof(config.Mqtt.Password)); strlcpy(config.Mqtt.Topic, mqtt["topic"] | MQTT_TOPIC, sizeof(config.Mqtt.Topic)); diff --git a/src/MqttSettings.cpp b/src/MqttSettings.cpp index 82d0540b..164794ff 100644 --- a/src/MqttSettings.cpp +++ b/src/MqttSettings.cpp @@ -115,7 +115,7 @@ void MqttSettingsClass::performConnect() MessageOutput.println("Connecting to MQTT..."); const CONFIG_T& config = Configuration.get(); const String willTopic = getPrefix() + config.Mqtt.Lwt.Topic; - const String clientId = NetworkSettings.getApName(); + const String clientId = config.Mqtt.ClientId; if (config.Mqtt.Tls.Enabled) { static_cast(_mqttClient)->setCACert(config.Mqtt.Tls.RootCaCert); static_cast(_mqttClient)->setServer(config.Mqtt.Hostname, config.Mqtt.Port); diff --git a/src/WebApi_mqtt.cpp b/src/WebApi_mqtt.cpp index 9d1a7dbe..b287b3df 100644 --- a/src/WebApi_mqtt.cpp +++ b/src/WebApi_mqtt.cpp @@ -34,6 +34,7 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request) root["mqtt_enabled"] = config.Mqtt.Enabled; root["mqtt_hostname"] = config.Mqtt.Hostname; root["mqtt_port"] = config.Mqtt.Port; + root["mqtt_clientid"] = config.Mqtt.ClientId; root["mqtt_username"] = config.Mqtt.Username; root["mqtt_topic"] = config.Mqtt.Topic; root["mqtt_connected"] = MqttSettings.getConnected(); @@ -67,6 +68,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request) root["mqtt_enabled"] = config.Mqtt.Enabled; root["mqtt_hostname"] = config.Mqtt.Hostname; root["mqtt_port"] = config.Mqtt.Port; + root["mqtt_clientid"] = config.Mqtt.ClientId; root["mqtt_username"] = config.Mqtt.Username; root["mqtt_password"] = config.Mqtt.Password; root["mqtt_topic"] = config.Mqtt.Topic; @@ -108,6 +110,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) if (!(root.containsKey("mqtt_enabled") && root.containsKey("mqtt_hostname") && root.containsKey("mqtt_port") + && root.containsKey("mqtt_clientid") && root.containsKey("mqtt_username") && root.containsKey("mqtt_password") && root.containsKey("mqtt_topic") @@ -142,6 +145,13 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) return; } + if (root["mqtt_clientid"].as().length() > MQTT_MAX_CLIENTID_STRLEN) { + retMsg["message"] = "Client ID must not be longer than " STR(MQTT_MAX_CLIENTID_STRLEN) " characters!"; + retMsg["code"] = WebApiError::MqttClientIdLength; + retMsg["param"]["max"] = MQTT_MAX_CLIENTID_STRLEN; + WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__); + return; + } if (root["mqtt_username"].as().length() > MQTT_MAX_USERNAME_STRLEN) { retMsg["message"] = "Username must not be longer than " STR(MQTT_MAX_USERNAME_STRLEN) " characters!"; retMsg["code"] = WebApiError::MqttUsernameLength; @@ -271,6 +281,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request) strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as().c_str(), sizeof(config.Mqtt.Tls.ClientKey)); config.Mqtt.Port = root["mqtt_port"].as(); strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as().c_str(), sizeof(config.Mqtt.Hostname)); + strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as().c_str(), sizeof(config.Mqtt.ClientId)); strlcpy(config.Mqtt.Username, root["mqtt_username"].as().c_str(), sizeof(config.Mqtt.Username)); strlcpy(config.Mqtt.Password, root["mqtt_password"].as().c_str(), sizeof(config.Mqtt.Password)); strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as().c_str(), sizeof(config.Mqtt.Lwt.Topic)); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 8b132271..834849d2 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -85,6 +85,7 @@ "7014": "Hass-Topic darf nicht länger als {max} Zeichen sein!", "7015": "Hass-Topic darf keine Leerzeichen enthalten!", "7016": "LWT QOS darf icht größer als {max} sein!", + "7017": "Client ID darf nicht länger als {max} Zeichen sein!", "8001": "IP-Adresse ist ungültig!", "8002": "Netzmaske ist ungültig!", "8003": "Standardgateway ist ungültig!", @@ -297,6 +298,7 @@ "Disabled": "nicht aktiv", "Server": "@:ntpinfo.Server", "Port": "Port", + "ClientId": "Client ID", "Username": "Benutzername", "BaseTopic": "Basis-Topic", "PublishInterval": "Veröffentlichungsintervall", @@ -441,6 +443,7 @@ "Hostname": "Hostname:", "HostnameHint": "Hostname oder IP-Adresse", "Port": "Port:", + "ClientId": "Client ID:", "Username": "Benutzername:", "UsernameHint": "Benutzername, leer lassen für anonyme Verbindung", "Password": "Passwort:", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index c918e537..af2a1b44 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -85,6 +85,7 @@ "7014": "Hass topic must not longer then {max} characters!", "7015": "Hass topic must not contain space characters!", "7016": "LWT QOS must not greater then {max}!", + "7017": "Client ID must not longer then {max} characters!", "8001": "IP address is invalid!", "8002": "Netmask is invalid!", "8003": "Gateway is invalid!", @@ -297,6 +298,7 @@ "Disabled": "Disabled", "Server": "@:ntpinfo.Server", "Port": "Port", + "ClientId": "Client ID", "Username": "Username", "BaseTopic": "Base Topic", "PublishInterval": "Publish Interval", @@ -441,6 +443,7 @@ "Hostname": "Hostname:", "HostnameHint": "Hostname or IP address", "Port": "Port:", + "ClientId": "Client ID:", "Username": "Username:", "UsernameHint": "Username, leave empty for anonymous connection", "Password": "Password:", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index acd1280f..96f259d0 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -85,6 +85,7 @@ "7014": "Le sujet Hass ne doit pas dépasser {max} caractères !", "7015": "Le sujet Hass ne doit pas contenir d'espace !", "7016": "LWT QOS ne doit pas être supérieur à {max}!", + "7017": "Client ID must not longer then {max} characters!", "8001": "L'adresse IP n'est pas valide !", "8002": "Le masque de réseau n'est pas valide !", "8003": "La passerelle n'est pas valide !", @@ -297,6 +298,7 @@ "Disabled": "Désactivé", "Server": "@:ntpinfo.Server", "Port": "Port", + "ClientId": "Client ID", "Username": "Nom d'utilisateur", "BaseTopic": "Sujet de base", "PublishInterval": "Intervalle de publication", @@ -441,6 +443,7 @@ "Hostname": "Nom d'hôte", "HostnameHint": "Nom d'hôte ou adresse IP", "Port": "Port", + "ClientId": "Client ID:", "Username": "Nom d'utilisateur", "UsernameHint": "Nom d'utilisateur, laisser vide pour une connexion anonyme", "Password": "Mot de passe:", diff --git a/webapp/src/types/MqttConfig.ts b/webapp/src/types/MqttConfig.ts index c61b770a..d64e0e44 100644 --- a/webapp/src/types/MqttConfig.ts +++ b/webapp/src/types/MqttConfig.ts @@ -2,6 +2,7 @@ export interface MqttConfig { mqtt_enabled: boolean; mqtt_hostname: string; mqtt_port: number; + mqtt_clientid: string; mqtt_username: string; mqtt_password: string; mqtt_topic: string; @@ -22,4 +23,4 @@ export interface MqttConfig { mqtt_hass_retain: boolean; mqtt_hass_topic: string; mqtt_hass_individualpanels: boolean; -} \ No newline at end of file +} diff --git a/webapp/src/types/MqttStatus.ts b/webapp/src/types/MqttStatus.ts index 5312ae55..df11dc2c 100644 --- a/webapp/src/types/MqttStatus.ts +++ b/webapp/src/types/MqttStatus.ts @@ -2,6 +2,7 @@ export interface MqttStatus { mqtt_enabled: boolean; mqtt_hostname: string; mqtt_port: number; + mqtt_clientid: string; mqtt_username: string; mqtt_topic: string; mqtt_publish_interval: number; @@ -17,4 +18,4 @@ export interface MqttStatus { mqtt_hass_retain: boolean; mqtt_hass_topic: string; mqtt_hass_individualpanels: boolean; -} \ No newline at end of file +} diff --git a/webapp/src/views/MqttAdminView.vue b/webapp/src/views/MqttAdminView.vue index ffa3890c..3571855f 100644 --- a/webapp/src/views/MqttAdminView.vue +++ b/webapp/src/views/MqttAdminView.vue @@ -28,6 +28,10 @@ v-model="mqttConfigList.mqtt_port" type="number" min="1" max="65535"/> + + {{ $t('mqttinfo.Port') }} {{ mqttDataList.mqtt_port }} + + {{ $t('mqttinfo.ClientId') }} + {{ mqttDataList.mqtt_clientid }} + {{ $t('mqttinfo.Username') }} {{ mqttDataList.mqtt_username }}