ESP32 Telegram-Bot bauen: Relais schalten & Sensorwerte aufs Handy – ohne eigene App

Du sitzt im Büro und fragst dich, ob zu Hause die Heizung im Bastelkeller noch läuft? Schick deinem ESP32 einfach eine Telegram-Nachricht. Ein Telegram-Bot ist der wohl schnellste Weg, deine Mikrocontroller-Projekte von überall auf der Welt zu steuern – ohne eigene App, ohne Portfreigabe im Router, ohne Cloud-Abo. Der ESP32 holt sich seine Befehle selbst bei den Telegram-Servern ab und schickt dir Messwerte und Alarme direkt aufs Handy. In diesem Tutorial legst du Schritt für Schritt einen eigenen Bot an, schaltest ein Relais per Chat-Befehl, fragst einen DHT22-Sensor ab und baust einen automatischen Temperatur-Alarm – inklusive Absicherung, damit wirklich nur du die Kontrolle hast.

Warum Telegram die perfekte IoT-Fernbedienung ist

Ein ESP32-Webserver ist großartig – solange du im heimischen WLAN bist. Von unterwegs erreichst du ihn nur mit Portfreigaben oder VPN, beides mit Sicherheits- und Bastelaufwand verbunden. Der Telegram-Trick dreht die Richtung um: Nicht du verbindest dich zum ESP32, sondern der ESP32 fragt regelmäßig bei den Telegram-Servern nach, ob neue Nachrichten für ihn vorliegen (Polling). Ausgehende Verbindungen erlaubt jeder Router – es funktioniert also im Heimnetz, im Uni-WLAN und am Handy-Hotspot, komplett ohne Netzwerk-Konfiguration.

  • Keine eigene App nötig: Telegram hast du (oder deine Familie) vermutlich eh auf dem Handy
  • Beide Richtungen: Befehle an den ESP32 senden und Alarme vom ESP32 empfangen
  • Kostenlos: Die Telegram-Bot-API ist gratis und ohne Limits für Hobby-Projekte
  • Verschlüsselt: Die Verbindung läuft über HTTPS/TLS

Das brauchst du

ESP32 Entwicklungsboard (USB-C) – WLAN an Bord, genügend Power für TLS-Verschlüsselung
KY-019 Relais-Modul (1 Kanal) – schaltet Lampe, Pumpe oder Lüfter per Chat-Befehl
DHT22 (AM2302) Temperatur- & Feuchtigkeitssensor – liefert die Messwerte für Abfrage und Alarm
Breadboard mit 400 Kontakten – für den fliegenden Aufbau
Telegram-Account + Arduino IDE – dazu die Bibliotheken UniversalTelegramBot und ArduinoJson aus dem Bibliotheksverwalter

Verkabelung

Bauteil Pin am Modul ESP32-Pin
KY-019 Relais VCC (+) 5V / VIN
KY-019 Relais GND (-) GND
KY-019 Relais Signal (S) GPIO 26
DHT22 VCC (+) 3.3V
DHT22 GND (-) GND
DHT22 DATA GPIO 4

⚠️ Netzspannung ist tabu: Das Relais kann theoretisch 230-V-Geräte schalten – für Bastelprojekte bleib bitte bei Kleinspannung (LED-Streifen, 12-V-Pumpen, Lüfter). Netzspannung gehört in die Hände einer Elektrofachkraft. Details zum Relais findest du im KY-019 Relais-Tutorial.

1Bot anlegen beim BotFather

