diff --git a/CHANGELOG.md b/CHANGELOG.md index fc9e57d..a49a812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/platformio.ini b/platformio.ini index d9f6618..2778e55 100644 --- a/platformio.ini +++ b/platformio.ini @@ -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 @@ -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 diff --git a/src/MqttPublisher.h b/src/MqttPublisher.h index 95e2606..26eb6b1 100644 --- a/src/MqttPublisher.h +++ b/src/MqttPublisher.h @@ -4,10 +4,10 @@ #include "config.h" #include "debug.h" #include -#include + +#include #include #include -#include #define MQTT_RECONNECT_DELAY 5 #define MQTT_LWT_TOPIC "LWT" @@ -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: ")); + DEBUG(F("MQTT: Topic: %s"), baseTopic.c_str()); + client.setServer(const_cast(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) @@ -128,6 +135,7 @@ class MqttPublisher DEBUG(F("MQTT: Connecting to broker...")); client.connect(); } + void disconnect() { if (!this->connected) @@ -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) { @@ -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; - } - }); } }; diff --git a/src/config.h b/src/config.h index 12d38f7..8495a57 100644 --- a/src/config.h +++ b/src/config.h @@ -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! diff --git a/src/main.cpp b/src/main.cpp index 7c57792..c6d53c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,31 +7,32 @@ #include "MqttPublisher.h" #include "EEPROM.h" #include +#include +#include -std::list *sensors = new std::list(); +std::list *sensors = new std::list(); 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) { @@ -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); @@ -70,26 +71,33 @@ 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(¶ms[i]); - } + paramGroup.addItem(&mqttServerParam); + paramGroup.addItem(&mqttPortParam); + paramGroup.addItem(&mqttUsernameParam); + paramGroup.addItem(&mqttPasswordParam); + paramGroup.addItem(&mqttTopicParam); + + iotWebConf.addParameterGroup(¶mGroup); + 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 { @@ -97,7 +105,8 @@ void setup() publisher.setup(mqttConfig); } - server.on("/", [] { iotWebConf.handleConfig(); }); + server.on("/", []() { iotWebConf.handleConfig(); }); + server.on("/reset", []() { needReset = true; }); server.onNotFound([]() { iotWebConf.handleNotFound(); }); DEBUG("Setup done."); @@ -130,6 +139,5 @@ void configSaved() void wifiConnected() { DEBUG("WiFi connection established."); - connected = true; publisher.connect(); } \ No newline at end of file