Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
/
/
ESP32 com FreeRTOS: Monitor de Nível da Caixa-d’Água com Sensor XKC-Y25 e Painel Web

ESP32 com FreeRTOS: Monitor de Nível da Caixa-d’Água com Sensor XKC-Y25 e Painel Web

Sumário

Baixe agora a apostila Arduino Iniciante e comece seus projetos

Compartilhe seu conhecimento e receba em dinheiro ou produtos.

Introdução

O monitoramento de nível de água é uma aplicação bastante comum em sistemas de automação residencial, comercial e industrial. Acompanhar o nível de uma caixa-d’água permite identificar situações de abastecimento, detectar quando o líquido atinge determinada altura e criar soluções para auxiliar no controle de reservatórios.

Neste projeto, vamos construir um monitor de nível utilizando o ESP32 e o sensor XKC-Y25, com uma interface web acessível pelo celular ou computador. O diferencial será desenvolver todo o firmware no Visual Studio Code, utilizando a extensão PlatformIO IDE e os recursos do FreeRTOS para organizar a execução do programa.

Em vez de concentrar todas as operações em um único laço principal, vamos dividir o software em tarefas independentes. Uma tarefa ficará responsável pela leitura do sensor e pela filtragem das mudanças de estado. Outra será responsável pelo servidor web, que disponibilizará as informações para o navegador.

A página apresentará uma representação gráfica de uma caixa-d’água, uma indicação do estado do sensor e informações sobre as leituras realizadas. A interface será atualizada automaticamente, sem que o usuário precise recarregar a página.Para simplificar a montagem, o ESP32 funcionará como ponto de acesso Wi-Fi, criando uma rede própria. Dessa forma, será possível acessar o painel sem depender de um roteador ou de uma conexão com a internet.É importante esclarecer que o XKC-Y25 detecta a presença de líquido em um ponto específico. Com apenas um sensor, não conseguimos medir diretamente a porcentagem real de enchimento da caixa. A representação gráfica será esquemática, mostrando se o líquido atingiu ou não a altura de detecção. Para monitorar diferentes alturas, poderemos utilizar sensores adicionais.

Conhecendo o sensor XKC-Y25

sensor

O XKC-Y25 é um sensor capacitivo de nível que pode ser instalado na parte externa de determinados recipientes. Seu funcionamento se baseia na alteração das propriedades capacitivas percebidas pelo sensor quando o líquido se aproxima da região de detecção.

Uma das vantagens dessa tecnologia é a possibilidade de detectar líquidos sem colocar o sensor diretamente em contato com eles. Isso pode simplificar a instalação e evitar mecanismos móveis no interior do reservatório.Entre as aplicações possíveis, destacam-se:
  • Monitoramento de caixas-d’água;
  • Detecção de nível em reservatórios plásticos;
  • Sistemas de abastecimento;
  • Monitoramento de tanques de processo;
  • Projetos de automação e Internet das Coisas.
A detecção depende do material e da espessura da parede, das características do líquido e das condições de instalação. Por isso, é necessário testar o sensor no recipiente que será utilizado.Antes de conectar o XKC-Y25 ao ESP32, confira a identificação dos fios, a tensão de alimentação e as características elétricas da saída. O ESP32 trabalha com sinais lógicos de 3,3 V e não tolera diretamente tensões superiores nos GPIOs. Se necessário, utilize uma interface elétrica apropriada, como um circuito de transistor ou optoacoplador.

Por que utilizar FreeRTOS?

O FreeRTOS é um sistema operacional de tempo real utilizado em sistemas embarcados. Ele permite organizar um programa em tarefas que executam de forma concorrente, com prioridades e intervalos de execução próprios. O ambiente ESP32 disponibiliza recursos do FreeRTOS, como criação de tarefas, temporizações, filas e mutexes. Esses recursos são úteis quando diferentes partes do programa precisam trabalhar sem depender de um único laço de execução.

Neste projeto, utilizaremos duas tarefas principais:Tarefa de monitoramento: lê a entrada digital do sensor periodicamente e confirma mudanças de estado após várias amostras consecutivas.Tarefa do servidor web: atende às requisições HTTP e disponibiliza a página e a API de consulta do estado.

Como as duas tarefas precisarão acessar informações compartilhadas, utilizaremos um mutex para proteger a estrutura de dados. Isso evita que uma tarefa leia os dados durante uma atualização feita pela outra. Entenda mais sobre mutex nesse artigo: FreeRTOS – Utilizando MUTEX

