Skip to content

Commit

Permalink
Merge branch 'release/2.3.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Rüttgers committed Mar 14, 2023
2 parents 349826d + dd3be15 commit dee3e38
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 96 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [2.3.0] - 2023-03-14
### Changed
- Upgraded IotWebConf to version 3
### Fixed
- [Issue #47](https://github.com/mruettgers/SMLReader/issues/47), Broken MQTT reconnect after WiFi disconnect

## [2.2.1] - 2022-03-17
### Changed
Expand Down
10 changes: 5 additions & 5 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
; https://docs.platformio.org/page/projectconf.html

[common]
platform = espressif8266@2.3.1
platform = espressif8266@^2.4.2
lib_deps =
git+https://github.com/volkszaehler/libsml
EspSoftwareSerial
MicroDebug
IotWebConf@^2.3.3
ESPAsyncTCP
git+https://github.com/philbowles/PangolinMQTT.git#v1.0.0
IotWebConf@3.2.0
ESP AsyncTCP
AsyncMqttClient
jled

env_default = d1_mini
Expand Down Expand Up @@ -47,7 +47,7 @@ board = d1_mini
framework = arduino
lib_deps = ${common.lib_deps}
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags} -DSERIAL_DEBUG=true -DSERIAL_DEBUG_VERBOSE=true
build_flags = ${common.build_flags} -DSERIAL_DEBUG=true -DSERIAL_DEBUG_VERBOSE=false
upload_port = /dev/ttyUSB0
monitor_port = /dev/ttyUSB0
monitor_speed = 115200
89 changes: 26 additions & 63 deletions src/MqttPublisher.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
#include "config.h"
#include "debug.h"
#include <Ticker.h>
#include <PangolinMQTT.h>

#include <AsyncMqttClient.h>
#include <string.h>
#include <sml/sml_file.h>
#include <Ticker.h>

#define MQTT_RECONNECT_DELAY 5
#define MQTT_LWT_TOPIC "LWT"
Expand Down Expand Up @@ -35,18 +35,25 @@ class MqttPublisher
config = _config;
uint8_t lastCharOfTopic = strlen(config.topic) - 1;
baseTopic = String(config.topic) + (lastCharOfTopic >= 0 && config.topic[lastCharOfTopic] == '/' ? "" : "/");

lastWillTopic = String(baseTopic + MQTT_LWT_TOPIC);

DEBUG(F("MQTT: Setting up..."));
DEBUG(F("MQTT: Server: %s"),config.server);
DEBUG(F("MQTT: Port: %d"),atoi(config.port));
DEBUG(F("MQTT: Username: %s"),config.username);
DEBUG(F("MQTT: Password: <hidden>"));
DEBUG(F("MQTT: Topic: %s"), baseTopic.c_str());

client.setServer(const_cast<const char *>(config.server), atoi(config.port));
if (strlen(config.username) > 0 || strlen(config.password) > 0)
{
client.setCredentials(config.username, config.password);
}

client.setCleanSession(true);
client.setWill(String(baseTopic + MQTT_LWT_TOPIC).c_str(), MQTT_LWT_QOS, MQTT_LWT_RETAIN, MQTT_LWT_PAYLOAD_OFFLINE);
client.setWill(lastWillTopic.c_str(), MQTT_LWT_QOS, MQTT_LWT_RETAIN, MQTT_LWT_PAYLOAD_OFFLINE);
client.setKeepAlive(MQTT_RECONNECT_DELAY * 3);

this->registerHandlers();

}

void debug(const char *message)
Expand Down Expand Up @@ -128,6 +135,7 @@ class MqttPublisher
DEBUG(F("MQTT: Connecting to broker..."));
client.connect();
}

void disconnect()
{
if (!this->connected)
Expand All @@ -137,15 +145,16 @@ class MqttPublisher
}
DEBUG(F("MQTT: Disconnecting from broker..."));
client.disconnect();
this->reconnectTimer.detach();
}

private:
bool connected = false;
MqttConfig config;
WiFiClient net;
PangolinMQTT client;
AsyncMqttClient client;
Ticker reconnectTimer;
String baseTopic;
String lastWillTopic;

void publish(const String &topic, const String &payload, uint8_t qos=0, bool retain=false)
{
Expand All @@ -167,77 +176,31 @@ class MqttPublisher
{
DEBUG(F("MQTT: Publishing to %s:"), topic);
DEBUG(F("%s\n"), payload);
client.publish(topic, payload, strlen(payload), qos, retain);
client.publish(topic, qos, retain, payload, strlen(payload));
}
}

