Gateway per sensore capacitivo di umidità del suolo
Schema di principio del collegamento a stella
Notare i collegamenti punto-punto tra tutti i dispositivi e il microcontrollore tramite linee esclusive.
Il sensore di livello capacitivo
Schema cablaggio
Condizionamento digitale
| Tensione di alimentazione | 3.3V | 5V |
|-----------------------------------------|---------|-----------|-----------|-----------|
| Umido/Secco | Umido | Secco | Umido | Secco |
| Sensore di umidità del suolo capacitivo | 2...8 | 14...21 | 821...824 | 490...549 |
| Sensore di umidità del suolo resistivo | 1024 | 483...505 | 1023 | 344...358 |
Teoricamente si può usare una qualsiasi di queste combinazioni, ma è necessario calibrare il sensore prima di dichiarare che il terreno è bagnato o asciutto.
Per il sensore di umidità del suolo capacitivo si vede anche dalla tabella che la differenza nel valore del sensore per una tensione di esercizio di 3,3V è molto bassa. Pertanto per evitare probabili errori è consigliabile, per il sensore capacitivo, utilizzare una tensione operativa di 5V.
Librerie del progetto
Dal punto di vista SW non servono librerie particolari tranne quelle per la pubblicazione dei valorri traite MQTT. Una parte del codice va comunque dedicata al condizionamento dei valori misurati dal sensore per tradurli ai valori di interesse di umidità.
Gateway MQTT per la lettura di un solo sensore di umidità del suolo
La libreria MQTT è asincrona per cui non bloccante. E’ adoperabile sia per ESP8266 che per ESP32.
Poiché ogni pin I/O digitale dell’ESP32, che non viene utilizzato per un’interfaccia di comunicazione, può essere un ingresso analogico, dobbiamo scegliere un pin qualsiasi come ingresso analogico.
//#include <WiFiClientSecure.h>
//#include <ESP8266WiFi.h> per ESP8266
#include <AsyncMqttClient.h>
#include <Ticker.h>
#include <WiFi.h> // per ESP32
// Raspberry Pi Mosquitto MQTT Broker
//#define MQTT_HOST IPAddress(192, 168, 1, 254)
#define MQTT_HOST "test.mosquitto.org"
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"
#define MQTT_PORT 1883
#define WIFI_SSID "myssid"
#define WIFI_PASSWORD "mypsw"
//Temperature MQTT Topic
#define MQTT_PUB "esp/umiditasuolo/"
//#define SensorPin A0 // used for Arduino and ESP8266
#define SensorPin 4 // used for ESP32
Ticker mqttReconnectTimer;
Ticker wifiReconnectTimer;
String datastr = "";
AsyncMqttClient mqttClient;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 2000; // Interval at which to publish sensor readings
byte count = 0;
unsigned long previusMillis = 0;
bool sensor1 = false;
float t1, h1;
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.mode(WIFI_STA);
//WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void WiFiEvent(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
connectToMqtt();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
wifiReconnectTimer.once_ms(2000, connectToWifi);
break;
}
}
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
mqttReconnectTimer.once_ms(2000, connectToMqtt);
}
}
void onMqttPublish(uint16_t packetId) {
Serial.println("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
WiFi.onEvent(WiFiEvent);
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
// If your broker requires authentication (username and password), set them below
//mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
connectToWifi();
count = 0;
while (WiFi.status() != WL_CONNECTED && count < 10) {
delay(500);
count++;
Serial.print(".");
}
}
void packData(String &str){
str = "{\"humidity1\":\"";
str += h1;
str += "\"}";
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Serial.print("Requesting data...");
h1 = analogRead(SensorPin);
Serial.println("DONE");
packData(datastr);
// Publish an MQTT message on topic esp32/ds18b20/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB, 1, true, datastr.c_str(), datastr.length());
Serial.print("Pubblicato sul topic %s at QoS 1, packetId: ");
Serial.println(MQTT_PUB);
Serial.println(packetIdPub1);
Serial.print("Messaggio inviato: ");
Serial.println(datastr);
}
}
Gateway MQTT per la lettura periodica di un sensore di umidità del suolo alimentato a batteria
Il codice seguente utilizza la modalità di sleep profondo del microcontrollore ESP32 che consiste nello spegnimento dei due core della CPU e di tutte le periferiche fatta eccezione per un timer HW che viene impostato ad un timeout allo scadere del quale avviene il risveglio della CPU. Lo sleep profondo consente un drastico risparmio di energia nei periodi di inattività che allunga la durata di una eventuale alimentazione a batterie.
L’istruzione esp_deep_sleep_start();
avvia la fase di sleep e viene eseguita una volta sola all’interno del setup(). Il loop() è praticamente inutile e viene lasciato vuoto dato che non è possibile arrivare alla sua esecuzione.
Il risveglio fa ripartire ogni volta il sistema dal setup() per cui tutte le elaborazioni e le eventuali comunicazioni devono avvenire la dentro.
L’istruzione esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR)
imposta il timeout del timer.
La funzione print_wakeup_reason()
stampa sulla seriale il motivo del wakeup.
I motivi possono essere:
- l’evento di timer HW, che sveglia il sistema in periodi di tempo prestabiliti;
- l’evento di tocco tattile di un certo pin;
- un evento di riattivazione esterna: è possibile utilizzare una riattivazione esterna o più risvegli esterni diversi;
- un evento generato dal coprocessore ULP ma questo non sarà trattato nella presente guida.
Nel codice seguente vengono effettuati alcuni tentativi di riconnessione in caso di mancato collegamento del WiFi o di mancata connessione MQTT. Fallito il numero massimo di tentativi si va in sleep profondo e si riprova al prossimo risveglio.
//#include <WiFiClientSecure.h>
//#include <ESP8266WiFi.h> per ESP8266
#include <AsyncMqttClient.h>
#include <WiFi.h> // per ESP32
// Raspberry Pi Mosquitto MQTT Broker
//#define MQTT_HOST IPAddress(192, 168, 1, 254)
#define MQTT_HOST "test.mosquitto.org"
// For a cloud MQTT broker, type the domain name
//#define MQTT_HOST "example.com"
#define MQTT_PORT 1883
#define WIFI_SSID "myssid"
#define WIFI_PASSWORD "mypsw"
//Temperature MQTT Topic
#define MQTT_PUB "esp/umiditasuolo/"
//#define SensorPin A0 // used for Arduino and ESP8266
#define SensorPin 4 // used for ESP32
//deep sleep
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
#define TIME_TO_SLEEP 30 /* Time ESP32 will go to sleep (in seconds) */
RTC_DATA_ATTR int bootCount = 0;
String datastr = "";
AsyncMqttClient mqttClient;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 2000; // Interval at which to publish sensor readings
byte count = 0;
unsigned long previusMillis = 0;
bool sensor1 = false;
float t1, h1;
/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason(){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason)
{
case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
}
}
void connectToWifi() {
Serial.println("Connecting to Wi-Fi...");
WiFi.mode(WIFI_STA);
//WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}
void packData(String &str){
str = "{\"humidity1\":\"";
str += h1;
str += "\"}";
}
void loop_once() {
Serial.print("Requesting data...");
h1 = analogRead(SensorPin);
Serial.println("DONE");
packData(datastr);
// Publish an MQTT message on topic esp32/ds18b20/temperature
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB, 1, true, datastr.c_str(), datastr.length());
Serial.print("Pubblicato sul topic %s at QoS 1, packetId: ");
Serial.println(MQTT_PUB);
Serial.println(packetIdPub1);
Serial.print("Messaggio inviato: ");
Serial.println(datastr);
}
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
// If your broker requires authentication (username and password), set them below
//mqttClient.setCredentials("REPlACE_WITH_YOUR_USER", "REPLACE_WITH_YOUR_PASSWORD");
count = 0;
connectToWifi();
while (WiFi.status() != WL_CONNECTED && count < 10) {
count++;
Serial.print(".");
delay(500);
}
if(WiFi.status() == WL_CONNECTED){
//se il WiFi è connesso
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
count = 0;
Serial.println("Connecting to MQTT...");
mqttClient.connect();
while (!mqttClient.connected() && WiFi.status() == WL_CONNECTED && count < 10) {
//Serial.print("MQTT lastError: ");
//Serial.println(mqttClient.lastError());
mqttClient.connect();
count++;
Serial.print(".");
delay(500);
}
if(mqttClient.connected()){
//se il WiFi è connesso
Serial.println("MQTT connected");
}
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
/*
First we configure the wake up source
We set our ESP32 to wake up every tot seconds
*/
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");
loop_once();
Serial.println("Going to sleep now");
delay(1000);
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop(){}
Sitografia:
- https://diyi0t.com/soil-moisture-sensor-tutorial-for-arduino-and-esp8266
- https://randomnerdtutorials.com/esp32-deep-sleep-arduino-ide-wake-up-sources/
- https://randomnerdtutorials.com/esp32-timer-wake-up-deep-sleep/