Essa arquitetura também facilita a inclusão de novas funcionalidades, como histórico de eventos, comunicação MQTT ou acionamento de uma bomba.

Lista de materiais

Para montar o projeto, você precisará de:

Para desenvolver o projeto apresentado neste artigo serão utilizados alguns componentes, todos facilmente encontrados na loja da Eletrogate.

Montagem do circuito

Vamos utilizar o GPIO 27 como entrada digital para receber o sinal condicionado do sensor.

 
SinalConexão
Saída lógica condicionada do sensor, fio AmareloGPIO 27
GND da interface, fio AzulGND do ESP32
Alimentação do sensor, fio MarromVIN(5v), verifique o datasheet
Fio preto, modo de saída (pino MODE)Não usado
 Depois de montar o circuito, confira a alimentação e a continuidade das conexões antes de energizar o sistema.

Preparando o Visual Studio Code com PlatformIO

Para desenvolver o firmware, utilizaremos o Visual Studio Code com a extensão PlatformIO IDE. Veja o nosso artigo: Como Programar o Arduino com VS Code e PlatformIOComo Programar o Arduino com VS Code e PlatformIO

O PlatformIO facilita o gerenciamento de bibliotecas, a configuração da placa, a compilação e o envio do firmware ao ESP32.

Passo 1 — Instalar o VS Code

Caso ainda não tenha o ambiente instalado, baixe o Visual Studio Code pelo site oficial:https://code.visualstudio.com/Instale o programa seguindo as instruções do sistema operacional.

Passo 2 — Instalar a extensão PlatformIO IDE

No VS Code, abra a área de extensões e procure por PlatformIO IDE. Instale a extensão oficial e aguarde a inicialização do ambiente.

Passo 3 — Criar o projeto

Abra o assistente do PlatformIO e selecione a opção para criar um novo projeto.Configure os campos da seguinte forma:
  • Project Name: MonitorCaixaAgua
  • Board: Espressif ESP32 Dev Module, ou a placa equivalente utilizada;
  • Framework: Arduino.
Finalize a criação do projeto. O PlatformIO criará a estrutura inicial e o arquivo platformio.ini.

Passo 4 — Configurar o projeto

Abra o arquivo platformio.ini e utilize uma configuração semelhante à seguinte:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

monitor_speed = 115200

build_flags =
    -DCORE_DEBUG_LEVEL=1

board_build.filesystem = littlefs

Essa configuração seleciona uma placa ESP32 Dev Module, utiliza o framework Arduino e configura o monitor serial para 115200 baud. Se a sua placa possuir outra identificação, ajuste o campo board conforme a documentação do PlatformIO.

Organizando os arquivos do projeto

Para manter o código organizado, vamos separar o firmware da interface web.A estrutura ficará assim:

MonitorCaixaAgua/
├── platformio.ini
├── src/
│   └── main.cpp
└── data/
    └── index.html

O arquivo main.cpp conterá o programa do ESP32, incluindo as tarefas FreeRTOS, a leitura do sensor e o servidor HTTP. O arquivo index.html conterá a interface web, com a representação gráfica da caixa-d’água e o código JavaScript responsável pela atualização automática.

Essa separação torna o projeto mais fácil de manter e permite modificar o painel sem misturar todo o HTML ao código do firmware.

Código do firmware no VS Code

Abra o arquivo src/main.cpp e adicione o código a seguir. Ele cria o ponto de acesso Wi-Fi, inicializa o servidor HTTP e executa as tarefas independentes do FreeRTOS.O exemplo pressupõe que a interface elétrica forneça nível baixo quando o líquido for detectado. Se a sua montagem utilizar lógica inversa, altere a constante correspondente.

/*******************************************************************************
* ESP32 com FreeRTOS: Monitor de Caixa-d’Água com Sensor XKC-Y25 e Painel Web
* ============================================================================
* Artigo para o blog Eletrogate.
* ============================================================================
* @author Saulo Aislan ([email protected])
* @version 1.0
* @date 2026-10-29
* @copyright Copyright (c) 2026
*/

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <LittleFS.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

// --------------------------------------
// CONFIGURACAO DO SENSOR
// --------------------------------------

constexpr uint8_t PINO_SENSOR = 27;
constexpr bool DETECTA_EM_LOW = true;

constexpr uint8_t AMOSTRAS_CONFIRMACAO = 5;
constexpr uint32_t INTERVALO_SENSOR_MS = 100;