Telegram-Bots werden – sehr passend – vom BotFather verwaltet, einem offiziellen Telegram-Bot. So bekommst du in zwei Minuten deinen eigenen:

  1. Öffne Telegram und suche nach @BotFather (blauer Haken = der echte)
  2. Sende /newbot und folge dem Dialog: erst ein Anzeigename (z. B. „Bastelkeller Bot"), dann ein Benutzername, der auf bot enden muss (z. B. bastelkeller_42_bot)
  3. Der BotFather antwortet mit deinem Bot-Token – einer langen Zeichenkette wie 7123456789:AAH3xF.... Das ist der Generalschlüssel zu deinem Bot: kopieren und geheim halten!
  4. Jetzt fehlt noch deine Chat-ID: Suche den Bot @userinfobot, sende ihm eine beliebige Nachricht – er antwortet mit deiner numerischen ID (z. B. 123456789)
  5. Wichtig: Öffne den Chat mit deinem neuen Bot und sende einmal /start – erst danach darf der Bot dir Nachrichten schicken

ℹ️ Token versehentlich veröffentlicht? Kein Drama: Beim BotFather kannst du mit /revoke jederzeit ein neues Token erzeugen – das alte wird sofort ungültig. Trotzdem gilt: Token niemals in öffentliche Repositories oder Foren-Posts kopieren.

2Erster Test: Der ESP32 meldet sich bei dir

Installiere im Bibliotheksverwalter der Arduino IDE die Bibliotheken UniversalTelegramBot (von Brian Lough) und ArduinoJson. Dieser Minimal-Sketch verbindet sich mit dem WLAN und schickt dir eine Startnachricht aufs Handy:

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

const char* WLAN_NAME     = "DeinWLAN";
const char* WLAN_PASSWORT = "DeinPasswort";
const char* BOT_TOKEN     = "7123456789:AAH3xF...";  // vom BotFather
const char* CHAT_ID       = "123456789";             // deine Chat-ID

WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);

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

  WiFi.mode(WIFI_STA);
  WiFi.begin(WLAN_NAME, WLAN_PASSWORT);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWLAN verbunden!");

  // Telegram-Root-Zertifikat setzen - noetig fuer die TLS-Verbindung
  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);

  bot.sendMessage(CHAT_ID, "ESP32 ist online und hoert auf deine Befehle!", "");
}

void loop() {}

Wenn nach dem Upload die Nachricht auf deinem Handy aufploppt, steht die Verbindung – der spannendste Moment des Projekts. Kommt nichts an, hilft der Troubleshooting-Abschnitt unten.

3Befehle empfangen: Relais per Chat schalten

Jetzt die Rückrichtung: Der ESP32 fragt alle Sekunde bei Telegram nach neuen Nachrichten und reagiert auf Befehle. Der Sketch versteht /an, /aus und /status – und ignoriert Nachrichten von Fremden:

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

const char* WLAN_NAME     = "DeinWLAN";
const char* WLAN_PASSWORT = "DeinPasswort";
const char* BOT_TOKEN     = "7123456789:AAH3xF...";
const char* CHAT_ID       = "123456789";

const int RELAIS = 26;

WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);

unsigned long letzteAbfrage = 0;
const unsigned long ABFRAGE_INTERVALL = 1000;   // alle 1000 ms nachsehen

void verarbeiteNachrichten(int anzahl) {
  for (int i = 0; i < anzahl; i++) {
    String absender = bot.messages[i].chat_id;
    String text     = bot.messages[i].text;

    // Sicherheits-Check: nur DEINE Chat-ID darf steuern
    if (absender != CHAT_ID) {
      bot.sendMessage(absender, "Keine Berechtigung.", "");
      continue;
    }

    if (text == "/start") {
      String hilfe = "Befehle:\n";
      hilfe += "/an - Relais einschalten\n";
      hilfe += "/aus - Relais ausschalten\n";
      hilfe += "/status - aktueller Zustand";
      bot.sendMessage(CHAT_ID, hilfe, "");
    }
    else if (text == "/an") {
      digitalWrite(RELAIS, HIGH);
      bot.sendMessage(CHAT_ID, "Relais ist AN", "");
    }
    else if (text == "/aus") {
      digitalWrite(RELAIS, LOW);
      bot.sendMessage(CHAT_ID, "Relais ist AUS", "");
    }
    else if (text == "/status") {
      bool an = digitalRead(RELAIS);
      bot.sendMessage(CHAT_ID, an ? "Relais laeuft (AN)" : "Relais ist AUS", "");
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAIS, OUTPUT);
  digitalWrite(RELAIS, LOW);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WLAN_NAME, WLAN_PASSWORT);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
  bot.sendMessage(CHAT_ID, "Relais-Bot bereit! /start fuer Hilfe", "");
}

