Add support for MQTT TLS
To support TLS its necessary to use another MQTT library. The new lib is a drop-in replacement for the async-mqtt-client.
This commit is contained in:
parent
6c088a9898
commit
4435fbcdad
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,4 +3,5 @@
|
|||||||
.vscode/c_cpp_properties.json
|
.vscode/c_cpp_properties.json
|
||||||
.vscode/launch.json
|
.vscode/launch.json
|
||||||
.vscode/ipch
|
.vscode/ipch
|
||||||
|
.vscode/settings.json
|
||||||
platformio-device-monitor*.log
|
platformio-device-monitor*.log
|
||||||
@ -4,7 +4,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define CONFIG_FILENAME "/config.bin"
|
#define CONFIG_FILENAME "/config.bin"
|
||||||
#define CONFIG_VERSION 0x00011200 // 0.1.18 // make sure to clean all after change
|
#define CONFIG_VERSION 0x00011300 // 0.1.19 // make sure to clean all after change
|
||||||
|
|
||||||
#define WIFI_MAX_SSID_STRLEN 31
|
#define WIFI_MAX_SSID_STRLEN 31
|
||||||
#define WIFI_MAX_PASSWORD_STRLEN 64
|
#define WIFI_MAX_PASSWORD_STRLEN 64
|
||||||
@ -19,6 +19,7 @@
|
|||||||
#define MQTT_MAX_PASSWORD_STRLEN 32
|
#define MQTT_MAX_PASSWORD_STRLEN 32
|
||||||
#define MQTT_MAX_TOPIC_STRLEN 32
|
#define MQTT_MAX_TOPIC_STRLEN 32
|
||||||
#define MQTT_MAX_LWTVALUE_STRLEN 20
|
#define MQTT_MAX_LWTVALUE_STRLEN 20
|
||||||
|
#define MQTT_MAX_ROOT_CA_CERT_STRLEN 2048
|
||||||
|
|
||||||
#define INV_MAX_NAME_STRLEN 31
|
#define INV_MAX_NAME_STRLEN 31
|
||||||
#define INV_MAX_COUNT 10
|
#define INV_MAX_COUNT 10
|
||||||
@ -70,6 +71,8 @@ struct CONFIG_T {
|
|||||||
bool Mqtt_Hass_Retain;
|
bool Mqtt_Hass_Retain;
|
||||||
char Mqtt_Hass_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
char Mqtt_Hass_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
|
||||||
bool Mqtt_Hass_IndividualPanels;
|
bool Mqtt_Hass_IndividualPanels;
|
||||||
|
bool Mqtt_Tls;
|
||||||
|
char Mqtt_RootCaCert[MQTT_MAX_ROOT_CA_CERT_STRLEN + 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigurationClass {
|
class ConfigurationClass {
|
||||||
|
|||||||
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <AsyncMqttClient.h>
|
|
||||||
#include <Ticker.h>
|
#include <Ticker.h>
|
||||||
|
#include <espMqttClient.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class MqttSettingsClass {
|
class MqttSettingsClass {
|
||||||
@ -21,13 +21,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
void NetworkEvent(network_event event);
|
void NetworkEvent(network_event event);
|
||||||
|
|
||||||
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
|
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
|
||||||
void onMqttConnect(bool sessionPresent);
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
|
||||||
void performConnect();
|
void performConnect();
|
||||||
void performDisconnect();
|
void performDisconnect();
|
||||||
|
|
||||||
AsyncMqttClient mqttClient;
|
void createMqttClientObject();
|
||||||
|
|
||||||
|
MqttClient* mqttClient = nullptr;
|
||||||
String clientId;
|
String clientId;
|
||||||
String willTopic;
|
String willTopic;
|
||||||
Ticker mqttReconnectTimer;
|
Ticker mqttReconnectTimer;
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
|
|
||||||
|
#define MQTT_JSON_DOC_SIZE 3072
|
||||||
|
|
||||||
class WebApiMqttClass {
|
class WebApiMqttClass {
|
||||||
public:
|
public:
|
||||||
void init(AsyncWebServer* server);
|
void init(AsyncWebServer* server);
|
||||||
@ -12,6 +14,7 @@ private:
|
|||||||
void onMqttStatus(AsyncWebServerRequest* request);
|
void onMqttStatus(AsyncWebServerRequest* request);
|
||||||
void onMqttAdminGet(AsyncWebServerRequest* request);
|
void onMqttAdminGet(AsyncWebServerRequest* request);
|
||||||
void onMqttAdminPost(AsyncWebServerRequest* request);
|
void onMqttAdminPost(AsyncWebServerRequest* request);
|
||||||
|
String getRootCaCertInfo(char* cert);
|
||||||
|
|
||||||
AsyncWebServer* _server;
|
AsyncWebServer* _server;
|
||||||
};
|
};
|
||||||
@ -29,6 +29,39 @@
|
|||||||
#define MQTT_PASSWORD ""
|
#define MQTT_PASSWORD ""
|
||||||
#define MQTT_TOPIC "solar/"
|
#define MQTT_TOPIC "solar/"
|
||||||
#define MQTT_RETAIN true
|
#define MQTT_RETAIN true
|
||||||
|
#define MQTT_TLS false
|
||||||
|
// ISRG_Root_X1.crt -- Root CA for Letsencrypt
|
||||||
|
#define MQTT_ROOT_CA_CERT "-----BEGIN CERTIFICATE-----\n" \
|
||||||
|
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
|
||||||
|
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
|
||||||
|
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
|
||||||
|
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
|
||||||
|
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
|
||||||
|
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \
|
||||||
|
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \
|
||||||
|
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \
|
||||||
|
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \
|
||||||
|
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \
|
||||||
|
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \
|
||||||
|
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \
|
||||||
|
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \
|
||||||
|
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \
|
||||||
|
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \
|
||||||
|
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \
|
||||||
|
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \
|
||||||
|
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \
|
||||||
|
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \
|
||||||
|
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \
|
||||||
|
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \
|
||||||
|
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \
|
||||||
|
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \
|
||||||
|
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \
|
||||||
|
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \
|
||||||
|
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \
|
||||||
|
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \
|
||||||
|
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \
|
||||||
|
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \
|
||||||
|
"-----END CERTIFICATE-----\n"
|
||||||
#define MQTT_LWT_TOPIC "dtu/status"
|
#define MQTT_LWT_TOPIC "dtu/status"
|
||||||
#define MQTT_LWT_ONLINE "online"
|
#define MQTT_LWT_ONLINE "online"
|
||||||
#define MQTT_LWT_OFFLINE "offline"
|
#define MQTT_LWT_OFFLINE "offline"
|
||||||
|
|||||||
@ -22,7 +22,7 @@ build_flags =
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
||||||
bblanchon/ArduinoJson @ ^6.19.4
|
bblanchon/ArduinoJson @ ^6.19.4
|
||||||
https://github.com/marvinroger/async-mqtt-client.git
|
https://github.com/bertmelis/espMqttClient.git
|
||||||
nrf24/RF24 @ ^1.4.2
|
nrf24/RF24 @ ^1.4.2
|
||||||
|
|
||||||
extra_scripts =
|
extra_scripts =
|
||||||
@ -37,7 +37,6 @@ upload_protocol = esptool
|
|||||||
|
|
||||||
[env:generic]
|
[env:generic]
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
|
|
||||||
monitor_port = COM4
|
monitor_port = COM4
|
||||||
upload_port = COM4
|
upload_port = COM4
|
||||||
|
|
||||||
@ -57,3 +56,18 @@ build_flags = ${env.build_flags}
|
|||||||
|
|
||||||
monitor_port = COM3
|
monitor_port = COM3
|
||||||
upload_port = COM3
|
upload_port = COM3
|
||||||
|
|
||||||
|
|
||||||
|
[env:d1 mini esp32]
|
||||||
|
board = wemos_d1_mini32
|
||||||
|
build_flags =
|
||||||
|
${env.build_flags}
|
||||||
|
-DHOYMILES_PIN_MISO=19
|
||||||
|
-DHOYMILES_PIN_MOSI=23
|
||||||
|
-DHOYMILES_PIN_SCLK=18
|
||||||
|
-DHOYMILES_PIN_IRQ=16
|
||||||
|
-DHOYMILES_PIN_CE=17
|
||||||
|
-DHOYMILES_PIN_CS=5
|
||||||
|
|
||||||
|
monitor_port = /dev/cu.usbserial-01E68DD0
|
||||||
|
upload_port = /dev/cu.usbserial-01E68DD0
|
||||||
|
|||||||
@ -33,6 +33,8 @@ void ConfigurationClass::init()
|
|||||||
strlcpy(config.Mqtt_Password, MQTT_PASSWORD, sizeof(config.Mqtt_Password));
|
strlcpy(config.Mqtt_Password, MQTT_PASSWORD, sizeof(config.Mqtt_Password));
|
||||||
strlcpy(config.Mqtt_Topic, MQTT_TOPIC, sizeof(config.Mqtt_Topic));
|
strlcpy(config.Mqtt_Topic, MQTT_TOPIC, sizeof(config.Mqtt_Topic));
|
||||||
config.Mqtt_Retain = MQTT_RETAIN;
|
config.Mqtt_Retain = MQTT_RETAIN;
|
||||||
|
config.Mqtt_Tls = MQTT_TLS;
|
||||||
|
strlcpy(config.Mqtt_RootCaCert, MQTT_ROOT_CA_CERT, sizeof(config.Mqtt_RootCaCert));
|
||||||
strlcpy(config.Mqtt_LwtTopic, MQTT_LWT_TOPIC, sizeof(config.Mqtt_LwtTopic));
|
strlcpy(config.Mqtt_LwtTopic, MQTT_LWT_TOPIC, sizeof(config.Mqtt_LwtTopic));
|
||||||
strlcpy(config.Mqtt_LwtValue_Online, MQTT_LWT_ONLINE, sizeof(config.Mqtt_LwtValue_Online));
|
strlcpy(config.Mqtt_LwtValue_Online, MQTT_LWT_ONLINE, sizeof(config.Mqtt_LwtValue_Online));
|
||||||
strlcpy(config.Mqtt_LwtValue_Offline, MQTT_LWT_OFFLINE, sizeof(config.Mqtt_LwtValue_Offline));
|
strlcpy(config.Mqtt_LwtValue_Offline, MQTT_LWT_OFFLINE, sizeof(config.Mqtt_LwtValue_Offline));
|
||||||
@ -140,6 +142,11 @@ void ConfigurationClass::migrate()
|
|||||||
config.Mqtt_Hass_IndividualPanels = MQTT_HASS_INDIVIDUALPANELS;
|
config.Mqtt_Hass_IndividualPanels = MQTT_HASS_INDIVIDUALPANELS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.Cfg_Version < 0x00011300) {
|
||||||
|
config.Mqtt_Tls = MQTT_TLS;
|
||||||
|
strlcpy(config.Mqtt_RootCaCert, MQTT_ROOT_CA_CERT, sizeof(config.Mqtt_RootCaCert));
|
||||||
|
}
|
||||||
|
|
||||||
config.Cfg_Version = CONFIG_VERSION;
|
config.Cfg_Version = CONFIG_VERSION;
|
||||||
write();
|
write();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,11 @@
|
|||||||
#include "MqttSettings.h"
|
#include "MqttSettings.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "NetworkSettings.h"
|
#include "NetworkSettings.h"
|
||||||
#include <AsyncMqttClient.h>
|
#include <MqttClientSetup.h>
|
||||||
#include <Ticker.h>
|
#include <Ticker.h>
|
||||||
|
#include <espMqttClient.h>
|
||||||
|
|
||||||
MqttSettingsClass::MqttSettingsClass()
|
MqttSettingsClass::MqttSettingsClass()
|
||||||
: mqttClient()
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,10 +34,33 @@ void MqttSettingsClass::onMqttConnect(bool sessionPresent)
|
|||||||
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Online);
|
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Online);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
|
void MqttSettingsClass::onMqttDisconnect(espMqttClientTypes::DisconnectReason reason)
|
||||||
{
|
{
|
||||||
Serial.println(F("Disconnected from MQTT."));
|
Serial.println(F("Disconnected from MQTT."));
|
||||||
|
|
||||||
|
Serial.print(F("Disconnect reason:"));
|
||||||
|
switch (reason) {
|
||||||
|
case espMqttClientTypes::DisconnectReason::TCP_DISCONNECTED:
|
||||||
|
Serial.println(F("TCP_DISCONNECTED"));
|
||||||
|
break;
|
||||||
|
case espMqttClientTypes::DisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION:
|
||||||
|
Serial.println(F("MQTT_UNACCEPTABLE_PROTOCOL_VERSION"));
|
||||||
|
break;
|
||||||
|
case espMqttClientTypes::DisconnectReason::MQTT_IDENTIFIER_REJECTED:
|
||||||
|
Serial.println(F("MQTT_IDENTIFIER_REJECTED"));
|
||||||
|
break;
|
||||||
|
case espMqttClientTypes::DisconnectReason::MQTT_SERVER_UNAVAILABLE:
|
||||||
|
Serial.println(F("MQTT_SERVER_UNAVAILABLE"));
|
||||||
|
break;
|
||||||
|
case espMqttClientTypes::DisconnectReason::MQTT_MALFORMED_CREDENTIALS:
|
||||||
|
Serial.println(F("MQTT_MALFORMED_CREDENTIALS"));
|
||||||
|
break;
|
||||||
|
case espMqttClientTypes::DisconnectReason::MQTT_NOT_AUTHORIZED:
|
||||||
|
Serial.println(F("MQTT_NOT_AUTHORIZED"));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Serial.println(F("Unknown"));
|
||||||
|
}
|
||||||
mqttReconnectTimer.once(
|
mqttReconnectTimer.once(
|
||||||
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
|
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
|
||||||
}
|
}
|
||||||
@ -45,18 +68,28 @@ void MqttSettingsClass::onMqttDisconnect(AsyncMqttClientDisconnectReason reason)
|
|||||||
void MqttSettingsClass::performConnect()
|
void MqttSettingsClass::performConnect()
|
||||||
{
|
{
|
||||||
if (NetworkSettings.isConnected() && Configuration.get().Mqtt_Enabled) {
|
if (NetworkSettings.isConnected() && Configuration.get().Mqtt_Enabled) {
|
||||||
|
using namespace std::placeholders;
|
||||||
Serial.println(F("Connecting to MQTT..."));
|
Serial.println(F("Connecting to MQTT..."));
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
mqttClient.setServer(config.Mqtt_Hostname, config.Mqtt_Port);
|
|
||||||
mqttClient.setCredentials(config.Mqtt_Username, config.Mqtt_Password);
|
|
||||||
|
|
||||||
willTopic = getPrefix() + config.Mqtt_LwtTopic;
|
willTopic = getPrefix() + config.Mqtt_LwtTopic;
|
||||||
mqttClient.setWill(willTopic.c_str(), 2, config.Mqtt_Retain, config.Mqtt_LwtValue_Offline);
|
|
||||||
|
|
||||||
clientId = NetworkSettings.getApName();
|
clientId = NetworkSettings.getApName();
|
||||||
mqttClient.setClientId(clientId.c_str());
|
if (config.Mqtt_Tls) {
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->setCACert(config.Mqtt_RootCaCert);
|
||||||
mqttClient.connect();
|
static_cast<espMqttClientSecure*>(mqttClient)->setServer(config.Mqtt_Hostname, config.Mqtt_Port);
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->setCredentials(config.Mqtt_Username, config.Mqtt_Password);
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->setWill(willTopic.c_str(), 2, config.Mqtt_Retain, config.Mqtt_LwtValue_Offline);
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->setClientId(clientId.c_str());
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
|
||||||
|
static_cast<espMqttClientSecure*>(mqttClient)->onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1));
|
||||||
|
} else {
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->setServer(config.Mqtt_Hostname, config.Mqtt_Port);
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->setCredentials(config.Mqtt_Username, config.Mqtt_Password);
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->setWill(willTopic.c_str(), 2, config.Mqtt_Retain, config.Mqtt_LwtValue_Offline);
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->setClientId(clientId.c_str());
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
|
||||||
|
static_cast<espMqttClient*>(mqttClient)->onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1));
|
||||||
|
}
|
||||||
|
mqttClient->connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,20 +97,22 @@ void MqttSettingsClass::performDisconnect()
|
|||||||
{
|
{
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Offline);
|
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Offline);
|
||||||
mqttClient.disconnect();
|
mqttClient->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::performReconnect()
|
void MqttSettingsClass::performReconnect()
|
||||||
{
|
{
|
||||||
performDisconnect();
|
performDisconnect();
|
||||||
|
|
||||||
|
createMqttClientObject();
|
||||||
|
|
||||||
mqttReconnectTimer.once(
|
mqttReconnectTimer.once(
|
||||||
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
|
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MqttSettingsClass::getConnected()
|
bool MqttSettingsClass::getConnected()
|
||||||
{
|
{
|
||||||
return mqttClient.connected();
|
return mqttClient->connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
String MqttSettingsClass::getPrefix()
|
String MqttSettingsClass::getPrefix()
|
||||||
@ -89,14 +124,14 @@ void MqttSettingsClass::publish(String subtopic, String payload)
|
|||||||
{
|
{
|
||||||
String topic = getPrefix();
|
String topic = getPrefix();
|
||||||
topic += subtopic;
|
topic += subtopic;
|
||||||
mqttClient.publish(topic.c_str(), 0, Configuration.get().Mqtt_Retain, payload.c_str());
|
mqttClient->publish(topic.c_str(), 0, Configuration.get().Mqtt_Retain, payload.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::publishHass(String subtopic, String payload)
|
void MqttSettingsClass::publishHass(String subtopic, String payload)
|
||||||
{
|
{
|
||||||
String topic = Configuration.get().Mqtt_Hass_Topic;
|
String topic = Configuration.get().Mqtt_Hass_Topic;
|
||||||
topic += subtopic;
|
topic += subtopic;
|
||||||
mqttClient.publish(topic.c_str(), 0, Configuration.get().Mqtt_Hass_Retain, payload.c_str());
|
mqttClient->publish(topic.c_str(), 0, Configuration.get().Mqtt_Hass_Retain, payload.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttSettingsClass::init()
|
void MqttSettingsClass::init()
|
||||||
@ -104,8 +139,19 @@ void MqttSettingsClass::init()
|
|||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
NetworkSettings.onEvent(std::bind(&MqttSettingsClass::NetworkEvent, this, _1));
|
NetworkSettings.onEvent(std::bind(&MqttSettingsClass::NetworkEvent, this, _1));
|
||||||
|
|
||||||
mqttClient.onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
|
createMqttClientObject();
|
||||||
mqttClient.onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1));
|
}
|
||||||
|
|
||||||
|
void MqttSettingsClass::createMqttClientObject()
|
||||||
|
{
|
||||||
|
if (mqttClient != nullptr)
|
||||||
|
delete mqttClient;
|
||||||
|
CONFIG_T& config = Configuration.get();
|
||||||
|
if (config.Mqtt_Tls) {
|
||||||
|
mqttClient = static_cast<MqttClient*>(new espMqttClientSecure);
|
||||||
|
} else {
|
||||||
|
mqttClient = static_cast<MqttClient*>(new espMqttClient);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MqttSettingsClass MqttSettings;
|
MqttSettingsClass MqttSettings;
|
||||||
@ -27,7 +27,7 @@ void WebApiMqttClass::loop()
|
|||||||
|
|
||||||
void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
@ -38,6 +38,8 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
|||||||
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
||||||
root[F("mqtt_connected")] = MqttSettings.getConnected();
|
root[F("mqtt_connected")] = MqttSettings.getConnected();
|
||||||
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
||||||
|
root[F("mqtt_tls")] = config.Mqtt_Tls;
|
||||||
|
root[F("mqtt_root_ca_cert_info")] = getRootCaCertInfo(config.Mqtt_RootCaCert);
|
||||||
root[F("mqtt_lwt_topic")] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
|
root[F("mqtt_lwt_topic")] = String(config.Mqtt_Topic) + config.Mqtt_LwtTopic;
|
||||||
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
|
root[F("mqtt_publish_interval")] = config.Mqtt_PublishInterval;
|
||||||
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
|
root[F("mqtt_hass_enabled")] = config.Mqtt_Hass_Enabled;
|
||||||
@ -51,7 +53,7 @@ void WebApiMqttClass::onMqttStatus(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject root = response->getRoot();
|
JsonObject root = response->getRoot();
|
||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
|
|
||||||
@ -62,6 +64,8 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
|||||||
root[F("mqtt_password")] = config.Mqtt_Password;
|
root[F("mqtt_password")] = config.Mqtt_Password;
|
||||||
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
root[F("mqtt_topic")] = config.Mqtt_Topic;
|
||||||
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
root[F("mqtt_retain")] = config.Mqtt_Retain;
|
||||||
|
root[F("mqtt_tls")] = config.Mqtt_Tls;
|
||||||
|
root[F("mqtt_root_ca_cert")] = config.Mqtt_RootCaCert;
|
||||||
root[F("mqtt_lwt_topic")] = config.Mqtt_LwtTopic;
|
root[F("mqtt_lwt_topic")] = config.Mqtt_LwtTopic;
|
||||||
root[F("mqtt_lwt_online")] = config.Mqtt_LwtValue_Online;
|
root[F("mqtt_lwt_online")] = config.Mqtt_LwtValue_Online;
|
||||||
root[F("mqtt_lwt_offline")] = config.Mqtt_LwtValue_Offline;
|
root[F("mqtt_lwt_offline")] = config.Mqtt_LwtValue_Offline;
|
||||||
@ -77,7 +81,7 @@ void WebApiMqttClass::onMqttAdminGet(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
||||||
{
|
{
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse();
|
AsyncJsonResponse* response = new AsyncJsonResponse(false, MQTT_JSON_DOC_SIZE);
|
||||||
JsonObject retMsg = response->getRoot();
|
JsonObject retMsg = response->getRoot();
|
||||||
retMsg[F("type")] = F("warning");
|
retMsg[F("type")] = F("warning");
|
||||||
|
|
||||||
@ -90,14 +94,14 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
String json = request->getParam("data", true)->value();
|
String json = request->getParam("data", true)->value();
|
||||||
|
|
||||||
if (json.length() > 1024) {
|
if (json.length() > MQTT_JSON_DOC_SIZE) {
|
||||||
retMsg[F("message")] = F("Data too large!");
|
retMsg[F("message")] = F("Data too large!");
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicJsonDocument root(1024);
|
DynamicJsonDocument root(MQTT_JSON_DOC_SIZE);
|
||||||
DeserializationError error = deserializeJson(root, json);
|
DeserializationError error = deserializeJson(root, json);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -107,7 +111,7 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(root.containsKey("mqtt_enabled") && root.containsKey("mqtt_hostname") && root.containsKey("mqtt_port") && root.containsKey("mqtt_username") && root.containsKey("mqtt_password") && root.containsKey("mqtt_topic") && root.containsKey("mqtt_retain") && root.containsKey("mqtt_lwt_topic") && root.containsKey("mqtt_lwt_online") && root.containsKey("mqtt_lwt_offline") && root.containsKey("mqtt_publish_interval") && root.containsKey("mqtt_hass_enabled") && root.containsKey("mqtt_hass_retain") && root.containsKey("mqtt_hass_topic") && root.containsKey("mqtt_hass_individualpanels"))) {
|
if (!(root.containsKey("mqtt_enabled") && root.containsKey("mqtt_hostname") && root.containsKey("mqtt_port") && root.containsKey("mqtt_username") && root.containsKey("mqtt_password") && root.containsKey("mqtt_topic") && root.containsKey("mqtt_retain") && root.containsKey("mqtt_tls") && root.containsKey("mqtt_lwt_topic") && root.containsKey("mqtt_lwt_online") && root.containsKey("mqtt_lwt_offline") && root.containsKey("mqtt_publish_interval") && root.containsKey("mqtt_hass_enabled") && root.containsKey("mqtt_hass_retain") && root.containsKey("mqtt_hass_topic") && root.containsKey("mqtt_hass_individualpanels"))) {
|
||||||
retMsg[F("message")] = F("Values are missing!");
|
retMsg[F("message")] = F("Values are missing!");
|
||||||
response->setLength();
|
response->setLength();
|
||||||
request->send(response);
|
request->send(response);
|
||||||
@ -155,6 +159,13 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root[F("mqtt_root_ca_cert")].as<String>().length() > MQTT_MAX_ROOT_CA_CERT_STRLEN) {
|
||||||
|
retMsg[F("message")] = F("Certificate must not longer then " STR(MQTT_MAX_ROOT_CA_CERT_STRLEN) " characters!");
|
||||||
|
response->setLength();
|
||||||
|
request->send(response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (root[F("mqtt_lwt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
if (root[F("mqtt_lwt_topic")].as<String>().length() > MQTT_MAX_TOPIC_STRLEN) {
|
||||||
retMsg[F("message")] = F("LWT topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!");
|
retMsg[F("message")] = F("LWT topic must not longer then " STR(MQTT_MAX_TOPIC_STRLEN) " characters!");
|
||||||
response->setLength();
|
response->setLength();
|
||||||
@ -210,6 +221,8 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
CONFIG_T& config = Configuration.get();
|
CONFIG_T& config = Configuration.get();
|
||||||
config.Mqtt_Enabled = root[F("mqtt_enabled")].as<bool>();
|
config.Mqtt_Enabled = root[F("mqtt_enabled")].as<bool>();
|
||||||
config.Mqtt_Retain = root[F("mqtt_retain")].as<bool>();
|
config.Mqtt_Retain = root[F("mqtt_retain")].as<bool>();
|
||||||
|
config.Mqtt_Tls = root[F("mqtt_tls")].as<bool>();
|
||||||
|
strcpy(config.Mqtt_RootCaCert, root[F("mqtt_root_ca_cert")].as<String>().c_str());
|
||||||
config.Mqtt_Port = root[F("mqtt_port")].as<uint>();
|
config.Mqtt_Port = root[F("mqtt_port")].as<uint>();
|
||||||
strcpy(config.Mqtt_Hostname, root[F("mqtt_hostname")].as<String>().c_str());
|
strcpy(config.Mqtt_Hostname, root[F("mqtt_hostname")].as<String>().c_str());
|
||||||
strcpy(config.Mqtt_Username, root[F("mqtt_username")].as<String>().c_str());
|
strcpy(config.Mqtt_Username, root[F("mqtt_username")].as<String>().c_str());
|
||||||
@ -234,3 +247,24 @@ void WebApiMqttClass::onMqttAdminPost(AsyncWebServerRequest* request)
|
|||||||
MqttSettings.performReconnect();
|
MqttSettings.performReconnect();
|
||||||
MqttHassPublishing.forceUpdate();
|
MqttHassPublishing.forceUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String WebApiMqttClass::getRootCaCertInfo(char* cert)
|
||||||
|
{
|
||||||
|
char rootCaCertInfo[1024] = "";
|
||||||
|
|
||||||
|
mbedtls_x509_crt global_cacert;
|
||||||
|
|
||||||
|
strcpy(rootCaCertInfo, "Can't parse root ca");
|
||||||
|
|
||||||
|
mbedtls_x509_crt_init(&global_cacert);
|
||||||
|
int ret = mbedtls_x509_crt_parse(&global_cacert, const_cast<unsigned char*>((unsigned char*)cert), 1 + strlen(cert));
|
||||||
|
if (ret < 0) {
|
||||||
|
sprintf(rootCaCertInfo, "Can't parse root ca: mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
|
||||||
|
mbedtls_x509_crt_free(&global_cacert);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
mbedtls_x509_crt_info(rootCaCertInfo, sizeof(rootCaCertInfo) - 1, "", &global_cacert);
|
||||||
|
mbedtls_x509_crt_free(&global_cacert);
|
||||||
|
|
||||||
|
return rootCaCertInfo;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
<div class="row mb-3" v-show="mqttConfigList.mqtt_enabled">
|
<div class="row mb-3" v-show="mqttConfigList.mqtt_enabled">
|
||||||
<label class="col-sm-4 form-check-label" for="inputMqttHass">Enable Home Assistant MQTT Auto
|
<label class="col-sm-4 form-check-label" for="inputMqttHass">Enable Home Assistant MQTT Auto
|
||||||
Discovery</label>
|
Discovery</label>
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" id="inputMqttHass"
|
<input class="form-check-input" type="checkbox" id="inputMqttHass"
|
||||||
@ -111,6 +111,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label class="col-sm-2 form-check-label" for="inputTls">Enable TLS</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="form-check form-switch">
|
||||||
|
<input class="form-check-input" type="checkbox" id="inputTls"
|
||||||
|
v-model="mqttConfigList.mqtt_tls" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3" v-show="mqttConfigList.mqtt_tls">
|
||||||
|
<label for="inputCert" class="col-sm-2 col-form-label">CA-Root-Certificate (default
|
||||||
|
Letsencrypt):</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea class="form-control" id="inputCert" maxlength="2048" rows="10"
|
||||||
|
placeholder="Root CA Certificate from Letsencrypt"
|
||||||
|
v-model="mqttConfigList.mqtt_root_ca_cert">
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -174,7 +196,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label class="col-sm-2 form-check-label" for="inputIndividualPanels">Individual Panels:</label>
|
<label class="col-sm-2 form-check-label" for="inputIndividualPanels">Individual
|
||||||
|
Panels:</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input class="form-check-input" type="checkbox" id="inputIndividualPanels"
|
<input class="form-check-input" type="checkbox" id="inputIndividualPanels"
|
||||||
@ -212,6 +235,8 @@ export default defineComponent({
|
|||||||
mqtt_topic: "",
|
mqtt_topic: "",
|
||||||
mqtt_publish_interval: 0,
|
mqtt_publish_interval: 0,
|
||||||
mqtt_retain: false,
|
mqtt_retain: false,
|
||||||
|
mqtt_tls: false,
|
||||||
|
mqtt_root_ca_cert: "",
|
||||||
mqtt_lwt_topic: "",
|
mqtt_lwt_topic: "",
|
||||||
mqtt_lwt_online: "",
|
mqtt_lwt_online: "",
|
||||||
mqtt_lwt_offline: "",
|
mqtt_lwt_offline: "",
|
||||||
|
|||||||
@ -57,6 +57,20 @@
|
|||||||
<span v-else>disabled</span>
|
<span v-else>disabled</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>TLS</th>
|
||||||
|
<td class="badge" :class="{
|
||||||
|
'bg-danger': !mqttDataList.mqtt_tls,
|
||||||
|
'bg-success': mqttDataList.mqtt_tls,
|
||||||
|
}">
|
||||||
|
<span v-if="mqttDataList.mqtt_tls">enabled</span>
|
||||||
|
<span v-else>disabled</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-show="mqttDataList.mqtt_tls">
|
||||||
|
<th>Root CA Certifcate Info</th>
|
||||||
|
<td>{{ mqttDataList.mqtt_root_ca_cert_info }}</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -149,6 +163,8 @@ export default defineComponent({
|
|||||||
mqtt_topic: "",
|
mqtt_topic: "",
|
||||||
mqtt_publish_interval: 0,
|
mqtt_publish_interval: 0,
|
||||||
mqtt_retain: false,
|
mqtt_retain: false,
|
||||||
|
mqtt_tls: false,
|
||||||
|
mqtt_root_ca_cert_info: "",
|
||||||
mqtt_connected: false,
|
mqtt_connected: false,
|
||||||
mqtt_hass_enabled: false,
|
mqtt_hass_enabled: false,
|
||||||
mqtt_hass_retain: false,
|
mqtt_hass_retain: false,
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user