void registerHandlers()
{

client.onConnect([this](bool sessionPresent) {
this->connected = true;
reconnectTimer.detach();
DEBUG(F("MQTT client connection established."));
this->reconnectTimer.detach();
DEBUG(F("MQTT: Connection established."));
char message[64];
snprintf(message, 64, "Hello from %08X, running SMLReader version %s.", ESP.getChipId(), VERSION);
info(message);
publish(baseTopic + MQTT_LWT_TOPIC, MQTT_LWT_PAYLOAD_ONLINE, MQTT_LWT_QOS, MQTT_LWT_RETAIN);
});
client.onDisconnect([this](int8_t reason) {
client.onDisconnect([this](AsyncMqttClientDisconnectReason reason) {
this->connected = false;
DEBUG("MQTT client disconnected with reason=%d", reason);
DEBUG(F("MQTT: Disconnected. Reason: %d."), reason);
reconnectTimer.attach(MQTT_RECONNECT_DELAY, [this]() {
this->connect();
if (WiFi.isConnected()) {
this->connect();
}
});
});
client.onError([this](uint8_t e, uint32_t info) {
switch (e)
{
case TCP_DISCONNECTED:
// usually because your structure is wrong and you called a function before onMqttConnect
DEBUG(F("MQTT: NOT CONNECTED info=%d"), info);
break;
case MQTT_SERVER_UNAVAILABLE:
// server has gone away - network problem? server crash?
DEBUG(F("MQTT: MQTT_SERVER_UNAVAILABLE info=%d"), info);
break;
case UNRECOVERABLE_CONNECT_FAIL:
// there is something wrong with your connection parameters? IP:port incorrect? user credentials typo'd?
DEBUG(F("MQTT: UNRECOVERABLE_CONNECT_FAIL info=%d"), info);
break;
case TLS_BAD_FINGERPRINT:
DEBUG(F("MQTT: TLS_BAD_FINGERPRINT info=%d"), info);
break;
case SUBSCRIBE_FAIL:
// you tried to subscribe to an invalid topic
DEBUG(F("MQTT: SUBSCRIBE_FAIL info=%d"), info);
break;
case INBOUND_QOS_ACK_FAIL:
DEBUG(F("MQTT: OUTBOUND_QOS_ACK_FAIL id=%d"), info);
break;
case OUTBOUND_QOS_ACK_FAIL:
DEBUG(F("MQTT: OUTBOUND_QOS_ACK_FAIL id=%d"), info);
break;
case INBOUND_PUB_TOO_BIG:
// someone sent you a p[acket that this MCU does not have enough FLASH to handle
DEBUG(F("MQTT: INBOUND_PUB_TOO_BIG size=%d Max=%d"), info, client.getMaxPayloadSize());
break;
case OUTBOUND_PUB_TOO_BIG:
// you tried to send a packet that this MCU does not have enough FLASH to handle
DEBUG(F("MQTT: OUTBOUND_PUB_TOO_BIG size=%d Max=%d"), info, client.getMaxPayloadSize());
break;
case BOGUS_PACKET: // Your server sent a control packet type unknown to MQTT 3.1.1
// 99.99% unlikely to ever happen, but this message is better than a crash, non?
DEBUG(F("MQTT: BOGUS_PACKET info=%02x"), info);
break;
case X_INVALID_LENGTH: // An x function rcvd a msg with an unexpected length: probale data corruption or malicious msg
// 99.99% unlikely to ever happen, but this message is better than a crash, non?
DEBUG(F("MQTT: X_INVALID_LENGTH info=%02x"), info);
break;
default:
DEBUG(F("MQTT: UNKNOWN ERROR: %u extra info %d"), e, info);
break;
}
});
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "Arduino.h"
#include "Sensor.h"

const char *VERSION = "2.2.1";
const char *VERSION = "2.3.0";

// Modifying the config version will probably cause a loss of the existig configuration.
// Be careful!
Expand Down
60 changes: 34 additions & 26 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,32 @@
#include "MqttPublisher.h"
#include "EEPROM.h"
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>

std::list<Sensor*> *sensors = new std::list<Sensor*>();
std::list<Sensor *> *sensors = new std::list<Sensor *>();

void wifiConnected();
void configSaved();

DNSServer dnsServer;
WebServer server(80);
HTTPUpdateServer httpUpdater;
ESP8266HTTPUpdateServer httpUpdater;
WiFiClient net;

MqttConfig mqttConfig;
MqttPublisher publisher;

IotWebConf iotWebConf(WIFI_AP_SSID, &dnsServer, &server, WIFI_AP_DEFAULT_PASSWORD, CONFIG_VERSION);
IotWebConfParameter params[] = {
IotWebConfParameter("MQTT server", "mqttServer", mqttConfig.server, sizeof(mqttConfig.server), "text", NULL, mqttConfig.server, NULL, true),
IotWebConfParameter("MQTT port", "mqttPort", mqttConfig.port, sizeof(mqttConfig.port), "text", NULL, mqttConfig.port, NULL, true),
IotWebConfParameter("MQTT username", "mqttUsername", mqttConfig.username, sizeof(mqttConfig.username), "text", NULL, mqttConfig.username, NULL, true),
IotWebConfParameter("MQTT password", "mqttPassword", mqttConfig.password, sizeof(mqttConfig.password), "password", NULL, mqttConfig.password, NULL, true),
IotWebConfParameter("MQTT topic", "mqttTopic", mqttConfig.topic, sizeof(mqttConfig.topic), "text", NULL, mqttConfig.topic, NULL, true)};

boolean needReset = false;
boolean connected = false;
iotwebconf::TextParameter mqttServerParam = iotwebconf::TextParameter("MQTT server", "mqttServer", mqttConfig.server, sizeof(mqttConfig.server), nullptr, mqttConfig.server);
iotwebconf::NumberParameter mqttPortParam = iotwebconf::NumberParameter("MQTT port", "mqttPort", mqttConfig.port, sizeof(mqttConfig.port), nullptr, mqttConfig.port);
iotwebconf::TextParameter mqttUsernameParam = iotwebconf::TextParameter("MQTT username", "mqttUsername", mqttConfig.username, sizeof(mqttConfig.username), nullptr, mqttConfig.username);
iotwebconf::PasswordParameter mqttPasswordParam = iotwebconf::PasswordParameter("MQTT password", "mqttPassword", mqttConfig.password, sizeof(mqttConfig.password), nullptr, mqttConfig.password);
iotwebconf::TextParameter mqttTopicParam = iotwebconf::TextParameter("MQTT topic", "mqttTopic", mqttConfig.topic, sizeof(mqttConfig.topic), nullptr, mqttConfig.topic);
iotwebconf::ParameterGroup paramGroup = iotwebconf::ParameterGroup("MQTT Settings", "");

boolean needReset = false;

void process_message(byte *buffer, size_t len, Sensor *sensor)
{
Expand All @@ -58,7 +59,7 @@ void setup()

// Setup reading heads
DEBUG("Setting up %d configured sensors...", NUM_OF_SENSORS);
const SensorConfig *config = SENSOR_CONFIGS;
const SensorConfig *config = SENSOR_CONFIGS;
for (uint8_t i = 0; i < NUM_OF_SENSORS; i++, config++)
{
Sensor *sensor = new Sensor(config, process_message);
Expand All @@ -70,34 +71,42 @@ void setup()
// Setup WiFi and config stuff
DEBUG("Setting up WiFi and config stuff.");

for (uint8_t i = 0; i < sizeof(params) / sizeof(params[0]); i++)
{
DEBUG("Adding parameter %s.", params[i].label);
iotWebConf.addParameter(&params[i]);
}
paramGroup.addItem(&mqttServerParam);
paramGroup.addItem(&mqttPortParam);
paramGroup.addItem(&mqttUsernameParam);
paramGroup.addItem(&mqttPasswordParam);
paramGroup.addItem(&mqttTopicParam);

iotWebConf.addParameterGroup(&paramGroup);

iotWebConf.setConfigSavedCallback(&configSaved);
iotWebConf.setWifiConnectionCallback(&wifiConnected);
iotWebConf.setupUpdateServer(&httpUpdater);


WiFi.onStationModeDisconnected([](const WiFiEventStationModeDisconnected& event) {
publisher.disconnect();
});

// -- Define how to handle updateServer calls.
iotWebConf.setupUpdateServer(
[](const char *updatePath)
{ httpUpdater.setup(&server, updatePath); },
[](const char *userName, char *password)
{ httpUpdater.updateCredentials(userName, password); });

boolean validConfig = iotWebConf.init();
if (!validConfig)
{
DEBUG("Missing or invalid config. MQTT publisher disabled.");
MqttConfig defaults;
// Resetting to default values
strcpy(mqttConfig.server, defaults.server);
strcpy(mqttConfig.port, defaults.port);
strcpy(mqttConfig.username, defaults.username);
strcpy(mqttConfig.password, defaults.password);
strcpy(mqttConfig.topic, defaults.topic);
}
else
{
// Setup MQTT publisher
publisher.setup(mqttConfig);
}

server.on("/", [] { iotWebConf.handleConfig(); });
server.on("/", []() { iotWebConf.handleConfig(); });
server.on("/reset", []() { needReset = true; });
server.onNotFound([]() { iotWebConf.handleNotFound(); });

DEBUG("Setup done.");
Expand Down Expand Up @@ -130,6 +139,5 @@ void configSaved()
void wifiConnected()
{
DEBUG("WiFi connection established.");
connected = true;
publisher.connect();
}

0 comments on commit dee3e38

Please sign in to comment.