Skip to content
Buy 10+ on select items — save 10% auto-applied
Free US shipping on orders $35+
Order by 3pm ET — ships same-day from the US
Skip to main content

ESP32 Telegram Bot: Remote Relay Pump Control | ShillehTek

September 14, 2026 6 views

ESP32 Telegram Bot: Remote Relay Pump Control | ShillehTek
Project

Build an ESP32 Telegram bot to switch a relay-driven pump with /on, /off, timers, and status replies, plus a local button override using ShillehTek parts.

45 min Intermediate6 parts

Project Overview

ESP32 Telegram Bot - Switch a Pump or Any Relay From Your Phone With Chat Commands, Timers and Status Replies: Build an ESP32 + Telegram bot relay controller that switches a pump (or any relay load) from your phone using chat commands, timed runs, and status replies. The ESP32 polls Telegram every second, answers commands like /on, /on60, /off and /status, drives a relay for a water pump (or a lamp, heater, or fan), and tells you when a timed run finishes. A physical button on the board still works and reports what it did. No port forwarding, no cloud dashboard, no monthly fee.

  • Time: ~45 minutes
  • Skill level: Intermediate
  • What you will build: A private Telegram bot with on/off/timed commands, a status query, chat-ID security, a local override button, and push notifications back to your phone.
ESP32 dev board wired to a 1-channel relay module controlling a water pump via Telegram commands
Type a command in Telegram and the relay clicks in the garden.

Parts List

From ShillehTek

External

  • A small submersible pump (5 V or 12 V) with its own supply, plus tubing, or any load you want to switch
  • A Telegram account

Note: The relay contacts are isolated, so the pump gets its own supply and only its positive wire passes through COM/NO. Keep this to low-voltage DC loads unless you are comfortable with mains wiring and a proper enclosure. The bot only obeys your own chat ID; anyone else who finds it gets a polite refusal.

Step-by-Step Guide

Step 1 - Create the Bot and Find Your Chat ID

Goal: Get the two strings the sketch needs.

What to do: In Telegram, open @BotFather, send /newbot, give it a display name and a username ending in "bot", and copy the token it replies with (looks like 123456789:AAF…). Then open @userinfobot (or @myidbot and send /getid) to get your numeric chat ID.

Finally open your new bot and press Start. A bot cannot message you until you have messaged it once.

Expected result: A bot token and a chat ID.

Step 2 - Wire the Relay and Button

Goal: Put the ESP32 in control of the pump.

What to do: Relay module: IN → GPIO22, VCC → 5V (from the ESP32's VIN/5V pin or the MB102), GND → GND. Pump: supply + → relay COM, relay NO → pump +, pump − → supply −. Button: GPIO23 to GND (internal pull-up).

Most of these relay modules are active-LOW. The sketch has a RELAY_ON constant to flip if yours clicks the wrong way.

Expected result: Relay off at boot and pump silent.

Step 3 - The Sketch

Code:

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>      // "UniversalTelegramBot" by Brian Lough (+ ArduinoJson)
#include <ArduinoJson.h>

const char* SSID = "YourNetwork";
const char* PASS = "YourPassword";
#define BOT_TOKEN "123456789:AAF-your-token-from-BotFather"
#define CHAT_ID   "123456789"           // your numeric chat id: only this chat is obeyed

const int RELAY = 22, BTN = 23;
const int RELAY_ON = LOW;               // most 1-channel modules are active-LOW; use HIGH if yours isn't

WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);
bool pumpOn = false;
unsigned long offAt = 0;                // millis() when a timed run should stop (0 = no timer)

void setPump(bool on, unsigned long ms = 0) {
  pumpOn = on;
  digitalWrite(RELAY, on ? RELAY_ON : !RELAY_ON);
  offAt = (on && ms) ? millis() + ms : 0;
}

