From 2620d05f498afefc4a70e0ea0b70f8fd29367841 Mon Sep 17 00:00:00 2001 From: coolneng Date: Wed, 11 Mar 2026 20:49:38 +0100 Subject: [PATCH] Use a robust asynchronous MQTT client --- include/config.h | 25 ++++++------- include/sensor.h | 10 ++++++ include/wlan.h | 29 ++++++++++----- platformio.ini | 9 ++--- src/config.cpp | 46 ++++++++++++------------ src/main.cpp | 47 +++++++++++-------------- src/sensor.cpp | 13 +++++++ src/wlan.cpp | 92 ++++++++++++++++++++++-------------------------- 8 files changed, 147 insertions(+), 124 deletions(-) create mode 100644 include/sensor.h create mode 100644 src/sensor.cpp diff --git a/include/config.h b/include/config.h index 176e45d..87c5f06 100644 --- a/include/config.h +++ b/include/config.h @@ -1,27 +1,24 @@ #ifndef CONFIG_H_ #define CONFIG_H_ -#include "FS.h" -#include "LittleFS.h" #include typedef struct { - const char *ssid; - const char *psk; - const char *mqtt_host; - const char *mqtt_user; - const char *mqtt_password; - const char *topic; - const char *device_id; - int mqtt_port; - long sleep_time; - int connection_attempts; + const char *ssid; + const char *psk; + const char *mqtt_host; + const char *mqtt_user; + const char *mqtt_password; + const char *topic; + const char *device_id; + int mqtt_port; + unsigned long sleep_time; } Config; -void initialize_config(Config *config, StaticJsonDocument<512> json); +void initialize_config(Config *config, JsonDocument json); bool load_config_file(const char *file_path, Config *config); -long minutes_to_microseconds(int minutes); +long minutes_to_milliseconds(int minutes); #endif // CONFIG_H_ diff --git a/include/sensor.h b/include/sensor.h new file mode 100644 index 0000000..3dc9786 --- /dev/null +++ b/include/sensor.h @@ -0,0 +1,10 @@ +#ifndef SENSOR_H_ +#define SENSOR_H_ + +#include + +void initialize_sensor(DHT &sensor); + +void read_values(DHT &sensor, float *data); + +#endif // SENSOR_H_ diff --git a/include/wlan.h b/include/wlan.h index 063b422..c41f65b 100644 --- a/include/wlan.h +++ b/include/wlan.h @@ -2,15 +2,28 @@ #define WLAN_H #include "config.h" -#include -#include +#include +#include +#include + +static AsyncMqttClient mqtt_client; +static Ticker mqtt_connection_timer, wlan_connection_timer; +extern Config *config; + +void initialize_wlan(); + +void initialize_mqtt(); + +void connect_wlan(); + +void connect_mqtt(); + +void wlan_connection_handler(WiFiEvent_t event); + +void on_mqtt_disconnection(AsyncMqttClientDisconnectReason reason); -void initial_connection(const char *ssid, const char *psk); -void connect_wlan(Config *config); -void connect_mqtt(PubSubClient &client, Config *config); -void disconnect_mqtt(PubSubClient &client, const char *topic); size_t construct_json(float *data, char *buffer, int buffer_size); -void mqtt_transfer(PubSubClient &client, Config *config, float *data); -void enter_deep_sleep(bool wifi_timeout, int sleep_time); + +void mqtt_transfer(float *data); #endif /* WLAN_H */ diff --git a/platformio.ini b/platformio.ini index 5f9dd80..27e6453 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,12 +9,13 @@ ; https://docs.platformio.org/page/projectconf.html [env:d1_mini] -platform = espressif8266 -board = d1_mini +platform = espressif32 +board = wemos_d1_mini32 board_build.filesystem = littlefs framework = arduino +monitor_filters = esp32_exception_decoder lib_deps = adafruit/DHT sensor library@^1.4.4 adafruit/Adafruit Unified Sensor@^1.1.9 - knolleary/PubSubClient@^2.8 - bblanchon/ArduinoJson@^6.21.1 + marvinroger/AsyncMqttClient@^0.9.0 + bblanchon/ArduinoJson@^7.4.1 diff --git a/src/config.cpp b/src/config.cpp index 9f10c59..da52799 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,30 +1,30 @@ #include "config.h" +#include "LittleFS.h" -void initialize_config(Config *config, StaticJsonDocument<512> json) { - config->ssid = strdup(json["ssid"]); - config->psk = strdup(json["psk"]); - config->mqtt_host = strdup(json["mqtt_host"]); - config->mqtt_user = strdup(json["mqtt_user"]); - config->mqtt_password = strdup(json["mqtt_password"]); - config->topic = strdup(json["mqtt_topic"]); - config->device_id = strdup(json["device_id"]); - config->mqtt_port = json["mqtt_port"]; - config->sleep_time = minutes_to_microseconds(json["sleep_time"]); - config->connection_attempts = json["connection_attempts"]; +void initialize_config(Config *config, JsonDocument json) { + config->ssid = strdup(json["ssid"]); + config->psk = strdup(json["psk"]); + config->mqtt_host = strdup(json["mqtt_host"]); + config->mqtt_user = strdup(json["mqtt_user"]); + config->mqtt_password = strdup(json["mqtt_password"]); + config->topic = strdup(json["mqtt_topic"]); + config->device_id = strdup(json["device_id"]); + config->mqtt_port = json["mqtt_port"]; + config->sleep_time = minutes_to_milliseconds(json["sleep_time"]); } bool load_config_file(const char *file_path, Config *config) { - if (!LittleFS.begin()) - return false; - File config_file = LittleFS.open(file_path, "r"); - if (!config_file) - return false; - StaticJsonDocument<512> json; - DeserializationError err = deserializeJson(json, config_file); - if (err) - return false; - initialize_config(config, json); - return true; + if (!LittleFS.begin()) + return false; + File config_file = LittleFS.open(file_path, "r"); + if (!config_file) + return false; + JsonDocument json; + DeserializationError err = deserializeJson(json, config_file); + if (err) + return false; + initialize_config(config, json); + return true; } -long minutes_to_microseconds(int minutes) { return (minutes * 6e7); } +long minutes_to_milliseconds(int minutes) { return (minutes * 6e4); } diff --git a/src/main.cpp b/src/main.cpp index ef9d41d..91acc08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,41 +1,36 @@ #include "config.h" +#include "sensor.h" #include "wlan.h" #include #include -#define DHTTYPE DHT22 -#define DHTPIN 4 -DHT dht(DHTPIN, DHTTYPE); +DHT dht(4, DHT22); -const int fc28_pin = A0; const char *config_file_path = "/config.json"; Config *config; -WiFiClient wifi_client; -PubSubClient mqtt_client(wifi_client); -bool check_valid_value(float value) { - return (!isnan(value) && value >= 0 && value <= 100); -} +float data[2]; +unsigned long previous_millis = 0; void setup() { - Serial.begin(9600); - dht.begin(); - config = (Config *)malloc(sizeof(Config)); - if (!load_config_file(config_file_path, config)) - Serial.println("ERROR: The config file could not be loaded"); - connect_wlan(config); + Serial.begin(9600); + config = (Config *)malloc(sizeof(Config)); + + if (!load_config_file(config_file_path, config)) + Serial.println("ERROR: The config file could not be loaded"); + + initialize_wlan(); + initialize_mqtt(); + connect_wlan(); + initialize_sensor(dht); } void loop() { - float temperature = dht.readTemperature(); - float humidity = dht.readHumidity(); - int analog_val = analogRead(fc28_pin); - int soil_percentage = map(analog_val, 0, 1023, 0, 100); - float data[3] = {temperature, humidity, static_cast(soil_percentage)}; - if (check_valid_value(temperature) && check_valid_value(humidity)) { - mqtt_transfer(mqtt_client, config, data); - } - disconnect_mqtt(mqtt_client, config->topic); - free(config); - enter_deep_sleep(false, config->sleep_time); + unsigned long current_millis = millis(); + + if (current_millis - previous_millis >= config->sleep_time) { + previous_millis = current_millis; + read_values(dht, data); + mqtt_transfer(data); + } } diff --git a/src/sensor.cpp b/src/sensor.cpp new file mode 100644 index 0000000..97ad558 --- /dev/null +++ b/src/sensor.cpp @@ -0,0 +1,13 @@ +#include "sensor.h" + +void initialize_sensor(DHT &sensor) { sensor.begin(); } + +void read_values(DHT &sensor, float *data) { + float temperature = sensor.readTemperature(); + float humidity = sensor.readHumidity(); + + Serial.println("Data fetched from the sensor"); + + data[0] = temperature; + data[1] = humidity; +} diff --git a/src/wlan.cpp b/src/wlan.cpp index 26d19b9..5c58619 100644 --- a/src/wlan.cpp +++ b/src/wlan.cpp @@ -1,63 +1,57 @@ #include "wlan.h" -#include -void initial_connection(const char *ssid, const char *psk) { - WiFi.begin(ssid, psk); - WiFi.persistent(true); - WiFi.setAutoConnect(true); - WiFi.setAutoReconnect(true); +void initialize_wlan() { WiFi.onEvent(wlan_connection_handler); } + +void initialize_mqtt() { + mqtt_client.onDisconnect(on_mqtt_disconnection); + mqtt_client.setServer(config->mqtt_host, config->mqtt_port); + mqtt_client.setCredentials(config->mqtt_user, config->mqtt_password); + Serial.println("MQTT initialization complete"); } -void connect_wlan(Config *config) { - if (WiFi.SSID() != config->ssid) - initial_connection(config->ssid, config->psk); - int retries = 0; - while (WiFi.status() != WL_CONNECTED) { - if (retries == config->connection_attempts) - enter_deep_sleep(true, config->sleep_time); - retries++; - delay(1000); - Serial.print("."); - } - Serial.println("WiFi connected"); +void connect_wlan() { WiFi.begin(config->ssid, config->psk); } + +void connect_mqtt() { + Serial.println("Connecting to MQTT"); + mqtt_client.connect(); } -void connect_mqtt(PubSubClient &client, Config *config) { - if (!client.connected()) - client.setServer(config->mqtt_host, config->mqtt_port); - if (client.connect(config->device_id, config->mqtt_user, - config->mqtt_password)) { - Serial.println("MQTT connected"); - client.subscribe(config->topic); - } +void wlan_connection_handler(WiFiEvent_t event) { + Serial.printf("[WiFi-event] event: %d\n", event); + switch (event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + connect_mqtt(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi disconnected"); + mqtt_connection_timer.detach(); + wlan_connection_timer.once(2, connect_wlan); + break; + } } -void disconnect_mqtt(PubSubClient &client, const char *topic) { - Serial.println("Disconnecting MQTT"); - client.unsubscribe(topic); - client.disconnect(); +void on_mqtt_disconnection(AsyncMqttClientDisconnectReason reason) { + Serial.println("MQTT disconnected"); + + if (WiFi.isConnected()) { + mqtt_connection_timer.once(2, connect_mqtt); + } } size_t construct_json(float *data, char *buffer, int buffer_size) { - StaticJsonDocument<100> json; - json["temperature"] = data[0]; - json["humidity"] = data[1]; - json["soil_humidity"] = data[2]; - size_t payload_size = serializeJson(json, buffer, buffer_size); - return payload_size; + JsonDocument json; + json["temperature"] = data[0]; + json["humidity"] = data[1]; + size_t payload_size = serializeJson(json, buffer, buffer_size); + return payload_size; } -void mqtt_transfer(PubSubClient &client, Config *config, float *data) { - char buffer[100]; - connect_mqtt(client, config); - size_t payload_size = construct_json(data, buffer, 100); - client.publish(config->topic, buffer, payload_size); - Serial.println("Data transferred successfully"); -} - -void enter_deep_sleep(bool wifi_timeout, int sleep_time) { - Serial.println("Entering deep sleep"); - if (wifi_timeout) - WiFi.disconnect(); - ESP.deepSleep(sleep_time, WAKE_RF_DEFAULT); +void mqtt_transfer(float *data) { + char buffer[100]; + size_t payload_size = construct_json(data, buffer, 100); + uint16_t response = + mqtt_client.publish(config->topic, 2, true, buffer, payload_size); + if (response) + Serial.println("Data transferred successfully"); }