// --------------------------------------
// REDE WI-FI
// --------------------------------------

const char* NOME_REDE = "MonitorCaixa";
const char* SENHA_REDE = "Caixa1234";

WebServer server(80);

// --------------------------------------
// ESTADO COMPARTILHADO
// --------------------------------------

struct EstadoSistema {
  bool detectado = false;
  bool inicializado = false;

  uint32_t mudancas = 0;
  uint32_t ultimaMudancaMs = 0;
};

EstadoSistema estado;
SemaphoreHandle_t mutexEstado = nullptr;

// --------------------------------------
// LEITURA DO SENSOR
// --------------------------------------

bool lerSensor() {
  const int valor = digitalRead(PINO_SENSOR);

  if (DETECTA_EM_LOW) {
    return valor == LOW;
  }

  return valor == HIGH;
}

// --------------------------------------
// TAREFA DO SENSOR
// --------------------------------------

void tarefaSensor(void* parametro) {
  bool candidato = false;
  uint8_t contador = 0;
  bool primeiraLeitura = true;

  for (;;) {
    const bool leitura = lerSensor();

    if (primeiraLeitura) {
      candidato = leitura;
      contador = 1;
      primeiraLeitura = false;
    } else if (leitura == candidato) {
      if (contador < AMOSTRAS_CONFIRMACAO) {
        contador++;
      }
    } else {
      candidato = leitura;
      contador = 1;
    }

    bool estadoMudou = false;
    bool primeiroEstado = false;
    uint32_t totalMudancas = 0;

    if (xSemaphoreTake(
          mutexEstado,
          pdMS_TO_TICKS(50)) == pdTRUE) {

      if (contador >= AMOSTRAS_CONFIRMACAO) {
        if (!estado.inicializado) {
          estado.detectado = candidato;
          estado.inicializado = true;
          estado.ultimaMudancaMs = millis();
          estadoMudou = true;
          primeiroEstado = true;

        } else if (estado.detectado != candidato) {
          estado.detectado = candidato;
          estado.mudancas++;
          estado.ultimaMudancaMs = millis();
          estadoMudou = true;
        }
      }

      totalMudancas = estado.mudancas;
      xSemaphoreGive(mutexEstado);
    }

    if (estadoMudou) {
      Serial.print("[");
      Serial.print(millis());
      Serial.print(" ms] Sensor ");
      Serial.print(primeiroEstado ? "inicializado: " : "mudou: ");
      Serial.print(candidato ? "NIVEL DETECTADO" : "NIVEL NAO DETECTADO");

      if (!primeiroEstado) {
        Serial.print(" (mudancas: ");
        Serial.print(totalMudancas);
        Serial.print(")");
      }

      Serial.println();
    }

    vTaskDelay(
      pdMS_TO_TICKS(INTERVALO_SENSOR_MS)
    );
  }
}

// --------------------------------------
// SERVIR A PAGINA WEB
// --------------------------------------

void handlePagina() {
  server.sendHeader("Location", "/index.html");
  server.send(302, "text/plain", "");
}

// --------------------------------------
// API DE STATUS
// --------------------------------------

void handleStatus() {
  EstadoSistema copia;

  if (xSemaphoreTake(
        mutexEstado,
        pdMS_TO_TICKS(100)) != pdTRUE) {

    server.send(
      503,
      "application/json",
      "{\"erro\":\"estado indisponivel\"}"
    );

    return;
  }

  copia = estado;
  xSemaphoreGive(mutexEstado);

  String json = "{";

  json += "\"inicializado\":";
  json += copia.inicializado ? "true" : "false";

  json += ",\"detectado\":";
  json += copia.detectado ? "true" : "false";

  json += ",\"mudancas\":";
  json += String(copia.mudancas);

  json += ",\"ultimaMudancaMs\":";
  json += String(copia.ultimaMudancaMs);

  json += "}";

  server.sendHeader("Cache-Control", "no-store");
  server.send(200, "application/json", json);
}

// --------------------------------------
// TAREFA DO SERVIDOR WEB
// --------------------------------------

void tarefaWeb(void* parametro) {
  for (;;) {
    server.handleClient();
    vTaskDelay(pdMS_TO_TICKS(2));
  }
}

// --------------------------------------
// INICIALIZACAO
// --------------------------------------

