so basically i built a water tank monitor that uses an ESP32 and an ultrasonic sensor to check if the tank is full or empty, then sends an MQTT message so a Go server can do something about it. right now the Go server sends the alert to WhatsApp and Telegram, because apparently one notification app was not enough.
I drew this diagram. Best way i can explain wtf this is:
the ESP32 reads the distance from the water surface using a HC-SR04 ultrasonic sensor. if the water is low, it publishes to message_pump_on (turn pump on). if the water is high enough, it publishes to message_pump_off (turn pump off).
the Go server runs an embedded MQTT broker so the ESP32 connects directly to your machine. the server subscribes to both topics and forwards the messages to WhatsApp using the Meta Cloud API, and to Telegram using a bot you make yourself.
for Telegram, the app checks the bot updates, grabs the chat id from whoever has messaged the bot, then saves that chat id in a little SQLite database. so yeah, the chat id is stored. once it has it, it can keep using that same chat id for pump alerts instead of begging Telegram for it every single time.
when the broker receives message_pump_on, it sends pump is turned on. when it receives message_pump_off, it sends pump is turned off.
i also added a retry system on the Arduino side because the water turbulence was making the pump toggle on and off rapidly. not the cleanest fix but it works.
- ESP32 - the microcontroller
- HC-SR04 - ultrasonic distance sensor (TRIG on pin 1, ECHO on pin 3)
- a pump or relay or whatever you're trying to control
this is the wiring i used in the sketch. nothing fancy, just don't mix up trig and echo or you will be debugging the wrong thing for no reason. I did that
ESP32 HC-SR04
----- -------
5V / VIN ------------------> VCC
GND ------------------> GND
GPIO 1 ------------------> TRIG
GPIO 3 <------------------ ECHO
small warning: the HC-SR04 echo pin can output 5V, and most ESP32 C3 pins want 3.3V. use a voltage divider on ECHO if your sensor board does not already handle that (I did not do this, btw because i am lazy and i fried some pins😂😂😂)
something like this works:
HC-SR04 ECHO ---- 1k resistor ----+---- ESP32 GPIO 3
|
2k resistor
|
GND
This is the Pin layout for the ESP 32 C3 Super Mini used in this project
- Arduino IDE
- WiFi - comes with the ESP32 board package
- PubSubClient - MQTT client library for Arduino. install it from the library manager in the IDE
you need Go installed. then run this in the mqtt_broker folder:
go mod tidythat pulls everything. the main packages are:
mochi-mqtt/server- this is the embedded MQTT broker, so you don't need to install mosquitto or anything externalpaho.mqtt.golang- the Go MQTT client that connects to the brokergowhatsapp- for sending WhatsApp messages via the Meta Cloud API- Telegram Bot API - for sending Telegram messages to whoever has chatted with your bot
modernc.org/sqlite- stores the Telegram chat ids locally so the bot remembers who to annoygodotenv- loads credentials from a.envfile so i don't have to hardcode them
cd mqtt_brokercopy the example file so you don't have to freestyle the env names:
cp .env.example .envon Windows PowerShell:
Copy-Item .env.example .envthen fill in the values with your actual stuff:
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id
WHATSAPP_ACCESS_TOKEN=your_access_token
WHATSAPP_RECIPIENT_NUMBER=recipient_phone_number_with_country_code
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
do not commit your real .env file. keep the token stuff private unless you enjoy pain.
get the WhatsApp values from Meta's developer platform. the flow is basically:
- create or open a Meta app
- add WhatsApp to the app
- go to WhatsApp > API Setup
- copy the phone number ID into
WHATSAPP_PHONE_NUMBER_ID - copy the access token into
WHATSAPP_ACCESS_TOKEN - set
WHATSAPP_RECIPIENT_NUMBERto the phone number you want to notify, including country code
for testing, Meta might make you add the recipient phone number as a test recipient first. if messages are not sending, check that before blaming the code.
this part is actually pretty chill:
- open Telegram and search for
@BotFather - send
/newbot - choose a bot name and username
- copy the bot token into
TELEGRAM_BOT_TOKEN - open your new bot in Telegram and send it any message, like
start
that last step matters because the app gets chat IDs from Telegram updates. if nobody has messaged the bot yet, the Go server has no chat IDs to send to, so it just has nobody to bother.
once the app sees your chat id, it stores it in SQLite under your user config folder at d3uc3y/water_pump_regulator/database/store.db. so most times you only need to message the bot once. after that, the saved chat id is used when pump alerts come in.
if you want the bot to notify a group, add the bot to the group and send a message in that group so Telegram creates an update for it. after that, the bot can pick up the group chat id too.
on Windows:
ipconfiglook for the IPv4 address under your WiFi adapter. it usually starts with 192.168.x.x.
in water_pump_regulator.ino, set your WiFi credentials and your machine's IP:
const char *ssid = "your_wifi_name";
const char *password = "your_wifi_password";
const char *mqtt_server = "192.168.x.x"; // your machine's IPmake sure your machine and the ESP32 are on the same WiFi network or this won't work, broski.
this one got me. the ESP32 kept failing to connect with rc=-2 and i could not figure out why for a while. turns out Windows Firewall was just blocking the port the whole time, lol.
open PowerShell as administrator (right-click → run as administrator) and run:
New-NetFirewallRule -DisplayName "MQTT Broker" -Direction Inbound -Protocol TCP -LocalPort 1883 -Action Allowyou only need to do this once. if you skip this step, the ESP32 will not connect, full stop.
go run .open water_pump_regulator.ino in the Arduino IDE and upload it.
.
├── mqtt_broker/ # the Go server
│ ├── main.go
│ ├── .env.example
│ └── internal/
│ ├── config/ # loads .env
│ ├── mqtt/ # embedded broker + subscriber + notification router thing
│ ├── storage/ # SQLite stuff + saved Telegram chat ids
│ ├── telegram/ # sends Telegram bot messages
│ └── whatsapp/ # sends WhatsApp messages
└── water_pump_regulator/
└── water_pump_regulator.ino # the Arduino sketch