Kapazitiven Bodenfeuchtesensor (HW-390) für ESP8266, ESP32 und Raspberry Pi Pico W mit Alexa bauen

In diesem Teil zeigen wir dir, wie du einen kapazitiven Bodenfeuchtesensor baust, der sich an einen ESP32, ESP8266 oder Raspberry Pi Pico W anschließen lässt. Sobald alles eingerichtet ist, kannst du die Bodenfeuchte mit Amazon Alexa abfragen, Alexa nach Informationen dazu fragen, sie in der Sinric Pro App überwachen und eine Push-Benachrichtigung senden, wenn der Boden trocken oder nass ist.

Sinric Pro HW-390 capacitive soil moisture sensor

Voraussetzungen :

  1. ESP32, ESP8266 oder Raspberry Pi Pico W x 1.
  2. Kapazitiver Bodenfeuchtesensor (HW-390) x 1.
  3. Pflanze mit Topf x 1.
  4. Jumperkabel.

Hinweis: Beim ESP32 ist ADC2 (GPIO04, GPIO02, GPIO15) instabil, solange WLAN verwendet wird.

Kurze Einführung in den kapazitiven Bodenfeuchtesensor

Kapazitive Bodenfeuchtesensoren messen den elektrischen Widerstand zwischen zwei Sonden. Der Widerstand ändert sich je nach Wassermenge im Boden. Der Sensor ist mit einem Mikrocontroller (MCU) verbunden, der die Kapazität zwischen den Sonden misst. Die Schaltung des HW-390 wandelt die Kapazitätsmessung in ein Spannungssignal (ADC) um, das dann an die MCU gesendet wird. Die MCU kann mit diesem Signal die Bodenfeuchte anzeigen oder andere Geräte steuern.

Hinweis: Dünger und Korrosion können die Genauigkeit des Sensors mit der Zeit verringern.

Verdrahtung des kapazitiven Bodenfeuchtesensors

Sinric Pro HW-390 esp8266 capacitive soil moisture sensor wiring

MCU GPIO-Pin
ESP32 34 (Analog ADC1_CH6)
ESP8266 A0
Pico W GP26 (ADC0)

Prüfen wir zuerst, ob der Sensor richtig verdrahtet ist und funktioniert.

#if defined(ESP8266)
  const int adcPin = A0;  
#elif defined(ESP32) 
  const int adcPin = 34;  
#elif defined(ARDUINO_ARCH_RP2040)
  const int adcPin = 26;  
#endif

void setup() {
  Serial.begin(9600);
  pinMode(adcPin, INPUT);
}

void loop() {
 Serial.println(analogRead(adcPin)); 
 delay(1000);
}

HW-390 capacitive soil moisture sensor arduino readings

Jetzt rechnen wir den analogen Eingangswert in einen Prozentwert um.

#if defined(ESP8266)
  const int adcPin = A0;  
#elif defined(ESP32) 
  const int adcPin = 34;  
#elif defined(ARDUINO_ARCH_RP2040)
  const int adcPin = 26;  
#endif

const int DRY = 720; // TODO: This is value when soil is dry. Adjust according to your usecase
const int WET = 560; // TODO: This is value when soil is wet. Adjust according to your usecase

void setup() {
  Serial.begin(9600);
  pinMode(adcPin, INPUT);
}

void loop() {
 int sensorVal = analogRead(adcPin);
 int percentage = map(sensorVal, WET, DRY, 100, 0); 
 Serial.printf("Sensor value: %d percentage: %d%%\r\n", sensorVal, percentage); 
 
 delay(1000);
}

Sinric Pro moisture sensor esp8266 readings

Schritt 1 : Mit Sinric Pro verbinden

Schritt 1.1 : Eigenen Gerätetyp für den kapazitiven Bodenfeuchtesensor anlegen.

Sinric Pro hat keinen eingebauten Gerätetyp für einen kapazitiven Bodenfeuchtesensor. Deshalb legen wir mit der Funktion Device Template einen eigenen Gerätetyp für den kapazitiven Bodenfeuchtesensor an, um Folgendes zu sehen:

  1. Der Boden ist nass oder trocken

  2. Feuchtigkeitswert.

Hinweis: Mit der weiter unten beschriebenen Importfunktion für Gerätevorlagen kannst du dir das Anlegen der kompletten Vorlage sparen.

Sinric Pro capacitive soil moisture sensor device template

Hier müssen wir die Funktionen unseres Bodenfeuchtesensors auswählen. Wir wollen wissen, ob der Boden nass oder trocken ist, und den Feuchtigkeitswert kennen. Ziehe also die Capabilities Range, Mode und Push Notification hinein.

Sinric Pro custom device type for capacitive soil moisture sensor

Klicke auf die Schaltfläche Configure und richte die beiden Capabilities wie unten gezeigt ein.

Sinric Pro moisture sensor template mode and range settings

Klicke zum Speichern auf Save.

