Cómo construir un sensor capacitivo de humedad del suelo (HW-390) con ESP8266, ESP32 o Raspberry Pi Pico W para Alexa
En esta parte te guiamos para construir un sensor capacitivo de humedad del suelo que se puede conectar a un ESP32, ESP8266 o Raspberry Pi Pico W. Una vez configurado, podrás comprobar el nivel de humedad del suelo con Amazon Alexa, preguntarle a Alexa por él, supervisarlo desde la app de Sinric Pro y enviar una notificación push cuando el suelo esté seco o húmedo.

Requisitos previos :
- ESP32, ESP8266 o Raspberry Pi Pico W x 1.
- Sensor capacitivo de humedad del suelo (HW-390) x 1.
- Planta con maceta x 1.
- Cables puente.
Nota: en el ESP32, el ADC2 (GPIO04, GPIO02, GPIO15) es inestable cuando se usa el Wi-Fi.
Breve introducción al sensor capacitivo de humedad del suelo
Los sensores capacitivos de humedad del suelo miden la resistencia eléctrica entre dos sondas. La resistencia cambia según la cantidad de agua que hay en el suelo. El sensor se conecta a un microcontrolador (MCU), que mide la capacitancia entre las sondas. El circuito del HW-390 convierte la medida de capacitancia en una señal de tensión (ADC), que se envía al MCU. El MCU puede usar esta señal para mostrar el nivel de humedad del suelo o para controlar otros dispositivos.
Nota: Los fertilizantes y la corrosión pueden reducir la precisión del sensor con el tiempo.
Cableado del sensor capacitivo de humedad del suelo

| MCU | Pin GPIO |
|---|---|
| ESP32 | 34 (analógico ADC1_CH6) |
| ESP8266 | A0 |
| Pico W | GP26 (ADC0) |
Vamos a comprobar que el sensor está bien cableado y funciona.
#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);
}

Vamos a convertir la entrada analógica en un valor porcentual.
#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);
}

Paso 1 : Conecta con Sinric Pro
Paso 1.1 : Crea un tipo de dispositivo personalizado para el sensor capacitivo de humedad del suelo.
Sinric Pro no tiene un tipo de dispositivo integrado para el sensor capacitivo de humedad del suelo, así que vamos a crear uno personalizado con la función Device Template para ver:
-
Si el suelo está Wet (húmedo) o Dry (seco)
-
El nivel de humedad.
Nota: Puedes usar la función de importación de plantillas de dispositivo que se explica más abajo para ahorrarte crear la plantilla completa.
-
Inicia sesión en tu cuenta de Sinric Pro y ve a Device Templates
-
Haz clic en Add Device Template. Escribe Capacitive Soil Moisture Sensor como nombre y descripción y selecciona Capacitive Soil Moisture Sensor como tipo de dispositivo

- Haz clic en Capabilities.
Aquí hay que seleccionar las funciones de nuestro sensor de humedad del suelo. Queremos saber si el suelo está húmedo o seco y el nivel de humedad. Así que arrastra una capacidad Range, una Mode y una Push Notification.

-
¿Qué es la capacidad Range?
La capacidad Range sirve para representar un número. Por ejemplo: la velocidad actual de una batidora.
-
¿Qué es la capacidad Mode?
La capacidad Mode sirve para representar un valor de una lista de valores predefinidos. Por ejemplo: el programa de lavado actual de una lavadora.
-
¿Qué es la capacidad Push Notification?
La capacidad Notification permite enviar una notificación push desde el código.
Haz clic en el botón Configure y configura las dos capacidades como se muestra a continuación.

Haz clic en Save para guardar.

Haz clic en Save para guardar la plantilla.

Ahora puedes ver la plantilla que acabamos de crear.
¿Importar una plantilla existente?
Si te da pereza configurar todos los valores de Mode y Range, puedes usar la función de importación.

Pega esta plantilla:
{
"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"
}
]
}
Ver este código en GitHub Gist
-
Inicia sesión en tu cuenta de Sinric Pro, ve al menú Devices, a la izquierda, y haz clic en el botón Add Device (arriba a la izquierda).
-
Escribe el nombre del dispositivo Garden, la descripción My Garden y selecciona el tipo de dispositivo Capacitive Soil Moisture Sensor.

-
Haz clic en la pestaña Others y después en Save
-
La siguiente pantalla muestra las credenciales necesarias para conectar el dispositivo que acabas de crear.

-
Copia Device Id, App Key y App Secret Mantén estos valores seguros. ¡NO LOS COMPARTAS EN FOROS PÚBLICOS!
-
Haz clic en Code Generator para generar el código. Haz clic en Download para descargarlo.

Paso 2 : Conecta con Sinric Pro
Paso 2.1 Instala la librería Sinric Pro

2.2 Código completo
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();
}
Ver este código en GitHub Gist
Ahora deberías poder consultar la humedad del suelo con Alexa y con la app de Sinric Pro
Alexa, ¿cuál es la humedad (nombre del modo) en garden (nombre del dispositivo)?
Alexa, ¿cuál es el nivel de humedad (nombre del rango) en garden (nombre del dispositivo)?


Paso 3 : ¡Anuncios de voz!
✅ Cómo funciona:
1️⃣ Añade un Switch en SinricPro (¡tu disparador secreto!)
2️⃣ Crea una rutina de Alexa que diga tu mensaje, por ejemplo “¡Es hora de regar el jardín!”, cuando se encienda el Switch
3️⃣ Envía desde tu código un evento de estado de encendido para poner ese interruptor en ON
void triggerVoiceAnnouncement() {
SinricProSwitch& mySwitch = SinricPro[SWITCH_ID];
mySwitch.sendPowerStateEvent(true);
}
Solución de problemas
-
Google Home y SmartThings no son compatibles.
-
Consulta nuestra página Troubleshooting para más detalles.
Tutoriales relacionados
- Cómo controlar un ESP32 o ESP8266 con Alexa y Google Home
- Sensor de humedad del suelo alimentado por batería
- Nivel de un depósito de agua con un sensor ultrasónico HC-SR04
- Sensor de fugas de agua, inundación y lluvia
Este documento es de código abierto. ¿Has visto una errata? Crea una issue