void loop() {
  // nicht-blockierend: alle 1000 ms bei Telegram nachfragen
  if (millis() - letzteAbfrage >= ABFRAGE_INTERVALL) {
    letzteAbfrage = millis();
    int anzahl = bot.getUpdates(bot.last_message_received + 1);
    while (anzahl) {
      verarbeiteNachrichten(anzahl);
      anzahl = bot.getUpdates(bot.last_message_received + 1);
    }
  }
}

💡 Das millis()-Muster im Einsatz: Die Telegram-Abfrage läuft nicht-blockierend – zwischen den Abfragen bleibt der loop() frei für Sensoren, Displays oder weitere Aufgaben. Wie dieses Muster genau funktioniert, erklärt das Tutorial millis() statt delay().

4Sensorwerte abfragen & automatischer Temperatur-Alarm

Zum Abschluss das Komplettpaket: Auf /temperatur antwortet der Bot mit den aktuellen DHT22-Werten – und überschreitet die Temperatur einen Grenzwert, schlägt der ESP32 von selbst Alarm (aber nur einmal pro Grenzwert-Überschreitung, nicht im Sekundentakt):

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>
#include <DHT.h>

const char* WLAN_NAME     = "DeinWLAN";
const char* WLAN_PASSWORT = "DeinPasswort";
const char* BOT_TOKEN     = "7123456789:AAH3xF...";
const char* CHAT_ID       = "123456789";

#define DHT_PIN  4
#define DHT_TYP  DHT22
DHT dht(DHT_PIN, DHT_TYP);

const float ALARM_GRENZE = 30.0;   // Grad Celsius
bool alarmAktiv = false;           // merkt sich, ob schon gewarnt wurde

WiFiClientSecure client;
UniversalTelegramBot bot(BOT_TOKEN, client);

unsigned long letzteAbfrage = 0;
unsigned long letzteMessung = 0;

void verarbeiteNachrichten(int anzahl) {
  for (int i = 0; i < anzahl; i++) {
    if (bot.messages[i].chat_id != CHAT_ID) continue;
    String text = bot.messages[i].text;

    if (text == "/temperatur") {
      float t = dht.readTemperature();
      float h = dht.readHumidity();
      if (isnan(t) || isnan(h)) {
        bot.sendMessage(CHAT_ID, "Sensorfehler - bitte Verkabelung pruefen.", "");
      } else {
        String antwort = "Aktuell: " + String(t, 1) + " Grad, ";
        antwort += String(h, 0) + " % Luftfeuchte";
        bot.sendMessage(CHAT_ID, antwort, "");
      }
    }
  }
}

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

  WiFi.mode(WIFI_STA);
  WiFi.begin(WLAN_NAME, WLAN_PASSWORT);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
  bot.sendMessage(CHAT_ID, "Temperatur-Waechter aktiv! /temperatur fuer Werte", "");
}

void loop() {
  // Aufgabe 1: alle Sekunde Telegram-Befehle abholen
  if (millis() - letzteAbfrage >= 1000) {
    letzteAbfrage = millis();
    int anzahl = bot.getUpdates(bot.last_message_received + 1);
    while (anzahl) {
      verarbeiteNachrichten(anzahl);
      anzahl = bot.getUpdates(bot.last_message_received + 1);
    }
  }

  // Aufgabe 2: alle 30 Sekunden messen und ggf. Alarm ausloesen
  if (millis() - letzteMessung >= 30000) {
    letzteMessung = millis();
    float t = dht.readTemperature();
    if (isnan(t)) return;

    if (t > ALARM_GRENZE && !alarmAktiv) {
      alarmAktiv = true;   // nur EINMAL warnen
      bot.sendMessage(CHAT_ID,
        "ALARM: " + String(t, 1) + " Grad - Grenzwert ueberschritten!", "");
    }
    if (t < ALARM_GRENZE - 2.0 && alarmAktiv) {
      alarmAktiv = false;  // 2 Grad Hysterese gegen Alarm-Pingpong
      bot.sendMessage(CHAT_ID,
        "Entwarnung: " + String(t, 1) + " Grad - wieder im gruenen Bereich.", "");
    }
  }
}