Sinric Pro moisture sensor template mode and range settings

Klicke auf Save, um die Vorlage zu speichern.

Sinric Pro moisture saved template

Jetzt siehst du die Vorlage, die wir gerade angelegt haben.

Eine vorhandene Vorlage importieren?

Wenn du keine Lust hast, alle Mode- und Range-Werte von Hand einzurichten, kannst du die Importfunktion verwenden.

Sinric Pro capacitive soil moisture sensor import template

Füge diese Vorlage ein:

{
  "name": "Capacitive Soil Moisture Sensor",
  "description": "Capacitive Soil Moisture Sensor",
  "deviceTypeId": "6522320f2b090cc39f39fb32",
  "capabilities": [
    {
      "id": "5ff0b41b994fd31b7d5e8961",
      "mode": {
        "instanceId": "modeInstance1",
        "locale": "en-US",
        "modeName": "Moisture",
        "nonControllable": true,
        "modeValues": [
          "Wet",
          "Dry"
        ]
      }
    },
    {
      "id": "5ff0b45f994fd31b7d5e89c2",
      "range": {
        "instanceId": "rangeInstance1",
        "locale": "en-US",
        "rangeName": "Moisture Level",
        "minimumValue": 1,
        "maximumValue": 100,
        "precision": 1,
        "unitOfMeasure": "5ffbeefbfaa11451974c6bbd",
        "presets": [],
        "nonControllable": true
      }
    },
    {
      "id": "62a707bd9e2f39090569e2d3"
    }
  ]
}

Diesen Code auf GitHub Gist ansehen

Sinric Pro create device alexa

Sinric Pro copy device id

Sinric Pro copy device id

Schritt 2 : Mit Sinric Pro verbinden

Schritt 2.1 Sinric Pro Bibliothek installieren

Sinric Pro install SinricPro library

2.2 Vollständiger Code

CapacitiveSoilMoistureSensor.h

#ifndef _CAPACITIVESOILMOISTURESENSOR_H_
#define _CAPACITIVESOILMOISTURESENSOR_H_

#include <SinricProDevice.h>
#include <Capabilities/ModeController.h>
#include <Capabilities/RangeController.h>
#include <Capabilities/PushNotification.h>

class CapacitiveSoilMoistureSensor 
: public SinricProDevice
, public ModeController<CapacitiveSoilMoistureSensor>
, public RangeController<CapacitiveSoilMoistureSensor>
, public PushNotification<CapacitiveSoilMoistureSensor> {
  friend class ModeController<CapacitiveSoilMoistureSensor>;
  friend class RangeController<CapacitiveSoilMoistureSensor>;
  friend class PushNotification<CapacitiveSoilMoistureSensor>;
public:
  CapacitiveSoilMoistureSensor(const String &deviceId) : SinricProDevice(deviceId, "CapacitiveSoilMoistureSensor") {};
};

#endif

sinricpro-capacitive-soil-moisture-sensor.ino

// #define ENABLE_DEBUG

#ifdef ENABLE_DEBUG
  #define DEBUG_ESP_PORT Serial
  #define NODEBUG_WEBSOCKETS
  #define NDEBUG
#endif

#include <Arduino.h>
#ifdef ESP8266
  #include <ESP8266WiFi.h>
#endif
#ifdef ESP32
  #include <WiFi.h>
#endif

#include <SinricPro.h>
#include "CapacitiveSoilMoistureSensor.h"

// Grab it from https://portal.sinric.pro.
#define APP_KEY    "" //Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx"
#define APP_SECRET "" //Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx"
#define DEVICE_ID  "" //Should look like "6534xxxxxxxc08c6ea1b"

#define SSID       "" // Your WiFi SSID
#define PASS       "" // Your WiFi Password

#define BAUD_RATE         115200              // Change baudrate to your need (used for serial monitor)
#define EVENT_WAIT_TIME   60000               // send event every 60 seconds

#if defined(ESP8266)
  const int adcPin = A0;  
#elif defined(ESP32) 
  const int adcPin = 34;  
#elif defined(ARDUINO_ARCH_RP2040)
  const int adcPin = 26;  
#endif

const int VERY_DRY = 720; // TODO: This is when soil is dry. Adjust according to your sensor
const int VERY_WET = 560; // TODO: This is when soil is wet. Adjust according to your sensor
const int NEITHER_DRY_OR_WET = 620; // TODO: This is when soil is neither wet or dry. Adjust according to your sensor
const int DRY_PUSH_NOTIFICATION_THRESHHOLD = 700; // TODO: This is when to send a push notification to the mobile phone. Adjust according to your sensor
const int UNPLUGGED = 735; // This is the value sensor produce when it's not in the ground.

int lastSoilMoisture = 0;
String lastSoilMoistureStr = "";

CapacitiveSoilMoistureSensor &capacitiveSoilMoistureSensor = SinricPro[DEVICE_ID];