void setup() {
  Serial.begin(115200);

  pinMode(PINO_SENSOR, INPUT_PULLUP);

  mutexEstado = xSemaphoreCreateMutex();

  if (mutexEstado == nullptr) {
    Serial.println("Falha ao criar mutex");

    while (true) {
      delay(1000);
    }
  }

  // Inicializa o sistema de arquivos LittleFS
  if (!LittleFS.begin(true)) {
    Serial.println("ERRO: Falha ao montar LittleFS!");

    while (true) {
      delay(1000);
    }
  }

  Serial.println("LittleFS montado com sucesso!");

  WiFi.mode(WIFI_AP);

  if (!WiFi.softAP(NOME_REDE, SENHA_REDE)) {
    Serial.println("Falha ao iniciar Wi-Fi");

    while (true) {
      delay(1000);
    }
  }

  Serial.print("Rede Wi-Fi: ");
  Serial.println(NOME_REDE);

  Serial.print("Acesse: http://");
  Serial.println(WiFi.softAPIP());

  // A pagina sera servida pelo sistema de arquivos.
  // O arquivo index.html precisa ser enviado para
  // a particao LittleFS pelo PlatformIO.
  server.serveStatic(
    "/index.html",
    LittleFS,
    "/index.html"
  );

  server.on("/", HTTP_GET, handlePagina);
  server.on("/api/status", HTTP_GET, handleStatus);

  server.begin();

  // Tarefa de leitura do sensor
  BaseType_t sensorOk = xTaskCreate(
    tarefaSensor,
    "LeituraSensor",
    3072,
    nullptr,
    2,
    nullptr
  );

  // Tarefa de atendimento HTTP
  BaseType_t webOk = xTaskCreate(
    tarefaWeb,
    "ServidorWeb",
    6144,
    nullptr,
    1,
    nullptr
  );

  if (sensorOk != pdPASS || webOk != pdPASS) {
    Serial.println("Falha ao criar tarefas");

    while (true) {
      delay(1000);
    }
  }

  Serial.println("Sistema iniciado.");
}

void loop() {
  vTaskDelay(pdMS_TO_TICKS(1000));
}

Criando o painel web em HTML

Agora vamos criar a interface gráfica.No VS Code, crie a pasta data na raiz do projeto e, dentro dela, o arquivo index.html.A página tem uma caixa-d’água desenhada em CSS, uma marcação para o ponto de detecção do sensor e um indicador de estado. O JavaScript consulta a API /api/status a cada dois segundos.

<!DOCTYPE html>
<html lang="pt-BR">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, initial-scale=1">

  <title>Monitor de Caixa-d'Agua</title>

  <style>
    * {
      box-sizing: border-box;
    }

    body {
      margin: 0;
      padding: 20px;
      font-family: Arial, sans-serif;
      background: #edf2f7;
      color: #1e293b;
    }

    .painel {
      max-width: 460px;
      margin: 20px auto;
      padding: 24px;
      background: white;
      border-radius: 18px;
      text-align: center;
      box-shadow: 0 6px 24px #00000012;
    }

    .estado {
      padding: 13px;
      margin: 15px 0;
      border-radius: 10px;
      font-weight: bold;
    }

    .ok {
      background: #dcfce7;
      color: #166534;
    }

    .alerta {
      background: #ffedd5;
      color: #9a3412;
    }

    .erro {
      background: #fee2e2;
      color: #991b1b;
    }

    .caixa {
      position: relative;
      width: 190px;
      height: 245px;
      margin: 24px auto;
      border: 5px solid #475569;
      border-top: 0;
      border-radius: 0 0 17px 17px;
      background: #f8fafc;
      overflow: visible;
    }

    .agua {
      position: absolute;
      left: 0;
      right: 0;
      bottom: 0;
      height: 0;
      background: #38bdf8;
      transition: height 0.5s ease;
    }

    .sensor-linha {
      position: absolute;
      left: -15px;
      right: -15px;
      bottom: 55%;
      border-top: 2px dashed #ea580c;
      z-index: 2;
    }

    .sensor-texto {
      position: absolute;
      left: 100%;
      top: -12px;
      padding-left: 8px;
      width: 100px;
      font-size: 11px;
      text-align: left;
      color: #c2410c;
    }

    .detalhes {
      padding: 13px;
      background: #f8fafc;
      border-radius: 10px;
      text-align: left;
      font-size: 14px;
      line-height: 1.8;
    }
  </style>
</head>

