Malte SteinDennis MikaJanfabian Fabriczek
Published © GPL3+

SoilSense adaptive soil moisture sensor

Soil moisture sensor reading relative moisture according to borders for high and low moisture which can be set by the user.

IntermediateWork in progress3 hours10
SoilSense adaptive soil moisture sensor

Things used in this project

Hardware components

Arduino UNO R4 WiFi
Arduino UNO R4 WiFi
×1
Grove - Capacitive Soil Moisture Sensor
Seeed Studio Grove - Capacitive Soil Moisture Sensor
×1

Software apps and online services

Arduino IDE
Arduino IDE
MQTT
MQTT
Eclipse IoT Eclipse Mosquitto
Arduino MQTT Library

Story

Read more

Code

Sensor Code

Arduino
Code that has to be flashed onto the sensor microcontroller
#include "WiFiS3.h"
#include "MQTT.h"

#define SensorPin A0

char ssid[] = "Malte-Laptop";
char pass[] = "ABCDEFGHIJ";

char mqttClientId[] = "Feuchtesensor1";
//char mqttUsername[] = "malte";
//char mqttPassword[] = "J*9snh!a6MfEKv#tEvwgdn^A";

char mqttAvailabilityTopic[] = "feuchtesensor/s1/avail";
char mqttStateTopic[] = "feuchtesensor/s1/value";
char brokerAvailabilityTopic[] = "homeassistant/status";
char upperBorderTopic[] = "feuchtesensor/s1/upperBorder";
char setUpperBorderTopic[] = "feuchtesensor/s1/setUpperBorder";
char setLowerBorderTopic[] = "feuchtesensor/s1/setLowerBorder";
char setLowerBorderValueTopic[] = "feuchtesensor/s1/setLowerBorderValue";
char setUpperBorderValueTopic[] = "feuchtesensor/s1/setUpperBorderValue";

char lowerBorderTopic[] = "feuchtesensor/s1/lowerBorder";

bool isBrokerOffline = false;  // Von aktivem Broker ausgehen, nur wenn Broker Last Will sendet wird Bool true

IPAddress mqttBrokerIP = "192.168.137.1";

WiFiClient net;
MQTTClient client;

int status = WL_IDLE_STATUS;

double upperBorderValue = 200;
double lowerBorderValue = 600;

void setup() {
  // put your setup code here, to run once:
  pinMode(SensorPin, INPUT);
  Serial.begin(115200);
  //while(!Serial) {}
  //Serial.println("Serial gestartet!");
  connectWiFi();
  connectMQTT();
  client.onMessage(messageHandler);
}


void loop() {
  // berprfe WiFi und MQTT Verbindung
  mqttKeepAlive();
  client.loop();
  double moisture = calc_rel_moisture(get_abs_moisture());  // Messe Feuchte und Berechne relative Feuchte
  //moisture = calc_rel_moisture(moisture)
  Serial.print("Feuchte: ");
  Serial.println(moisture);
  publishMqttDouble(moisture, mqttStateTopic);
  delay(1000);
}


// Funktion nimmt 5 Messungen in 1 Sekunde und gibt absolutes Ergebnis als int zurck
double get_abs_moisture () {
  double measurement = 5;
  for (int n_measurements = 0; n_measurements < 5; n_measurements++) {  // Nehme 5 Messungen in einer Sekunde
    measurement += analogRead(SensorPin); // Addiere Analog-Werte
    delay(1000); // Warte 200ms
  }
  Serial.print("Gemessener Analogwert: ");
  Serial.println(measurement/5);
  return measurement/5; // Gebe Durchschnitt der Messungen zurck
}

// Funktion um die relative Feuchte aus der absoluten Feuchte zu berechnen
double calc_rel_moisture (double abs_moisture) {
  double rel_moisture = 0;
  if (abs_moisture <= upperBorderValue) {  // Falls absolute Feuchte ber 500 also maximal
    rel_moisture = 100; // Setze relative Feuchte auf 100
    return rel_moisture;
  }
  else if (abs_moisture >= lowerBorderValue) { // Falls absolute Feuchte ber 900 also nicht vorhanden
    rel_moisture = 0; // Setze relative Feuchte auf 0
    return rel_moisture;
  }
  else {
    double onePercentMoisture = (lowerBorderValue - upperBorderValue) / 100;
    double moistureBelowLowerBorder = (lowerBorderValue - abs_moisture);
    rel_moisture = (moistureBelowLowerBorder/onePercentMoisture);  // Relative Feuchte nach dem Dreisatz oben ausrechnen
    //rel_moisture = round(rel_moisture); // Relative Feuchte runden
    return rel_moisture;
  }
}


// Prft ob WiFi verbunden ist und ob Client ordnungsgem verbunden ist, besttigt Online-Status in Topic
void mqttKeepAlive() {
  if(!isWiFiConnected()) {
    Serial.println("Keepalive: WiFi nicht verbunden");
    connectWiFi();
  }
  if(!isMQTTConnected()) { // Falls client nicht verbunden oder Broker nicht verfgbar
    Serial.println("Keepalive: MQTT nicht verbunden");
    connectMQTT();
  }
  client.publish(mqttAvailabilityTopic, "online");
  Serial.println("Keepalive abgeschlossen");
  return;
}

// Prft ob WiFi verbunden ist
bool isWiFiConnected() {
  if((WiFi.localIP() != "0.0.0.0") && (WiFi.status() == WL_CONNECTED)) { // Falls IP zugewiesen und der WiFi Status connected ist
    return true;
  } else {
    return false;
  }
}

