Bir MQTT Telegram botu, telefonunuzu cihazlarınız için bir cep konsoluna dönüştürür: alarmlar sohbet mesajı olarak gelir ve hızlı bir /off pump1 komutu cihaza geri bir komut yayınlar. Bu eğitimde bu botu Python'da paho-mqtt ve Telegram Bot HTTP API ile geliştirecek, bir sohbet izin listesiyle koruyacak ve gerçek bir broker'a karşı çalıştıracaksınız. Her şey iki bağımlılığı olan tek bir betikten ibaret.
Bot MQTT Sisteminize Nasıl Yerleşir?
Bot sıradan bir MQTT client'ıdır. Cihazlar tam olarak eskisi gibi yayın yapmaya ve abone olmaya devam eder; bot ise broker ile Telegram arasında durur:
device --publish alert--> MQTT broker --> telegram_bot.py --sendMessage--> your chat
your chat --/off pump1--> telegram_bot.py --publish cmd--> MQTT broker --> device
Cihaz tarafındaki hiçbir şey Telegram'ın varlığından haberdar değildir. Bu ayrım önemlidir: daha sonra firmware'e dokunmadan Telegram'ı e-posta veya Slack ile değiştirebilirsiniz ve bir mikrodenetleyiciye asla bot token'ı koymazsınız. Bu tabloda bir MQTT broker'ın ne yaptığını hatırlamak isterseniz: broker yalnızca mesajları topic'ler ve client'lar arasında yönlendirir.
Uyarılar ve Komutlar İçin Topic Tasarımı
Botun cihaz adlarını topic'lerden ayrıştırabilmesi için öngörülebilir bir yapı kullanın:
| Topic | Yön | Payload örneği |
|---|---|---|
connectmq/demo/tgbot-9214/<device>/telemetry |
cihazdan bota | {"temp": 41.2} |
connectmq/demo/tgbot-9214/<device>/alert |
cihazdan bota | {"level": "high", "text": "Temperature above 80 C"} |
connectmq/demo/tgbot-9214/<device>/cmd |
bottan cihaza | {"action": "off", "by": "telegram"} |
connectmq/demo/tgbot-9214 öneki, broker.connectmq.com adresindeki ücretsiz public MQTT broker üzerinde test için kullanılan rastgele bir ad alanıdır. Public alan aynı topic'e abone olan herkes tarafından okunabilir; bu yüzden kendi rastgele sonekinizi seçin ve private bir broker'a geçene kadar botu yalnızca test cihazlarıyla kullanın.
Adım 1: Botu Oluşturun ve Chat ID'nizi Bulun
- Telegram'da @BotFather ile bir sohbet açın,
/newbotgönderin ve yönergeleri izleyin.123456789:AA...gibi bir token alırsınız. Ona bir parola gibi davranın. - Yeni botunuzla bir sohbet açın ve ona herhangi bir mesaj gönderin, örneğin
hi. - Chat ID'nizi bulmak için bir tarayıcıda veya terminalde
getUpdatesçağrısı yapın:
curl -s "https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates"
Yanıtta "chat":{"id":123456789,...} ifadesini arayın. Bu sayı izin listesine girer. Bir grup için botu gruba ekleyin ve grubun negatif chat ID'sini kullanın. Telegram Bot API dokümantasyonu aşağıda kullanılan tüm metotları açıklar.
Adım 2: Bağımlılıkları Kurun
pip install "paho-mqtt>=2.0" requests
Betik bir bot framework'ü yerine düz HTTPS çağrıları kullanır. Bu, iş parçacığı yönetimini basit tutar: paho ağ döngüsünü arka plandaki bir iş parçacığında çalıştırır, ana iş parçacığı ise komutlar için Telegram'ı long polling ile dinler.
Adım 3: MQTT Telegram Botu
telegram_bot.py olarak kaydedin:
import json
import os
import threading
import time
import uuid
import paho.mqtt.client as mqtt
import requests
BOT_TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
ALLOWED_CHATS = {int(c) for c in os.environ["TELEGRAM_CHAT_IDS"].split(",")}
API = f"https://api.telegram.org/bot{BOT_TOKEN}"
BROKER = os.environ.get("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.environ.get("MQTT_PORT", "1883"))
USERNAME = os.environ.get("MQTT_USERNAME")
PASSWORD = os.environ.get("MQTT_PASSWORD")
CLIENT_ID = os.environ.get("MQTT_CLIENT_ID", f"tgbot-{uuid.uuid4().hex[:8]}")
PREFIX = os.environ.get("TOPIC_PREFIX", "connectmq/demo/tgbot-9214")
ALERT_COOLDOWN = int(os.environ.get("ALERT_COOLDOWN", "300")) # cihaz başına saniye
latest = {} # cihaz -> (zaman damgası, payload sözlüğü)
last_alert = {} # cihaz -> son iletilen uyarının zaman damgası
state_lock = threading.Lock()
def send(chat_id: int, text: str):
try:
r = requests.post(f"{API}/sendMessage", json={"chat_id": chat_id, "text": text}, timeout=10)
if r.status_code == 429:
retry = r.json().get("parameters", {}).get("retry_after", 5)
time.sleep(retry)
requests.post(f"{API}/sendMessage", json={"chat_id": chat_id, "text": text}, timeout=10)
except requests.RequestException as exc:
print(f"Telegram send failed: {exc}")
def broadcast(text: str):
for chat_id in ALLOWED_CHATS:
send(chat_id, text)
# ---------- MQTT tarafı ----------
def on_connect(client, userdata, flags, reason_code, properties):
if reason_code.is_failure:
print(f"MQTT connect failed: {reason_code}")
return
client.subscribe(f"{PREFIX}/+/telemetry", qos=0)
client.subscribe(f"{PREFIX}/+/alert", qos=1)
print("MQTT connected and subscribed")
def on_message(client, userdata, msg):
parts = msg.topic.split("/")
device, kind = parts[-2], parts[-1]
try:
payload = json.loads(msg.payload)
except (json.JSONDecodeError, UnicodeDecodeError):
payload = {"raw": msg.payload.decode("utf-8", errors="replace")}
now = time.time()
if kind == "telemetry":
with state_lock:
latest[device] = (now, payload)
elif kind == "alert" and not msg.retain:
with state_lock:
if now - last_alert.get(device, 0) < ALERT_COOLDOWN:
return
last_alert[device] = now
level = str(payload.get("level", "alert")).upper()
text = payload.get("text", json.dumps(payload))
# yavaş bir HTTP çağrısı MQTT döngüsünü asla engellemesin diye ayrı bir iş parçacığından gönder
threading.Thread(target=broadcast, args=(f"[{level}] {device}: {text}",), daemon=True).start()
# ---------- Telegram tarafı ----------
def handle_command(client: mqtt.Client, chat_id: int, text: str):
parts = text.strip().split()
cmd = parts[0].split("@")[0].lower()
arg = parts[1] if len(parts) > 1 else None
if cmd in ("/start", "/help"):
send(chat_id, "Commands:\n/status - latest values\n/on <device>\n/off <device>")
elif cmd == "/status":
with state_lock:
snapshot = dict(latest)
if not snapshot:
send(chat_id, "No telemetry received yet.")
return
lines = []
for device, (ts, data) in sorted(snapshot.items()):
age = int(time.time() - ts)
lines.append(f"{device}: {json.dumps(data)} ({age}s ago)")
send(chat_id, "\n".join(lines))
elif cmd in ("/on", "/off"):
if not arg or "/" in arg or "+" in arg or "#" in arg:
send(chat_id, f"Usage: {cmd} <device>")
return
body = json.dumps({"action": cmd[1:], "by": f"telegram:{chat_id}"})
info = client.publish(f"{PREFIX}/{arg}/cmd", body, qos=1)
info.wait_for_publish(timeout=5)
send(chat_id, f"Sent '{cmd[1:]}' to {arg}" if info.is_published() else "Publish failed, broker not reachable")
else:
send(chat_id, "Unknown command. Try /help")
def poll_telegram(client: mqtt.Client):
offset = None
while True:
try:
r = requests.get(f"{API}/getUpdates", params={"timeout": 30, "offset": offset}, timeout=40)
for update in r.json().get("result", []):
offset = update["update_id"] + 1
message = update.get("message") or {}
chat_id = message.get("chat", {}).get("id")
text = message.get("text", "")
if chat_id not in ALLOWED_CHATS:
print(f"Ignoring chat {chat_id}")
continue
if text.startswith("/"):
handle_command(client, chat_id, text)
except requests.RequestException as exc:
print(f"Telegram polling error: {exc}")
time.sleep(5)
def main():
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
if USERNAME:
client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
client.tls_set()
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
broadcast("Bot started")
poll_telegram(client)
if __name__ == "__main__":
main()
Adım 4: Çalıştırın
export TELEGRAM_BOT_TOKEN=YOUR_BOT_TOKEN
export TELEGRAM_CHAT_IDS=123456789
python telegram_bot.py
Başka bir terminalde bir cihazı simüle edin. Önce biraz telemetri, ardından bir uyarı gönderin, sonra komutları dinleyin:
mosquitto_pub -h broker.connectmq.com -p 1883 -i tg-dev-9214 \
-t connectmq/demo/tgbot-9214/pump1/telemetry -m '{"temp": 41.2, "running": true}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i tg-dev-9214 \
-t connectmq/demo/tgbot-9214/pump1/alert -m '{"level": "high", "text": "Temperature above 80 C"}'
mosquitto_sub -h broker.connectmq.com -p 1883 -i tg-listen-9214 -v \
-t "connectmq/demo/tgbot-9214/+/cmd"
Telefonunuzda [HIGH] pump1: Temperature above 80 C görünür. Önbelleğe alınmış telemetriyi görmek için /status, komutun mosquitto_sub penceresinde belirdiğini izlemek için /off pump1 gönderin. Gerçek donanımda cihaz kendi cmd topic'ine abone olur; cihaz tarafını ESP32 MQTT eğitimi gösterir.
Atlamamanız Gereken Güvenlik Kuralları
Ekipmanı açıp kapatabilen bir sohbet botu bir uzaktan kumandadır. Ona göre davranın:
- Chat ID'leri izin listesine alın. Betik listede olmayan her sohbeti yok sayar. Herkes botunuzu adıyla bulabilir, bu nedenle bu kontrol zorunludur.
- Cihaz argümanını doğrulayın. Kod
/,+ve#karakterlerini reddeder; böylece kimse amaçlanan topic dışında yayın yapamaz veya wildcard enjekte edemez. - Token'ı kaynak kontrolünün dışında tutun. Ortam değişkenleri veya bir gizli bilgi yöneticisi kullanın; token sızarsa BotFather ile iptal edin.
- Gerçek ekipmanı asla public broker üzerinden kontrol etmeyin. Herkes public topic'lere yayın yapabilir. Kimlik bilgileri ve TLS ile private bir broker kullanın.
- Tehlikeli işlemler için onay ekleyin. Makineleri hareket ettiren her şey için yayın yapmadan önce
/confirmgibi ikinci bir mesaj isteyin.
MQTT güvenliği için en iyi uygulamalar yazısındaki kapsamlı kontrol listesi, cihazlar için olduğu kadar bot için de geçerlidir.
Uyarı Fırtınalarını Yönetmek
Kararsız bir sensör dakikada yüzlerce uyarı gönderebilir ve Telegram çok hızlı mesaj gönderen botları hız sınırına tabi tutar. Betik cihaz başına bir bekleme süresi (varsayılan olarak beş dakika) uygular ve Telegram'ın HTTP 429 ile döndürdüğü retry_after değerine uyar. Ayrıca retained uyarıları atlar; böylece bir yeniden bağlantı dünün alarmını tekrar göndermez. Kalıcı durumlar için cihazın ayrı bir "giderildi" uyarısı yayınlamasını sağlayın; böylece sohbet geçmişi olayın tamamını anlatır.
Sorun Giderme
- Telegram'a hiç mesaj gelmiyor.
TELEGRAM_CHAT_IDSdeğerinin sayısal chat ID'nizi içerdiğinden ve bota önce en az bir mesaj gönderdiğinizden emin olun; botlar sohbet başlatamaz. - getUpdates'ten
409 Conflict. Bot için bir webhook ayarlanmış veya betiğin ikinci bir kopyası çalışıyor. Webhook'udeleteWebhookmetoduyla silin ve yalnızca bir örnek çalıştırın. - Komutlar çalışıyor, uyarılar çalışmıyor. Uyarı topic'i
<prefix>/<device>/alertile eşleşmiyor veya o cihaz için bekleme süresi hâlâ etkin. - Bot MQTT'ye tekrar tekrar bağlanıyor. İki örnek aynı client ID'yi paylaşıyor. ID'leri süreç başına benzersiz tutun.
Botu Bir Servis Olarak Çalıştırmak
Yalnızca dizüstü bilgisayarınız açıkken çalışan bir bot pek de bir uyarı sistemi sayılmaz. Bir Raspberry Pi veya küçük bir Linux VM üzerinde, açılışta başlaması ve çöktükten sonra yeniden başlaması için onu systemd altında çalıştırın. Gizli bilgileri yalnızca servis kullanıcısının okuyabileceği bir ortam dosyasına koyun:
sudo tee /etc/telegram-mqtt-bot.env >/dev/null <<'EOF'
TELEGRAM_BOT_TOKEN=YOUR_BOT_TOKEN
TELEGRAM_CHAT_IDS=123456789
MQTT_HOST=broker.connectmq.com
MQTT_PORT=1883
EOF
sudo chmod 600 /etc/telegram-mqtt-bot.env
sudo tee /etc/systemd/system/telegram-mqtt-bot.service >/dev/null <<'EOF'
[Unit]
Description=MQTT Telegram bot
After=network-online.target
Wants=network-online.target
[Service]
EnvironmentFile=/etc/telegram-mqtt-bot.env
ExecStart=/usr/bin/python3 /opt/telegram-bot/telegram_bot.py
Restart=always
RestartSec=5
User=pi
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now telegram-mqtt-bot
journalctl -u telegram-mqtt-bot -f
Betiğin açılışta yayınladığı "Bot started" mesajı aynı zamanda bir yeniden başlatma bildirimi işlevi görür: beklenmedik şekilde görürseniz servis çökmüş veya makine yeniden başlamış demektir; nedenini journalctl söyler. Botun sohbet uyarıları için tek hata noktası olduğunu unutmayın. Çökerse size kimse haber vermez; bu yüzden onu basit bir heartbeat ile eşleştirin: bottan offline değerinde bir Last Will ile retained bir durum yayınlayın ve bu topic'i başka bir sistemin izlemesini sağlayın.
Private Bir ConnectMQ Broker'a Geçiş
Bot gerçek cihazları kontrol ettiğinde onu private bir broker'a taşıyın. ConnectMQ üzerinde bir broker oluşturun, üretilen kullanıcı adını, parolayı ve client ID'yi portaldan kopyalayın ve MQTT_HOST, MQTT_PORT=8883, MQTT_USERNAME, MQTT_PASSWORD ve MQTT_CLIENT_ID değerlerini ayarlayın. Barındırılan bir MQTT broker ile işletmeniz gereken tek süreç botun kendisidir.
ConnectMQ ayrıca portalda eşik tabanlı uyarı kuralları ve bir uyarı günlüğü sunar; bunlar broker'ınızdaki alarmları bir bakışta görmek için kullanışlıdır. Bot ise seçili uyarıları insanların zaten bulunduğu yere ileterek bunu tamamlar. Ekibiniz sohbet yerine gelen kutusunu tercih ediyorsa aynı yapı Python ile MQTT e-posta uyarıları yazısında SMTP ile de çalışır. Diğer diller ve framework'ler için MQTT client kütüphaneleri rehberi seçenekleri karşılaştırır.
ConnectMQ ile Başlayın
Telegram botunuzu bugün TLS ile korunan private bir broker'a karşı çalıştırın. app.connectmq.com adresinden kaydolun, ücretsiz Serverless planını seçin (kredi kartı gerekmez), bir broker oluşturun ve kimlik bilgilerini botun ortamına yapıştırın. Portaldaki tarayıcı içi MQTT client'ı, bekleme süresini ayarlarken test uyarıları göndermenin pratik bir yoludur.
Sık Sorulan Sorular
Bir MQTT Telegram botu çalıştırmak için sunucuya ihtiyacım var mı?
Betiğin sürekli çalışabileceği bir yere ihtiyacınız var; örneğin bir Raspberry Pi, küçük bir VM veya bir container. Yalnızca dışa doğru bağlantılar kurduğu için açık port veya public IP gerekmez.
Birden fazla kişi aynı bot üzerinden cihazları kontrol edebilir mi?
Evet. Her kişinin chat ID'sini TELEGRAM_CHAT_IDS değerine ekleyin veya botu bir gruba ekleyip grup ID'sini izin listesine alın. Betiğin yaptığı gibi gönderen bilgisini komut payload'ına ekleyin; böylece cihazlar komutu kimin verdiğini kaydedebilir.
Neden Telegram webhook'u yerine long polling kullanılıyor?
Webhook'lar public bir HTTPS uç noktası gerektirir. Long polling NAT ve güvenlik duvarlarının arkasından çalışır; bu da cihazlarınızın yanındaki bir gateway veya Raspberry Pi üzerinde çalışan bir bot için idealdir.
Bot çevrimdışıyken uyarılar teslim edilir mi?
QoS 1 ile kalıcı bir oturum kullanmadığınız sürece bot bağlı değilken yayınlanan uyarılar kaçırılır. Kritik alarmlar için sohbete ek olarak ikinci bir bildirim yolu bulundurun.



