Skip to content

Commit

Permalink
Add support for MQTT TLS
Browse files Browse the repository at this point in the history
To support TLS its necessary to use another MQTT library.
The new lib is a drop-in replacement for the async-mqtt-client.
  • Loading branch information
helgeerbe authored and tbnobody committed Aug 5, 2022
1 parent 6c088a9 commit 4435fbc
Show file tree
Hide file tree
Showing 12 changed files with 217 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.vscode/settings.json
platformio-device-monitor*.log
5 changes: 4 additions & 1 deletion include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <Arduino.h>

#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_PASSWORD_STRLEN 64
Expand All @@ -19,6 +19,7 @@
#define MQTT_MAX_PASSWORD_STRLEN 32
#define MQTT_MAX_TOPIC_STRLEN 32
#define MQTT_MAX_LWTVALUE_STRLEN 20
#define MQTT_MAX_ROOT_CA_CERT_STRLEN 2048

#define INV_MAX_NAME_STRLEN 31
#define INV_MAX_COUNT 10
Expand Down Expand Up @@ -70,6 +71,8 @@ struct CONFIG_T {
bool Mqtt_Hass_Retain;
char Mqtt_Hass_Topic[MQTT_MAX_TOPIC_STRLEN + 1];
bool Mqtt_Hass_IndividualPanels;
bool Mqtt_Tls;
char Mqtt_RootCaCert[MQTT_MAX_ROOT_CA_CERT_STRLEN + 1];
};

class ConfigurationClass {
Expand Down
8 changes: 5 additions & 3 deletions include/MqttSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

#include "NetworkSettings.h"
#include <Arduino.h>
#include <AsyncMqttClient.h>
#include <Ticker.h>
#include <espMqttClient.h>
#include <memory>

class MqttSettingsClass {
Expand All @@ -21,13 +21,15 @@ class MqttSettingsClass {
private:
void NetworkEvent(network_event event);

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
void onMqttDisconnect(espMqttClientTypes::DisconnectReason reason);
void onMqttConnect(bool sessionPresent);

void performConnect();
void performDisconnect();

AsyncMqttClient mqttClient;
void createMqttClientObject();

MqttClient* mqttClient = nullptr;
String clientId;
String willTopic;
Ticker mqttReconnectTimer;
Expand Down
3 changes: 3 additions & 0 deletions include/WebApi_mqtt.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <ESPAsyncWebServer.h>

#define MQTT_JSON_DOC_SIZE 3072

class WebApiMqttClass {
public:
void init(AsyncWebServer* server);
Expand All @@ -12,6 +14,7 @@ class WebApiMqttClass {
void onMqttStatus(AsyncWebServerRequest* request);
void onMqttAdminGet(AsyncWebServerRequest* request);
void onMqttAdminPost(AsyncWebServerRequest* request);
String getRootCaCertInfo(char* cert);

AsyncWebServer* _server;
};
33 changes: 33 additions & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,39 @@
#define MQTT_PASSWORD ""
#define MQTT_TOPIC "solar/"
#define MQTT_RETAIN true
#define MQTT_TLS false
// ISRG_Root_X1.crt -- Root CA for Letsencrypt
#define MQTT_ROOT_CA_CERT "-----BEGIN CERTIFICATE-----\n" \
"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\n" \
"-----END CERTIFICATE-----\n"
#define MQTT_LWT_TOPIC "dtu/status"
#define MQTT_LWT_ONLINE "online"
#define MQTT_LWT_OFFLINE "offline"
Expand Down
20 changes: 17 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ build_flags =
lib_deps =
https://github.com/me-no-dev/ESPAsyncWebServer.git
bblanchon/ArduinoJson @ ^6.19.4
https://github.com/marvinroger/async-mqtt-client.git
https://github.com/bertmelis/espMqttClient.git
nrf24/RF24 @ ^1.4.2

extra_scripts =
Expand All @@ -37,7 +37,6 @@ upload_protocol = esptool

[env:generic]
board = esp32dev

monitor_port = COM4
upload_port = COM4

Expand All @@ -56,4 +55,19 @@ build_flags = ${env.build_flags}
-DOPENDTU_ETHERNET

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
7 changes: 7 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ void ConfigurationClass::init()
strlcpy(config.Mqtt_Password, MQTT_PASSWORD, sizeof(config.Mqtt_Password));
strlcpy(config.Mqtt_Topic, MQTT_TOPIC, sizeof(config.Mqtt_Topic));
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_LwtValue_Online, MQTT_LWT_ONLINE, sizeof(config.Mqtt_LwtValue_Online));
strlcpy(config.Mqtt_LwtValue_Offline, MQTT_LWT_OFFLINE, sizeof(config.Mqtt_LwtValue_Offline));
Expand Down Expand Up @@ -140,6 +142,11 @@ void ConfigurationClass::migrate()
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;
write();
}
Expand Down
80 changes: 63 additions & 17 deletions src/MqttSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#include "MqttSettings.h"
#include "Configuration.h"
#include "NetworkSettings.h"
#include <AsyncMqttClient.h>
#include <MqttClientSetup.h>
#include <Ticker.h>
#include <espMqttClient.h>

MqttSettingsClass::MqttSettingsClass()
: mqttClient()
{
}

Expand All @@ -34,50 +34,85 @@ void MqttSettingsClass::onMqttConnect(bool sessionPresent)
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.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(
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
}

void MqttSettingsClass::performConnect()
{
if (NetworkSettings.isConnected() && Configuration.get().Mqtt_Enabled) {
using namespace std::placeholders;
Serial.println(F("Connecting to MQTT..."));
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;
mqttClient.setWill(willTopic.c_str(), 2, config.Mqtt_Retain, config.Mqtt_LwtValue_Offline);

clientId = NetworkSettings.getApName();
mqttClient.setClientId(clientId.c_str());

mqttClient.connect();
if (config.Mqtt_Tls) {
static_cast<espMqttClientSecure*>(mqttClient)->setCACert(config.Mqtt_RootCaCert);
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();
}
}

void MqttSettingsClass::performDisconnect()
{
CONFIG_T& config = Configuration.get();
publish(config.Mqtt_LwtTopic, config.Mqtt_LwtValue_Offline);
mqttClient.disconnect();
mqttClient->disconnect();
}

void MqttSettingsClass::performReconnect()
{
performDisconnect();

createMqttClientObject();

mqttReconnectTimer.once(
2, +[](MqttSettingsClass* instance) { instance->performConnect(); }, this);
}

bool MqttSettingsClass::getConnected()
{
return mqttClient.connected();
return mqttClient->connected();
}

String MqttSettingsClass::getPrefix()
Expand All @@ -89,23 +124,34 @@ void MqttSettingsClass::publish(String subtopic, String payload)
{
String topic = getPrefix();
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)
{
String topic = Configuration.get().Mqtt_Hass_Topic;
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()
{
using namespace std::placeholders;
NetworkSettings.onEvent(std::bind(&MqttSettingsClass::NetworkEvent, this, _1));

mqttClient.onConnect(std::bind(&MqttSettingsClass::onMqttConnect, this, _1));
mqttClient.onDisconnect(std::bind(&MqttSettingsClass::onMqttDisconnect, this, _1));
createMqttClientObject();
}

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;
Loading

0 comments on commit 4435fbc

Please sign in to comment.