<body>
  <main class="painel">
    <h1>Monitor de Caixa-d'Agua</h1>

    <div id="estado" class="estado alerta">
      Consultando sensor...
    </div>

    <div class="caixa">
      <div id="agua" class="agua"></div>

      <div class="sensor-linha">
        <span class="sensor-texto">
          Ponto de deteccao
        </span>
      </div>
    </div>

    <p id="legenda">
      Aguardando dados do sensor.
    </p>

    <div class="detalhes">
      <div>Estado: <strong id="detalhe">--</strong></div>
      <div>Mudancas: <strong id="mudancas">0</strong></div>
      <div>Ultima mudanca: <strong id="mudanca">--</strong></div>
    </div>

    <p id="conexao">
      Atualizacao automatica a cada 2 segundos.
    </p>
  </main>

  <script>
    async function atualizarPainel() {
      const estado = document.getElementById("estado");
      const agua = document.getElementById("agua");

      try {
        const resposta = await fetch("/api/status", {
          cache: "no-store"
        });

        if (!resposta.ok) {
          throw new Error("Erro HTTP");
        }

        const dados = await resposta.json();

        if (!dados.inicializado) {
          estado.textContent = "INICIALIZANDO SENSOR";
          estado.className = "estado alerta";
          agua.style.height = "0%";
        } else if (dados.detectado) {
          estado.textContent = "NÍVEL DETECTADO";
          estado.className = "estado ok";
          agua.style.height = "55%";
        } else {
          estado.textContent = "NÍVEL NAO DETECTADO";
          estado.className = "estado alerta";
          agua.style.height = "20%";
        }

        document.getElementById("detalhe").textContent =
          !dados.inicializado
            ? "Aguardando"
            : (dados.detectado ? "Detectado" : "Nao detectado");

        document.getElementById("mudancas").textContent =
          dados.mudancas;

        document.getElementById("mudanca").textContent =
          dados.ultimaMudancaMs + " ms";

        document.getElementById("conexao").textContent =
          "Conectado ao ESP32";

        document.getElementById("legenda").textContent =
          dados.detectado
            ? "Liquido presente na altura do sensor."
            : "Liquido nao detectado nessa altura.";

      } catch (erro) {
        estado.textContent = "SEM COMUNICACAO";
        estado.className = "estado erro";

        document.getElementById("conexao").textContent =
          "Nao foi possivel consultar o ESP32.";
      }
    }

    atualizarPainel();
    setInterval(atualizarPainel, 2000);
  </script>
</body>
</html>
 

Entendendo as informações do painel

Na interface web, três informações ajudam a acompanhar o funcionamento do sistema:
  • Estado: indica se o líquido foi detectado pelo sensor na altura em que ele está instalado. O estado pode ser “Detectado” ou “Não detectado”.
  • Mudanças: contabiliza quantas vezes o estado do sensor mudou desde que o ESP32 foi ligado. Por exemplo, se o sensor alternar entre detectar e não detectar água, esse contador aumentará.
  • Última mudança: informa o tempo, em milissegundos, registrado desde a inicialização do ESP32 até a última mudança de estado do sensor. Esse valor não representa o tempo decorrido desde a última mudança até o momento atual.
Essas informações permitem acompanhar as alterações no nível da água e verificar o comportamento do sensor durante a operação. Vale lembrar que o sensor identifica a presença de líquido em um ponto específico, não medindo diretamente o volume ou a porcentagem de água na caixa.

Como compilar e executar no VS Code

Configurando o LittleFS no PlatformIO

Como a interface foi separada do firmware, precisamos enviar o arquivo index.html para a memória de arquivos do ESP32. No PlatformIO, mantenha a pasta data na raiz do projeto. Em seguida, execute a tarefa PlatformIO: Build Filesystem Image na paleta de comandos do VS Code e depois PlatformIO: Upload Filesystem Image, conforme as opções disponíveis na versão instalada.
Com os arquivos criados, siga esta sequência:
  1. Conecte o ESP32 ao computador.
  2. Abra o projeto MonitorCaixaAgua no VS Code.
  3. Clique em Build para compilar o firmware.
  4. Corrija eventuais erros de compilação.
  5. Clique em Upload para gravar o programa.
  6. Execute Build Filesystem Image.
  7. Execute Upload Filesystem Image para enviar a página web.
  8. Abra o monitor serial em 115200 baud.
  9. Conecte o celular à rede MonitorCaixa.
  10. Acesse o endereço informado no monitor serial, normalmente http://192.168.4.1.