// Verbindet mit in Globalen Konstanten festgelegten WiFi-Konnektivittsdaten
void connectWiFi() {
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Kommunikation mit WiFi Modul fehlgeschlagen!");
    while (true);
  }
  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Wifi-Firmware-Update verfgbar!");
  }
  Serial.print("Versuche mit SSID ");
  Serial.print(ssid);
  Serial.println(" zu verbinden!");
  do {
    WiFi.begin(ssid, pass);
    Serial.print(".");
    delay(5000);
  } while (!isWiFiConnected());
  
  print_Wifi_Status();
  return;
}

// Funktion zur Ausgeb von WiFi-Konnektivittsdaten
void print_Wifi_Status() {
  // Gebe SSID aus
  Serial.println("WiFi verbunden mit folgenden Verbindungsdetails:");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Gebe IP-Adresse aus
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Addresse: ");
  Serial.println(ip);

  // Gebe Signalstrke aus
  long rssi = WiFi.RSSI();
  Serial.print("Signalstrke (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  return;
}

// Prft ob MQTT Client verbunden ist und ob Broker offline
bool isMQTTConnected() {
  if(client.connected() && !isBrokerOffline) {  // Falls Client verbunden und Broker nicht offline
    return true;
  } else {
    return false;
  }
}

// Verbindet mit in Globalen Variablen festgelegten MQTT Verbindungsdaten
void connectMQTT() {
  Serial.println("Verbinde mit MQTT Broker");
  client.begin(mqttBrokerIP, net);  // Starte MQTT Client mit IP des Brokers und dem Wifi-Client
  client.setWill(mqttAvailabilityTopic, "offline");
  do {
    client.connect(mqttClientId); // client.connect(mqttClientId, mqttUsername, mqttPassword);
    Serial.print(".");
    delay(1000);
  } while (!isMQTTConnected());
  Serial.println("Verbindung zu MQTT Broker hergestellt");
  delay(3000);  // Warte 3s damit Home Assistant komplett starten kann vor Birth Nachricht
  client.subscribe(upperBorderTopic);
  client.subscribe(lowerBorderTopic);
  client.subscribe(setUpperBorderValueTopic);
  client.subscribe(setUpperBorderTopic);
  client.subscribe(setLowerBorderValueTopic);
  client.subscribe(setLowerBorderTopic);
  client.publish(mqttAvailabilityTopic, "online");
  publishMqttDouble(lowerBorderValue, lowerBorderTopic);
  publishMqttDouble(upperBorderValue, upperBorderTopic);
  isBrokerOffline = false;
  return;
}

// Sendet double an MQTT Topic
void publishMqttDouble(double msg, String topic) {
  char msgString[16]; // Erstelle char Array
  dtostrf(msg, 6, 1, msgString);  // Konvertiere double in char Array
  client.publish(topic, msgString);  // Verffentliche Wert in passendem Topic
  //client.publish(mqttStateTopic, "1");
  return;
}

// Prft ob Broker Last Will sendet
void messageHandler(String &topic, String &payload) {
  Serial.println(payload);
  if((topic == brokerAvailabilityTopic) && (payload == "offline")) {  // Falls Broker Last Will sendet
    isBrokerOffline = true;
  } else if(topic == setUpperBorderValueTopic) { // Wenn obere Grenze manuell auf Wert gesetzt wird
    upperBorderValue = payload.toFloat();
    Serial.println("obere Grenze auf ");
    Serial.print(upperBorderValue);
    Serial.print(" gesetzt");
    publishMqttDouble(lowerBorderValue, lowerBorderTopic);
    publishMqttDouble(upperBorderValue, upperBorderTopic);
  } else if(topic == setLowerBorderValueTopic) { // Wenn untere Grenze manuell auf Wert gesetzt wird
    lowerBorderValue = payload.toFloat();
    Serial.println("untere Grenze auf ");
    Serial.print(lowerBorderValue);
    Serial.print(" gesetzt");
    publishMqttDouble(lowerBorderValue, lowerBorderTopic);
    publishMqttDouble(upperBorderValue, upperBorderTopic);
  } else if (topic == setUpperBorderTopic) { // Wenn obere Grenze manuell auf aktuellen Wert gesetzt wird
    upperBorderValue = get_abs_moisture();
    Serial.println("obere Grenze auf");
    Serial.print(upperBorderValue);
    Serial.print(" gesetzt");
    publishMqttDouble(lowerBorderValue, lowerBorderTopic);
    publishMqttDouble(upperBorderValue, upperBorderTopic);
  } else if (topic == setLowerBorderTopic) {  // Wenn untere Grenze manuell auf aktuellen Wert gesetzt wird
    lowerBorderValue = get_abs_moisture();
    Serial.println("untere Grenze auf ");
    Serial.print(lowerBorderValue);
    Serial.print(" gesetzt");
    publishMqttDouble(lowerBorderValue, lowerBorderTopic);
    publishMqttDouble(upperBorderValue, upperBorderTopic);
  }
  return;
}

Credits

Malte Stein
1 project • 0 followers
Dennis Mika
1 project • 0 followers
Janfabian Fabriczek
8 projects • 7 followers
Embedded Software Expert @ Festo SE & Co. KG; Lecturer IoT Ecosystems @ Hochschule Esslingen

Comments