Die Hysterese (Entwarnung erst 2 Grad unter der Alarmgrenze) verhindert, dass der Bot dich bei 29,9–30,1 Grad mit Alarm/Entwarnung im Minutentakt bombardiert – ein kleiner Kniff mit großer Wirkung. Mehr zum DHT22 und seinen Eigenheiten steht im ESP32-Wetterstations-Tutorial.

Ideen zum Weiterbauen

💡 Was dein Bot noch lernen kann

  • Mehrere Nutzer erlauben: Statt einer Chat-ID ein Array erlaubter IDs pflegen – praktisch für die Familie
  • Antwort-Tastatur: Mit sendMessageWithReplyKeyboard() bekommt der Chat Buttons wie „An" und „Aus" – kein Befehle-Tippen mehr
  • Bewässerungs-Bot: Kombiniere das Relais mit dem kapazitiven Bodenfeuchte-Sensor – die Pumpe läuft auf Befehl oder meldet trockene Erde
  • Tür- und Bewegungsmelder: Ein HC-SR501 PIR-Sensor schickt dir eine Nachricht, sobald sich im Bastelkeller etwas bewegt
  • Stromspar-Variante: Für Batterie-Projekte den Bot mit Deep Sleep kombinieren – aufwachen, messen, melden, schlafen

Perfekt für: Fernsteuerung, Alarmanlagen, Gewächshaus-Monitoring, Urlaubs-Überwachung

Troubleshooting

⚠️ Keine Startnachricht auf dem Handy: Hast du dem Bot ein /start geschickt? Vorher darf er dir nicht schreiben. Prüfe außerdem Token und Chat-ID auf Tippfehler – die häufigste Fehlerquelle überhaupt.

⚠️ Verbindung schlägt fehl / TLS-Fehler: Die Zeile client.setCACert(TELEGRAM_CERTIFICATE_ROOT) fehlt. Ohne Zertifikat verweigert Telegram die HTTPS-Verbindung. Als Notlösung zum Testen geht client.setInsecure() – für den Dauerbetrieb aber bitte das Zertifikat nutzen.

⚠️ Bot reagiert sehr träge: Das Abfrage-Intervall steht zu hoch oder ein blockierender Codeteil (delay, langsame Sensoren) bremst den loop(). 1000 ms Polling sind ein guter Kompromiss aus Reaktionszeit und Datenverbrauch.

⚠️ Befehle kommen doppelt an: Der Parameter in getUpdates(bot.last_message_received + 1) fehlt oder steht falsch – ohne das + 1 holt der Bot alte Nachrichten erneut ab.

⚠️ DHT22 liefert nan: Zwischen zwei Messungen müssen mindestens 2 Sekunden liegen, und die Datenleitung braucht bei längeren Kabeln einen Pull-up-Widerstand (10 kΩ zwischen DATA und VCC).

⚠️ Heap-Probleme bei langen Nachrichten: Sehr lange Antworttexte können den Speicher sprengen. Nachrichten unter 4096 Zeichen halten und Strings nicht unnötig verketten.

🚀 Dein Telegram-Bot-Starterpaket

Alles für dieses Projekt bekommst du im Shop:

Fazit

Mit einem Telegram-Bot wird dein ESP32 zur weltweiten Fernbedienung – ohne App-Entwicklung, ohne Portfreigabe, ohne laufende Kosten. Du hast einen Bot beim BotFather angelegt, den ESP32 Nachrichten senden und empfangen lassen, ein Relais per Chat-Befehl geschaltet, Sensorwerte auf Zuruf geliefert und einen Temperatur-Alarm mit Hysterese gebaut, der dich nur dann stört, wenn es wirklich nötig ist.

Die drei Merksätze zum Schluss: Token und Chat-ID sind deine Schlüssel – geheim halten und jede eingehende Nachricht gegen die erlaubte Chat-ID prüfen. Das TLS-Zertifikat mit setCACert() nicht vergessen. Und das Polling nicht-blockierend mit millis() aufbauen, damit Sensoren und Relais flüssig weiterlaufen. Damit steht deinem persönlichen IoT-Assistenten nichts mehr im Weg – viel Spaß beim Bauen!

Zurück zum Blog