A página deverá mostrar a caixa-d’água esquemática e o estado do sensor. Ao mudar a condição de detecção, a interface será atualizada automaticamente.

Testes e solução de problemas

  • A compilação falha. Verifique se o pacote ESP32 está instalado e se a placa selecionada corresponde ao hardware utilizado.
  • A página não abre. Confirme se o arquivo index.html foi enviado para o LittleFS e se o servidor HTTP foi iniciado.
  • O sensor indica o estado incorreto. Revise a ligação elétrica, a lógica da saída e a configuração DETECTA_EM_LOW.
  • A leitura oscila. Confira a fixação do sensor, a alimentação e a compatibilidade do recipiente. O filtro por amostras consecutivas ajuda a reduzir oscilações breves, mas não resolve problemas físicos de instalação.
  • O ESP32 reinicia. Verifique a alimentação e certifique-se de que nenhuma entrada recebe tensão superior à permitida.

Possibilidades de expansão

Uma das principais possibilidades de expansão do projeto é utilizar dois sensores XKC-Y25 instalados em alturas diferentes da caixa-d’água. Dessa forma, podemos monitorar os níveis mínimo e máximo do reservatório, tornando o sistema mais útil para aplicações de automação.O primeiro sensor deve ser instalado próximo ao nível mínimo desejado, enquanto o segundo deve ficar próximo ao nível máximo. Cada sensor será conectado a uma entrada digital do ESP32, permitindo que o firmware identifique as condições do reservatório.Com essa configuração, o sistema poderá trabalhar com três condições principais:

  • Nível baixo: o líquido não é detectado pelo sensor instalado na altura mínima, indicando que o reservatório pode precisar de abastecimento.
  • Nível intermediário: o sensor inferior detecta a presença de líquido, mas o sensor superior ainda não detecta. Isso indica que o nível está entre os dois pontos de detecção.
  • Nível alto: os dois sensores detectam a presença de líquido, indicando que o reservatório atingiu ou ultrapassou a altura do sensor superior.
Essas condições podem ser representadas visualmente no painel web. A interface poderá destacar o nível baixo com um alerta, apresentar o nível intermediário como condição normal de acompanhamento e indicar quando a água atingir o nível máximo.

Além do monitoramento, essa configuração permite implementar um sistema automático de controle de bomba. Por exemplo, quando o nível cair abaixo do sensor inferior, o ESP32 poderá solicitar o acionamento da bomba.

Quando a água atingir o sensor superior, o sistema poderá solicitar seu desligamento. Para evitar acionamentos frequentes, o firmware deverá manter o estado de operação entre os dois limites.

Essa expansão mantém a arquitetura baseada em FreeRTOS: a tarefa de monitoramento passa a ler os dois sensores, enquanto a tarefa do servidor web disponibiliza os estados atualizados para o navegador.

A API também poderá informar separadamente o estado de cada sensor, permitindo que o painel apresente os níveis mínimo e máximo de forma independente.

É importante destacar que dois sensores fornecem detecção por pontos, e não uma medição contínua da porcentagem de água. O nível intermediário representa apenas a região entre os sensores, e não um percentual exato do volume armazenado.

Resultado

Vídeo demonstrando da detecção do nível da água na garrafa. Observação na demonstração o sensor é um pouco diferente do descrito no artigo, mas o principio é o mesmo.

Conclusão

Neste tutorial, desenvolvemos a base de um sistema de monitoramento de caixa-d’água utilizando ESP32, FreeRTOS, sensor XKC-Y25 e uma interface web.

A utilização do Visual Studio Code com PlatformIO permite organizar o firmware em arquivos separados, compilar o projeto e gerenciar o sistema de arquivos utilizado pela página web.

Com tarefas independentes, sincronização por mutex e atualização automática da interface, o projeto demonstra como combinar programação embarcada, comunicação HTTP e visualização de dados em uma única aplicação.

O resultado é um ponto de partida para soluções mais completas de monitoramento e automação de reservatórios.

Para mais materiais como esse, continue acompanhando as postagens semanais do blog e não deixe de visitar nossa loja. Lá você encontra todos os componentes necessários para desenvolver esse e muitos outros projetos!

Que a força esteja com você! Até mais!

Neste projeto, vamos construir um monitor de nível utilizando o ESP32 e o sensor XKC-Y25, com uma interface web acessível pelo celular ou computador.

Precisa dos componentes para este projeto?

Encontre tudo na Loja Eletrogate com frete grátis para compras acima de R$ 200