Um sensor de umidade do solo com MQTT informa quando um canteiro, vaso ou zona de lavoura realmente precisa de água, em vez de você regar em horário fixo. Neste tutorial você vai ligar uma sonda capacitiva a um ESP32, calibrá-la com solo seco e saturado, publicar a umidade em percentual em um broker MQTT em um ciclo de deep sleep e gerar um alerta de irrigação com histerese sobre o qual dashboards e automações podem agir.
Por que uma Sonda Capacitiva
As sondas resistivas baratas de dois dentes, comuns em kits iniciais, fazem passar corrente pelo solo. Em poucas semanas os eletrodos expostos corroem, as leituras derivam e o metal se dissolve no solo. As sondas capacitivas medem a permissividade dielétrica do solo através de uma placa de circuito revestida, então nada condutor toca a terra. Elas são o mínimo sensato para qualquer coisa que precise durar uma safra.
| Tipo de sonda | Vida útil no solo | Precisão | Observações |
|---|---|---|---|
| Garfo resistivo | Semanas | Ruim, deriva | Serve apenas para uma demonstração de um dia |
| Capacitiva (placas v1.2 / v2.0) | Safras, se a borda for vedada | Relativa, precisa de calibração | Melhor custo-benefício para hobby e pequenas propriedades |
| Sondas FDR/TDR profissionais | Anos | Boa, muitas vezes volumétrica | Saída SDI-12 ou RS485, custo maior |
As placas capacitivas fornecem uma leitura relativa, não o conteúdo volumétrico de água. Isso basta para decidir quando regar, desde que você calibre cada sonda no solo onde ela vai ficar.
Peças e Ligação
| Peça | Função |
|---|---|
| Placa de desenvolvimento ESP32 (ou uma placa de baixo consumo em repouso para baterias) | Lê a sonda, conecta ao Wi-Fi e ao MQTT |
| Sonda capacitiva de umidade do solo | Mede a umidade |
| 3 jumpers | Alimentação, terra, sinal |
| Opcional: célula 18650, suporte e pequeno painel solar | Alimentação fora da rede |
Ligação:
| Pino da sonda | Pino do ESP32 |
|---|---|
| VCC | GPIO 25 (alimentação chaveada) |
| GND | GND |
| AOUT | GPIO 34 (ADC1) |
Dois detalhes importam. Primeiro, use um pino ADC1 (GPIO 32 a 39). Os pinos ADC2 não podem ser lidos enquanto o Wi-Fi está ativo. Segundo, alimente a sonda por um GPIO em vez da linha de 3,3 V, para que ela não consuma nada enquanto o ESP32 dorme. As sondas capacitivas consomem apenas alguns miliampères, bem dentro do que um GPIO consegue fornecer. Algumas placas baratas vêm com um regulador que se comporta mal em 3,3 V; se as leituras estiverem erráticas, verifique a revisão da placa.
Vede a borda superior da sonda e os componentes expostos com esmalte de unha, verniz conformal ou termorretrátil. A água que penetra pela borda cortada da PCB é a causa mais comum de falha da sonda.
Calibrando a Sonda
O ESP32 retorna um valor bruto de 0 a 4095. As sondas capacitivas leem alto quando seco e baixo quando úmido. Grave o sketch abaixo com CALIBRATION_MODE definido como true, abra o monitor serial em 115200 baud e anote dois valores:
- Seco: a sonda em solo completamente seco do mesmo canteiro (ou no ar, como alternativa aproximada).
- Úmido: a sonda no mesmo solo saturado de água, após alguns minutos para estabilizar.
Insira a sonda sempre na mesma profundidade, até a linha marcada na placa, nunca mais fundo. Valores típicos ficam em torno de 2.600 a 3.000 no seco e 1.000 a 1.400 no úmido, mas cada sonda é diferente, e por isso você mede em vez de copiar.
O Sketch do Sensor de Umidade do Solo MQTT com ESP32
O sketch acorda, liga a sonda, tira a mediana de várias leituras, converte para percentual, conecta ao Wi-Fi e ao broker, publica uma mensagem de telemetria retida e um estado de alerta e volta ao deep sleep. Ele usa a biblioteca PubSubClient. Substitua s5d1v8 por uma string aleatória sua, já que a área do servidor MQTT público pode ser lida por todos.
#include <WiFi.h>
#include <PubSubClient.h>
#define CALIBRATION_MODE false
const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;
const char* CLIENT_ID = "soil-bed1-s5d1v8";
const char* TOPIC_TELE = "connectmq/demo/s5d1v8/garden/bed1/telemetry";
const char* TOPIC_ALERT = "connectmq/demo/s5d1v8/garden/bed1/alert";
const char* TOPIC_STATUS = "connectmq/demo/s5d1v8/garden/bed1/status";
const int PIN_PROBE_PWR = 25;
const int PIN_PROBE_ADC = 34;
const int RAW_DRY = 2850; // da calibração
const int RAW_WET = 1180; // da calibração
const float ALERT_ON_PCT = 25.0; // inicia o alerta abaixo deste valor
const float ALERT_OFF_PCT = 35.0; // limpa o alerta acima deste valor
const uint64_t SLEEP_MIN = 15;
RTC_DATA_ATTR bool alertActive = false;
RTC_DATA_ATTR uint32_t bootCount = 0;
WiFiClient net;
PubSubClient mqtt(net);
int readRawMedian() {
digitalWrite(PIN_PROBE_PWR, HIGH);
delay(300); // deixa a saída da sonda estabilizar
int v[9];
for (int i = 0; i < 9; i++) {
v[i] = analogRead(PIN_PROBE_ADC);
delay(20);
}
digitalWrite(PIN_PROBE_PWR, LOW);
for (int i = 1; i < 9; i++) { // insertion sort
int k = v[i], j = i - 1;
while (j >= 0 && v[j] > k) { v[j + 1] = v[j]; j--; }
v[j + 1] = k;
}
return v[4];
}
float rawToPercent(int raw) {
float pct = 100.0f * (RAW_DRY - raw) / (float)(RAW_DRY - RAW_WET);
if (pct < 0) pct = 0;
if (pct > 100) pct = 100;
return pct;
}
bool connectWifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
for (int i = 0; i < 40 && WiFi.status() != WL_CONNECTED; i++) delay(250);
return WiFi.status() == WL_CONNECTED;
}
bool connectMqtt() {
mqtt.setServer(MQTT_HOST, MQTT_PORT);
for (int i = 0; i < 3; i++) {
if (mqtt.connect(CLIENT_ID, TOPIC_STATUS, 1, true, "offline")) return true;
delay(1000);
}
return false;
}
void goToSleep() {
esp_sleep_enable_timer_wakeup(SLEEP_MIN * 60ULL * 1000000ULL);
esp_deep_sleep_start();
}
void setup() {
Serial.begin(115200);
pinMode(PIN_PROBE_PWR, OUTPUT);
analogSetPinAttenuation(PIN_PROBE_ADC, ADC_11db);
bootCount++;
int raw = readRawMedian();
if (CALIBRATION_MODE) {
while (true) {
Serial.printf("raw=%d\n", readRawMedian());
delay(1000);
}
}
float pct = rawToPercent(raw);
bool changed = false;
if (!alertActive && pct < ALERT_ON_PCT) { alertActive = true; changed = true; }
if (alertActive && pct > ALERT_OFF_PCT) { alertActive = false; changed = true; }
if (connectWifi() && connectMqtt()) {
char buf[160];
snprintf(buf, sizeof(buf),
"{\"moisture_pct\":%.1f,\"raw\":%d,\"rssi\":%d,\"boot\":%lu}",
pct, raw, WiFi.RSSI(), (unsigned long)bootCount);
mqtt.publish(TOPIC_STATUS, "online", true);
mqtt.publish(TOPIC_TELE, buf, true);
snprintf(buf, sizeof(buf), "{\"active\":%s,\"moisture_pct\":%.1f}",
alertActive ? "true" : "false", pct);
mqtt.publish(TOPIC_ALERT, buf, true);
if (changed) Serial.println(alertActive ? "ALERT raised" : "ALERT cleared");
mqtt.loop();
delay(200); // dá tempo para a pilha TCP esvaziar o buffer
mqtt.publish(TOPIC_STATUS, "sleeping", true);
mqtt.disconnect();
}
goToSleep();
}
void loop() {}
Acompanhando as leituras
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-s5d1v8 \
-t 'connectmq/demo/s5d1v8/garden/#' -v
Como a telemetria é retida, o assinante mostra a leitura mais recente imediatamente, mesmo que o dispositivo passe quase todo o tempo dormindo. O tópico de status informa se o nó está online, sleeping ou se caiu inesperadamente (offline, pelo last will).
Como o Alerta de Irrigação Funciona
Um único limite faria o alerta ligar e desligar repetidamente enquanto as leituras oscilam em torno dele, principalmente logo após uma chuva fraca ou quando o sol aquece o solo. O sketch usa histerese: o alerta liga abaixo de 25 por cento e só é limpo quando a umidade sobe acima de 35 por cento. A flag alertActive fica na memória RTC (RTC_DATA_ATTR), então sobrevive ao deep sleep.
O tópico de alerta é retido e sempre traz o estado atual, de modo que qualquer consumidor pode agir sobre ele:
- uma automação do Home Assistant que envia uma notificação ao seu celular, como mostrado no guia de automação MQTT no Home Assistant;
- um fluxo do Node-RED ou um controlador em Python que abre uma válvula, abordado no tutorial de sistema de irrigação automática;
- uma regra de alerta por limite no portal da ConnectMQ sobre
moisture_pct, que registra os alertas mesmo se o seu servidor doméstico estiver offline.
Dicas de Precisão e Confiabilidade
- Calibre no solo real. Solos arenosos e argilosos dão leituras muito diferentes para o mesmo teor de água.
- Mantenha a profundidade de inserção constante. Bolsões de ar ao redor da sonda fazem as leituras cair bruscamente; firme o solo em volta dela após a inserção.
- Observe a tendência, não valores isolados. Uma curva caindo ao longo de dois dias diz mais do que uma leitura.
- Evite os extremos do ADC. O ADC do ESP32 não é linear perto de 0 e de 4095. Com atenuação de 11 dB, a faixa útil cobre uma sonda capacitiva com folga.
- Monitore a bateria. Adicione um divisor de tensão em outro pino ADC1 e inclua
battery_vno payload; o artigo sobre sensor ESP32 alimentado por bateria traz os detalhes.
Duração da Bateria
Com despertares a cada 15 minutos, o nó fica acordado apenas alguns segundos por ciclo, a maior parte esperando a associação ao Wi-Fi. Usar IP estático e o BSSID e o canal do roteador pode encurtar isso de forma perceptível. Escolha uma placa com regulador de baixo consumo em repouso e sem chip USB e LED sempre ligados, porque muitas placas de desenvolvimento consomem mais "dormindo" do que o próprio ESP32. Para campos longe do Wi-Fi, um nó LoRaWAN com a mesma sonda e uma bridge do network server é o projeto melhor; veja o guia de agricultura inteligente com IoT para os prós e contras.
Configuração de Produção
A área do servidor MQTT público (gratuito) é ideal para montar e testar, mas é compartilhada e pública. Para uma instalação permanente, crie um broker privado e mude para TLS:
- inclua
WiFiClientSecure.h, useWiFiClientSecure net;enet.setCACert(ISRG_ROOT_X1);com o certificado ISRG Root X1; - mude a porta para 8883;
- conecte com
mqtt.connect("YOUR_CLIENT_ID", "YOUR_USERNAME", "YOUR_PASSWORD", TOPIC_STATUS, 1, true, "offline"); - mova os tópicos para o seu próprio prefixo, por exemplo
farm1/garden/bed1/telemetry.
O TLS acrescenta um ou dois segundos a cada ciclo de despertar, um custo pequeno para manter seus dados privados. Um broker MQTT gerenciado também poupa você de rodar um broker na mesma rede da qual os sensores dependem. Em uma fazenda com muitas zonas, as leituras retidas de cada talhão também servem de base para um gêmeo digital da lavoura. Mais projetos como este estão no guia de automação com IoT.
Monitore o Seu Solo na ConnectMQ
A ConnectMQ dá aos seus sensores um broker privado protegido por TLS, com explorador de tópicos ao vivo, dashboard e regras de alerta por limite para avisos de solo seco. Crie um broker Serverless gratuito em app.connectmq.com, sem cartão de crédito, e troque três linhas no sketch para entrar em produção.
Perguntas frequentes
Por que meu sensor capacitivo de umidade do solo lê um valor maior quando o solo está seco?
É assim que as sondas capacitivas funcionam: a tensão de saída cai à medida que a constante dielétrica sobe com a água. O sketch inverte a escala durante a conversão para percentual.
Posso usar várias sondas em um único ESP32?
Sim. Use outros pinos ADC1 (GPIO 32, 33, 35, 36, 39), calibre cada sonda separadamente e publique cada uma em seu próprio tópico ou como campos em uma única mensagem JSON.
Em que profundidade o sensor de umidade do solo deve ficar?
Na zona das raízes da cultura, normalmente de 5 a 15 cm para hortaliças e vasos. Insira apenas até a linha marcada, para que a eletrônica fique acima do solo.
Com que frequência um sensor de umidade do solo deve publicar via MQTT?
A cada 15 a 60 minutos é mais que suficiente. A umidade do solo muda devagar, e intervalos mais longos aumentam drasticamente a duração da bateria.



