2022-07-15 18:05:58 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
/*
|
2024-01-20 02:00:22 +01:00
|
|
|
* Copyright (C) 2022-2024 Thomas Basler and others
|
2022-07-15 18:05:58 +02:00
|
|
|
*/
|
2022-06-15 23:46:22 +02:00
|
|
|
#include "WebApi_mqtt.h"
|
|
|
|
|
#include "Configuration.h"
|
2022-12-14 19:07:11 +01:00
|
|
|
#include "MqttHandleHass.h"
|
2024-05-20 17:56:59 +02:00
|
|
|
#include "MqttHandleInverter.h"
|
2022-06-15 23:46:22 +02:00
|
|
|
#include "MqttSettings.h"
|
2022-11-03 21:31:50 +01:00
|
|
|
#include "WebApi.h"
|
2022-12-23 19:46:59 +01:00
|
|
|
#include "WebApi_errors.h"
|
2022-06-15 23:46:22 +02:00
|
|
|
#include "helper.h"
|
2022-12-14 22:13:03 +01:00
|
|
|
#include <AsyncJson.h>
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2024-01-20 02:00:22 +01:00
|
|
|
void WebApiMqttClass::init(AsyncWebServer& server, Scheduler& scheduler)
|
2022-06-15 23:46:22 +02:00
|
|
|
{
|
2022-09-13 21:35:51 +02:00
|
|
|
using std::placeholders::_1;
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2024-01-27 01:09:55 +01:00
|
|
|
server.on("/api/mqtt/status", HTTP_GET, std::bind(&WebApiMqttClass::onMqttStatus, this, _1));
|
|
|
|
|
server.on("/api/mqtt/config", HTTP_GET, std::bind(&WebApiMqttClass::onMqttAdminGet, this, _1));
|
|
|
|
|
server.on("/api/mqtt/config", HTTP_POST, std::bind(&WebApiMqttClass::onMqttAdminPost, this, _1));
|
2022-06-15 23:46:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
|
|
|
|
{
|
2022-11-22 23:40:19 +01:00
|
|
|
if (!WebApi.checkCredentialsReadonly(request)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 23:23:12 +02:00
|
|
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
2024-01-04 15:38:56 +01:00
|
|
|
auto& root = response->getRoot();
|
2022-09-05 21:41:45 +02:00
|
|
|
const CONFIG_T& config = Configuration.get();
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_enabled"] = config.Mqtt.Enabled;
|
|
|
|
|
root["mqtt_hostname"] = config.Mqtt.Hostname;
|
|
|
|
|
root["mqtt_port"] = config.Mqtt.Port;
|
2024-06-29 11:05:04 +02:00
|
|
|
root["mqtt_clientid"] = MqttSettings.getClientId();
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_username"] = config.Mqtt.Username;
|
|
|
|
|
root["mqtt_topic"] = config.Mqtt.Topic;
|
2023-04-04 18:51:18 +02:00
|
|
|
root["mqtt_connected"] = MqttSettings.getConnected();
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_retain"] = config.Mqtt.Retain;
|
|
|
|
|
root["mqtt_tls"] = config.Mqtt.Tls.Enabled;
|
|
|
|
|
root["mqtt_root_ca_cert_info"] = getTlsCertInfo(config.Mqtt.Tls.RootCaCert);
|
|
|
|
|
root["mqtt_tls_cert_login"] = config.Mqtt.Tls.CertLogin;
|
|
|
|
|
root["mqtt_client_cert_info"] = getTlsCertInfo(config.Mqtt.Tls.ClientCert);
|
|
|
|
|
root["mqtt_lwt_topic"] = String(config.Mqtt.Topic) + config.Mqtt.Lwt.Topic;
|
|
|
|
|
root["mqtt_publish_interval"] = config.Mqtt.PublishInterval;
|
|
|
|
|
root["mqtt_clean_session"] = config.Mqtt.CleanSession;
|
|
|
|
|
root["mqtt_hass_enabled"] = config.Mqtt.Hass.Enabled;
|
|
|
|
|
root["mqtt_hass_expire"] = config.Mqtt.Hass.Expire;
|
|
|
|
|
root["mqtt_hass_retain"] = config.Mqtt.Hass.Retain;
|
|
|
|
|
root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic;
|
|
|
|
|
root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels;
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
|
|
|
|
{
|
2022-11-03 21:31:50 +01:00
|
|
|
if (!WebApi.checkCredentials(request)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 23:23:12 +02:00
|
|
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
2024-01-04 15:38:56 +01:00
|
|
|
auto& root = response->getRoot();
|
2022-09-05 21:41:45 +02:00
|
|
|
const CONFIG_T& config = Configuration.get();
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_enabled"] = config.Mqtt.Enabled;
|
|
|
|
|
root["mqtt_hostname"] = config.Mqtt.Hostname;
|
|
|
|
|
root["mqtt_port"] = config.Mqtt.Port;
|
2024-06-29 00:28:21 +02:00
|
|
|
root["mqtt_clientid"] = config.Mqtt.ClientId;
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_username"] = config.Mqtt.Username;
|
|
|
|
|
root["mqtt_password"] = config.Mqtt.Password;
|
|
|
|
|
root["mqtt_topic"] = config.Mqtt.Topic;
|
|
|
|
|
root["mqtt_retain"] = config.Mqtt.Retain;
|
|
|
|
|
root["mqtt_tls"] = config.Mqtt.Tls.Enabled;
|
|
|
|
|
root["mqtt_root_ca_cert"] = config.Mqtt.Tls.RootCaCert;
|
|
|
|
|
root["mqtt_tls_cert_login"] = config.Mqtt.Tls.CertLogin;
|
|
|
|
|
root["mqtt_client_cert"] = config.Mqtt.Tls.ClientCert;
|
|
|
|
|
root["mqtt_client_key"] = config.Mqtt.Tls.ClientKey;
|
|
|
|
|
root["mqtt_lwt_topic"] = config.Mqtt.Lwt.Topic;
|
2024-05-20 17:56:59 +02:00
|
|
|
root["mqtt_lwt_online"] = config.Mqtt.Lwt.Value_Online;
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_lwt_offline"] = config.Mqtt.Lwt.Value_Offline;
|
2023-11-19 16:17:10 +01:00
|
|
|
root["mqtt_lwt_qos"] = config.Mqtt.Lwt.Qos;
|
2023-11-19 14:53:26 +01:00
|
|
|
root["mqtt_publish_interval"] = config.Mqtt.PublishInterval;
|
|
|
|
|
root["mqtt_clean_session"] = config.Mqtt.CleanSession;
|
|
|
|
|
root["mqtt_hass_enabled"] = config.Mqtt.Hass.Enabled;
|
|
|
|
|
root["mqtt_hass_expire"] = config.Mqtt.Hass.Expire;
|
|
|
|
|
root["mqtt_hass_retain"] = config.Mqtt.Hass.Retain;
|
|
|
|
|
root["mqtt_hass_topic"] = config.Mqtt.Hass.Topic;
|
|
|
|
|
root["mqtt_hass_individualpanels"] = config.Mqtt.Hass.IndividualPanels;
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|
|
|
|
{
|
2022-11-03 21:31:50 +01:00
|
|
|
if (!WebApi.checkCredentials(request)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-02 23:23:12 +02:00
|
|
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
|
|
|
|
JsonDocument root;
|
|
|
|
|
if (!WebApi.parseRequestData(request, response, root)) {
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-01 13:52:09 +02:00
|
|
|
auto& retMsg = response->getRoot();
|
|
|
|
|
|
2024-09-21 00:12:15 +02:00
|
|
|
if (!(root["mqtt_enabled"].is<bool>()
|
|
|
|
|
&& root["mqtt_hostname"].is<String>()
|
|
|
|
|
&& root["mqtt_port"].is<uint>()
|
|
|
|
|
&& root["mqtt_clientid"].is<String>()
|
|
|
|
|
&& root["mqtt_username"].is<String>()
|
|
|
|
|
&& root["mqtt_password"].is<String>()
|
|
|
|
|
&& root["mqtt_topic"].is<String>()
|
|
|
|
|
&& root["mqtt_retain"].is<bool>()
|
|
|
|
|
&& root["mqtt_tls"].is<bool>()
|
|
|
|
|
&& root["mqtt_tls_cert_login"].is<bool>()
|
|
|
|
|
&& root["mqtt_client_cert"].is<String>()
|
|
|
|
|
&& root["mqtt_client_key"].is<String>()
|
|
|
|
|
&& root["mqtt_lwt_topic"].is<String>()
|
|
|
|
|
&& root["mqtt_lwt_online"].is<String>()
|
|
|
|
|
&& root["mqtt_lwt_offline"].is<String>()
|
|
|
|
|
&& root["mqtt_lwt_qos"].is<uint8_t>()
|
|
|
|
|
&& root["mqtt_publish_interval"].is<uint32_t>()
|
|
|
|
|
&& root["mqtt_clean_session"].is<bool>()
|
|
|
|
|
&& root["mqtt_hass_enabled"].is<bool>()
|
|
|
|
|
&& root["mqtt_hass_expire"].is<bool>()
|
|
|
|
|
&& root["mqtt_hass_retain"].is<bool>()
|
|
|
|
|
&& root["mqtt_hass_topic"].is<String>()
|
|
|
|
|
&& root["mqtt_hass_individualpanels"].is<bool>())) {
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["message"] = "Values are missing!";
|
|
|
|
|
retMsg["code"] = WebApiError::GenericValueMissing;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_enabled"].as<bool>()) {
|
|
|
|
|
if (root["mqtt_hostname"].as<String>().length() == 0 || root["mqtt_hostname"].as<String>().length() > MQTT_MAX_HOSTNAME_STRLEN) {
|
|
|
|
|
retMsg["message"] = "MqTT Server must between 1 and " STR(MQTT_MAX_HOSTNAME_STRLEN) " characters long!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttHostnameLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_HOSTNAME_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-29 00:28:21 +02:00
|
|
|
if (root["mqtt_clientid"].as<String>().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;
|
|
|
|
|
}
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_username"].as<String>().length() > MQTT_MAX_USERNAME_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "Username must not be longer than " STR(MQTT_MAX_USERNAME_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttUsernameLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_USERNAME_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_password"].as<String>().length() > MQTT_MAX_PASSWORD_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "Password must not be longer than " STR(MQTT_MAX_PASSWORD_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttPasswordLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_PASSWORD_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "Topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttTopicLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_topic"].as<String>().indexOf(' ') != -1) {
|
|
|
|
|
retMsg["message"] = "Topic must not contain space characters!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttTopicCharacter;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-08-03 21:23:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (!root["mqtt_topic"].as<String>().endsWith("/")) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "Topic must end with a slash (/)!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttTopicTrailingSlash;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-10-11 22:26:06 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_port"].as<uint>() == 0 || root["mqtt_port"].as<uint>() > 65535) {
|
|
|
|
|
retMsg["message"] = "Port must be a number between 1 and 65535!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttPort;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-12 11:58:27 +02:00
|
|
|
if (root["mqtt_root_ca_cert"].as<String>().length() > MQTT_MAX_CERT_STRLEN
|
2023-07-22 18:00:41 +02:00
|
|
|
|| root["mqtt_client_cert"].as<String>().length() > MQTT_MAX_CERT_STRLEN
|
|
|
|
|
|| root["mqtt_client_key"].as<String>().length() > MQTT_MAX_CERT_STRLEN) {
|
2023-04-12 11:58:27 +02:00
|
|
|
retMsg["message"] = "Certificates must not be longer than " STR(MQTT_MAX_CERT_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttCertificateLength;
|
2023-04-12 11:58:27 +02:00
|
|
|
retMsg["param"]["max"] = MQTT_MAX_CERT_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-07-26 16:08:45 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_lwt_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "LWT topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttLwtTopicLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_lwt_topic"].as<String>().indexOf(' ') != -1) {
|
|
|
|
|
retMsg["message"] = "LWT topic must not contain space characters!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttLwtTopicCharacter;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-08-03 21:23:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_lwt_online"].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "LWT online value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttLwtOnlineLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_lwt_offline"].as<String>().length() > MQTT_MAX_LWTVALUE_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "LWT offline value must not be longer than " STR(MQTT_MAX_LWTVALUE_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttLwtOfflineLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_LWTVALUE_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-06-16 14:57:12 +02:00
|
|
|
|
2023-11-19 16:17:10 +01:00
|
|
|
if (root["mqtt_lwt_qos"].as<uint8_t>() > 2) {
|
|
|
|
|
retMsg["message"] = "LWT QoS must not be greater than " STR(2) "!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttLwtQos;
|
|
|
|
|
retMsg["param"]["max"] = 2;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2023-11-19 16:17:10 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_publish_interval"].as<uint32_t>() < 5 || root["mqtt_publish_interval"].as<uint32_t>() > 65535) {
|
|
|
|
|
retMsg["message"] = "Publish interval must be a number between 5 and 65535!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttPublishInterval;
|
|
|
|
|
retMsg["param"]["min"] = 5;
|
|
|
|
|
retMsg["param"]["max"] = 65535;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-16 14:57:12 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-07-18 22:28:03 +02:00
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_hass_enabled"].as<bool>()) {
|
|
|
|
|
if (root["mqtt_hass_topic"].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
2023-04-12 08:37:49 +02:00
|
|
|
retMsg["message"] = "Hass topic must not be longer than " STR(MQTT_MAX_TOPIC_STRLEN) " characters!";
|
2023-04-04 18:51:18 +02:00
|
|
|
retMsg["code"] = WebApiError::MqttHassTopicLength;
|
|
|
|
|
retMsg["param"]["max"] = MQTT_MAX_TOPIC_STRLEN;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-07-18 22:28:03 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2022-08-03 21:23:22 +02:00
|
|
|
|
2023-04-04 18:51:18 +02:00
|
|
|
if (root["mqtt_hass_topic"].as<String>().indexOf(' ') != -1) {
|
|
|
|
|
retMsg["message"] = "Hass topic must not contain space characters!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttHassTopicCharacter;
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-08-03 21:23:22 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2025-05-20 19:44:59 +02:00
|
|
|
|
|
|
|
|
if (!root["mqtt_hass_topic"].as<String>().endsWith("/")) {
|
|
|
|
|
retMsg["message"] = "Hass topic must end with a slash (/)!";
|
|
|
|
|
retMsg["code"] = WebApiError::MqttHassTopicTrailingSlash;
|
|
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-07-18 22:28:03 +02:00
|
|
|
}
|
2022-06-15 23:46:22 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-17 21:46:32 +02:00
|
|
|
{
|
|
|
|
|
auto guard = Configuration.getWriteGuard();
|
|
|
|
|
auto& config = guard.getConfig();
|
|
|
|
|
|
|
|
|
|
config.Mqtt.Enabled = root["mqtt_enabled"].as<bool>();
|
|
|
|
|
config.Mqtt.Retain = root["mqtt_retain"].as<bool>();
|
|
|
|
|
config.Mqtt.Tls.Enabled = root["mqtt_tls"].as<bool>();
|
|
|
|
|
strlcpy(config.Mqtt.Tls.RootCaCert, root["mqtt_root_ca_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.RootCaCert));
|
|
|
|
|
config.Mqtt.Tls.CertLogin = root["mqtt_tls_cert_login"].as<bool>();
|
|
|
|
|
strlcpy(config.Mqtt.Tls.ClientCert, root["mqtt_client_cert"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientCert));
|
|
|
|
|
strlcpy(config.Mqtt.Tls.ClientKey, root["mqtt_client_key"].as<String>().c_str(), sizeof(config.Mqtt.Tls.ClientKey));
|
|
|
|
|
config.Mqtt.Port = root["mqtt_port"].as<uint>();
|
|
|
|
|
strlcpy(config.Mqtt.Hostname, root["mqtt_hostname"].as<String>().c_str(), sizeof(config.Mqtt.Hostname));
|
|
|
|
|
strlcpy(config.Mqtt.ClientId, root["mqtt_clientid"].as<String>().c_str(), sizeof(config.Mqtt.ClientId));
|
|
|
|
|
strlcpy(config.Mqtt.Username, root["mqtt_username"].as<String>().c_str(), sizeof(config.Mqtt.Username));
|
|
|
|
|
strlcpy(config.Mqtt.Password, root["mqtt_password"].as<String>().c_str(), sizeof(config.Mqtt.Password));
|
|
|
|
|
strlcpy(config.Mqtt.Lwt.Topic, root["mqtt_lwt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Topic));
|
|
|
|
|
strlcpy(config.Mqtt.Lwt.Value_Online, root["mqtt_lwt_online"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Online));
|
|
|
|
|
strlcpy(config.Mqtt.Lwt.Value_Offline, root["mqtt_lwt_offline"].as<String>().c_str(), sizeof(config.Mqtt.Lwt.Value_Offline));
|
|
|
|
|
config.Mqtt.Lwt.Qos = root["mqtt_lwt_qos"].as<uint8_t>();
|
|
|
|
|
config.Mqtt.PublishInterval = root["mqtt_publish_interval"].as<uint32_t>();
|
|
|
|
|
config.Mqtt.CleanSession = root["mqtt_clean_session"].as<bool>();
|
|
|
|
|
config.Mqtt.Hass.Enabled = root["mqtt_hass_enabled"].as<bool>();
|
|
|
|
|
config.Mqtt.Hass.Expire = root["mqtt_hass_expire"].as<bool>();
|
|
|
|
|
config.Mqtt.Hass.Retain = root["mqtt_hass_retain"].as<bool>();
|
|
|
|
|
config.Mqtt.Hass.IndividualPanels = root["mqtt_hass_individualpanels"].as<bool>();
|
|
|
|
|
strlcpy(config.Mqtt.Hass.Topic, root["mqtt_hass_topic"].as<String>().c_str(), sizeof(config.Mqtt.Hass.Topic));
|
|
|
|
|
|
|
|
|
|
// Check if base topic was changed
|
|
|
|
|
if (strcmp(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str())) {
|
|
|
|
|
MqttHandleInverter.unsubscribeTopics();
|
|
|
|
|
strlcpy(config.Mqtt.Topic, root["mqtt_topic"].as<String>().c_str(), sizeof(config.Mqtt.Topic));
|
|
|
|
|
MqttHandleInverter.subscribeTopics();
|
|
|
|
|
}
|
2024-05-20 17:56:59 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-04 13:42:39 +01:00
|
|
|
WebApi.writeConfig(retMsg);
|
2022-06-15 23:46:22 +02:00
|
|
|
|
2024-04-04 20:43:07 +02:00
|
|
|
WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
|
2022-06-15 23:46:22 +02:00
|
|
|
|
|
|
|
|
MqttSettings.performReconnect();
|
2022-12-14 19:07:11 +01:00
|
|
|
MqttHandleHass.forceUpdate();
|
2022-07-26 16:08:45 +02:00
|
|
|
}
|
|
|
|
|
|
2023-04-12 08:47:24 +02:00
|
|
|
String WebApiMqttClass::getTlsCertInfo(const char* cert)
|
2022-07-26 16:08:45 +02:00
|
|
|
{
|
2023-04-12 08:47:24 +02:00
|
|
|
char tlsCertInfo[1024] = "";
|
2022-07-26 16:08:45 +02:00
|
|
|
|
2023-04-12 08:47:24 +02:00
|
|
|
mbedtls_x509_crt tlsCert;
|
2022-07-26 16:08:45 +02:00
|
|
|
|
2023-04-12 08:47:24 +02:00
|
|
|
strlcpy(tlsCertInfo, "Can't parse TLS certificate", sizeof(tlsCertInfo));
|
2022-07-26 16:08:45 +02:00
|
|
|
|
2023-04-12 08:47:24 +02:00
|
|
|
mbedtls_x509_crt_init(&tlsCert);
|
|
|
|
|
int ret = mbedtls_x509_crt_parse(&tlsCert, const_cast<unsigned char*>((unsigned char*)cert), 1 + strlen(cert));
|
2022-07-26 16:08:45 +02:00
|
|
|
if (ret < 0) {
|
2023-04-12 08:47:24 +02:00
|
|
|
snprintf(tlsCertInfo, sizeof(tlsCertInfo), "Can't parse TLS certificate: mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
|
|
|
|
mbedtls_x509_crt_free(&tlsCert);
|
2022-07-26 16:08:45 +02:00
|
|
|
return "";
|
|
|
|
|
}
|
2023-04-12 08:47:24 +02:00
|
|
|
mbedtls_x509_crt_info(tlsCertInfo, sizeof(tlsCertInfo) - 1, "", &tlsCert);
|
|
|
|
|
mbedtls_x509_crt_free(&tlsCert);
|
2022-07-26 16:08:45 +02:00
|
|
|
|
2023-04-12 08:47:24 +02:00
|
|
|
return tlsCertInfo;
|
2022-07-26 16:08:45 +02:00
|
|
|
}
|