void updateSoilState(String mode) {
  capacitiveSoilMoistureSensor.sendModeEvent("modeInstance1", mode, "PHYSICAL_INTERACTION");
}

void updateMoistureLevel(int value) {
  capacitiveSoilMoistureSensor.sendRangeValueEvent("rangeInstance1", value);
}

void sendPushNotification(String message) {
  capacitiveSoilMoistureSensor.sendPushNotification(message);
}

void handleCapacitiveSoilMoistureSensor() {
  if (SinricPro.isConnected() == false) {
    return; 
  }

  static unsigned long last_millis;
  unsigned long        current_millis = millis();
  if (last_millis && current_millis - last_millis < EVENT_WAIT_TIME) return;
  last_millis = current_millis;
  
  int soilMoisture = analogRead(adcPin);
  int percentage = map(soilMoisture, VERY_WET, VERY_DRY, 100, 0); 
  percentage = constrain(percentage, 1, 100);

  Serial.printf("Soil Moisture: %d. as a percentage: %d%%\r\n", soilMoisture, percentage); 
 
  if (isnan(soilMoisture)) { // reading failed... 
    Serial.printf("Capacitive Soil Moisture Sensor reading failed!\r\n");  // print error message
    return;                                    // try again next time
  } 

  if (soilMoisture == lastSoilMoisture) {
    Serial.printf("Soil moisture did not changed. do nothing...!\r\n");
    return; 
  }

  // Determine Wet or Dry.
  String soilMoistureStr = "";
  if(soilMoisture > NEITHER_DRY_OR_WET) {
    soilMoistureStr = "Dry"; // NOTE: must be Wet, Dry. This is from modes list in template.
  } else {
    soilMoistureStr = "Wet";
  }

  // Update Moisture label
  if(lastSoilMoistureStr != soilMoistureStr) {
    lastSoilMoistureStr = soilMoistureStr;
    updateSoilState(soilMoistureStr);
  }
  
  delay(500);

  // Update Moisture level label
  updateMoistureLevel(percentage); 

  // Send push notifications
  if(soilMoisture > DRY_PUSH_NOTIFICATION_THRESHHOLD) {
    sendPushNotification("Plants are too dry. Time to water the plants!");
  }

  if(soilMoisture > UNPLUGGED) {
    sendPushNotification("Sensor seems to be unhooked. Please check!");
  }

  lastSoilMoisture = soilMoisture;  // save to compare next time.
}


/********* 
 * Setups *
 *********/

void setupSinricPro() {
  SinricPro.onConnected([]{ Serial.printf("[SinricPro]: Connected\r\n"); });
  SinricPro.onDisconnected([]{ Serial.printf("[SinricPro]: Disconnected\r\n"); });
  SinricPro.begin(APP_KEY, APP_SECRET);
};

void setupSensor() {
  pinMode(adcPin, INPUT);
}

void setupWiFi() {
  #if defined(ESP8266)
    WiFi.setSleepMode(WIFI_NONE_SLEEP); 
    WiFi.setAutoReconnect(true);
  #elif defined(ESP32)
    WiFi.setSleep(false); 
    WiFi.setAutoReconnect(true);
  #endif

  WiFi.begin(SSID, PASS);
  Serial.printf("[WiFi]: Connecting to %s", SSID);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.printf(".");
    delay(250);
  }
  Serial.printf("connected\r\n");
}

void setup() {
  Serial.begin(BAUD_RATE);
  setupSensor();
  setupWiFi();
  setupSinricPro();
}

/********
 * Loop *
 ********/

void loop() {
  SinricPro.handle();
  handleCapacitiveSoilMoistureSensor();
}

Diesen Code auf GitHub Gist ansehen

Jetzt solltest du die Bodenfeuchte über Alexa und die Sinric Pro App sehen können

Alexa, wie ist die Feuchtigkeit (Name des Modes) im Garten (Gerätename)

Alexa, wie hoch ist der Feuchtigkeitswert (Name der Range) im Garten (Gerätename)

Sinric Pro Alexa water sensor

Sinric Pro portal

Schritt 3 : Sprachansagen!

✅ So funktioniert es:

1️⃣ Lege in SinricPro einen Switch an (dein geheimer Auslöser!)

2️⃣ Erstelle eine Alexa-Routine, die deine Nachricht ansagt, etwa „Zeit, den Garten zu gießen!“, sobald der Switch eingeschaltet wird

3️⃣ Sende aus deinem Code ein Power-State-Event, um diesen Switch einzuschalten

void triggerVoiceAnnouncement() {
    SinricProSwitch& mySwitch = SinricPro[SWITCH_ID];
    mySwitch.sendPowerStateEvent(true);
}

Fehlerbehebung

  1. Google Home und SmartThings werden nicht unterstützt.

  2. Weitere Details findest du auf unserer Seite zur Fehlerbehebung.

Verwandte Tutorials

Dieses Dokument ist Open Source. Einen Tippfehler entdeckt? Bitte erstelle ein Issue