void handleMessages(int n) {
  for (int i = 0; i < n; i++) {
    String chat = bot.messages[i].chat_id, text = bot.messages[i].text;
    if (chat != CHAT_ID) { bot.sendMessage(chat, "Sorry, this bot is private.", ""); continue; }
    if      (text == "/on")     { setPump(true);        bot.sendMessage(chat, "Pump ON", ""); }
    else if (text == "/on10")   { setPump(true, 10000); bot.sendMessage(chat, "Pump ON for 10 s", ""); }
    else if (text == "/on60")   { setPump(true, 60000); bot.sendMessage(chat, "Pump ON for 60 s", ""); }
    else if (text == "/off")    { setPump(false);       bot.sendMessage(chat, "Pump OFF", ""); }
    else if (text == "/status") {
      bot.sendMessage(chat, String("Pump is ") + (pumpOn ? "ON" : "OFF") + (offAt ? " (timed)" : ""), "");
    } else {
      bot.sendMessage(chat, "Commands:\n/on - run\n/on10 - run 10 s\n/on60 - run 60 s\n/off - stop\n/status", "");
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY, OUTPUT); setPump(false);
  pinMode(BTN, INPUT_PULLUP);
  WiFi.begin(SSID, PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);    // ships with the library (or client.setInsecure())
  configTime(0, 0, "pool.ntp.org");                // TLS needs the real time
  bot.sendMessage(CHAT_ID, "Pump controller online at " + WiFi.localIP().toString(), "");
}

void loop() {
  static unsigned long lastPoll = 0; static bool btnWas = true;

  if (millis() - lastPoll >= 1000) {                                 // ask Telegram for new messages
    lastPoll = millis();
    int n = bot.getUpdates(bot.last_message_received + 1);
    while (n) { handleMessages(n); n = bot.getUpdates(bot.last_message_received + 1); }
  }

  if (offAt && millis() >= offAt) {                                  // timed run finished
    setPump(false);
    bot.sendMessage(CHAT_ID, "Timer done, pump OFF", "");
  }

  bool btn = digitalRead(BTN);                                       // local override button
  if (!btn && btnWas) {
    setPump(!pumpOn);
    bot.sendMessage(CHAT_ID, pumpOn ? "Button: pump ON" : "Button: pump OFF", "");
    delay(50);
  }
  btnWas = btn;
}

What to do: Install "UniversalTelegramBot" and ArduinoJson from the Library Manager, paste in Wi-Fi details, token and chat ID, then upload.

Expected result: Your phone buzzes: "Pump controller online at 192.168.x.x". Send /on10 and the relay clicks, "Pump ON for 10 s" comes back, and ten seconds later "Timer done, pump OFF". Press the button and the bot reports "Button: pump ON". Send anything else and you get the command list.

Step 4 - How It Works (and Why It's Safe)

Goal: Understand polling and the security model.

What to do: The ESP32 makes an outbound HTTPS request to Telegram once a second asking "anything new since message N?". That is why it works behind any home router with no open ports. Replies are just more outbound requests.

Because every message carries the sender's chat ID, the sketch compares it to yours and ignores everyone else. The bot token is the only secret, so keep it out of screenshots. The library's certificate keeps the connection verified. If Telegram rotates certificates years from now, setInsecure() is the quick fix.

Expected result: A remote control you would trust with a pump.

Step 5 - Make It a Garden System

Goal: Go beyond one relay.

What to do: Add a capacitive soil sensor and a /soil command, or have the bot message you when the soil dries out and ask "water for 60 s? /on60". Add a second relay for a light with /lamp. Send a daily report at 8 am. Add a flow sensor and report litres delivered after each run. Use Telegram's inline keyboards (sendMessageWithInlineKeyboard) for tappable ON/OFF buttons instead of typed commands.

Expected result: A garden that texts you.

Conclusion

A bot token, a chat ID, and a polling loop turn Telegram into a free, secure remote control for anything an ESP32 can switch through a relay. This same pattern can also carry sensors and alerts back to your phone.

Want the exact parts used in this build? Grab them from ShillehTek.com. If you want help customizing this project or building something for your product, check out our IoT consulting services.

Image credit and reference: carlosvolt on Hackster.io (LGPL license).

Parts for this build

Everything used in this tutorial. Uncheck what you already have.

All 6 in stock
0 parts selected $0.00