İyi bir akıllı ev MQTT topic düzeni sıkıcı ve öngörülebilirdir: oda başına bir dal, cihaz başına bir dal ve state, komutlar ve erişilebilirlik için sabit bir uç topic seti. Bu makale kopyalayabileceğiniz somut bir düzen öneriyor; komutların ve state'in neden ayrı topic'lerde durduğunu, hangi mesajların retained olması gerektiğini ve düzenin Home Assistant discovery ile broker ACL'lerine nasıl karşılık geldiğini açıklıyor.
home/<room>/<device>/state current state, JSON, retained
home/<room>/<device>/set commands to the device, NOT retained
home/<room>/<device>/availability "online" / "offline", retained, Last Will
home/<room>/<device>/event one-off events (button press), NOT retainedİsimlendirme kuralları
Topic isimleri evinizin API'sinin bir parçasıdır. Sonradan değiştirmek her otomasyona dokunmak anlamına gelir; bu yüzden kuralları bir kez belirleyin:
- Küçük harf ASCII, kelimeler
-ile birleşik:living-room,ceiling-light. Boşluk, Türkçe karakter veya emoji yok. - Başta eğik çizgi yok.
/home/kitchenboş bir ilk seviye oluşturur vehome/#ile eşleşmez. - Asla
$ile başlamayın: bu prefix$SYSgibi broker topic'lerine ayrılmıştır. - Yerler ve nesneler için isimler, uçlar için sabit kelimeler:
state,set,availability,event. Cihazlar arasındastatus,cmdvecommandkarıştırmayın. - Derinliği sabit tutun. Her cihaz tam olarak
home/<room>/<device>konumundadır; böylecehome/+/+/stateher zaman "tüm cihazların state'i" anlamına gelir.
Daha genel öneriler için MQTT topic tasarımı en iyi uygulamaları yazısına bakın.
Odaya göre mi, ID'ye göre mi?
| Stil | Örnek | Uygun olduğu durum | Dezavantajı |
|---|---|---|---|
| Odaya göre | home/kitchen/ceiling-light/state | Tipik evler, elle yazılan otomasyonlar | Cihazı taşımak topic'lerini değiştirir |
| ID'ye göre | home/device/shelly-a8032a/state | Büyük veya sık değişen kurulumlar | Oda bilgisi başka yerde tutulmalı (metadata, HA alanları) |
| Karma | home/kitchen/shelly-a8032a/state | Okunabilir gruplamayla benzersiz isimler | Taşındığında yine değişir |
Çoğu evde okunabilirlik açısından odaya göre düzen kazanır. Yer değiştiren cihazlarınız varsa (taşınabilir bir ısıtıcı, bir arabadaki sensör), onlara sabit bir ID verin ve home/mobile/ gibi nötr bir dalın altına koyun.
Komutlar ve state
En önemli kural: cihaz state'i yayınlar, diğer herkes komut yayınlar ve ikisi asla aynı topic'i paylaşmaz.
app ──PUBLISH home/kitchen/ceiling-light/set {"state":"ON"} (not retained)
light ──applies the command, then
light ──PUBLISH home/kitchen/ceiling-light/state {"state":"ON","brightness":255} (retained)
app, HA ◀─ receive the new state and update the UINeden ayırmalı?
- State topic'i her zaman gerçeği yansıtır. Komut başarısız olursa (röle takılır, cihaz çevrimdışıdır) state topic'i yine doğruyu gösterir ve arayüz yalan söylemez.
- Yankı döngüsü olmaz. Kendi state topic'ine abone olan bir cihaz kendi güncellemelerini alır.
setvestateayrı olduğunda her taraf yalnızca ihtiyaç duyduğu topic'e abone olur. - Güvenli ACL'ler. Bir dashboard kullanıcısına
.../setyazma ve.../stateokuma izni verilebilir; ama cihazın state'ini taklit edemez.
Cihaz, hiçbir şey değişmemiş olsa bile yeni state'i komutu uyguladıktan sonra yayınlamalıdır. Arayüzlerin ve otomasyonların beklediği onay budur. Korelasyon ID'leri ile istek/yanıt desenleri için MQTT üzerinden komut ve kontrol yazısına bakın.
Neler retained olmalı
| Topic | Retained? | Neden |
|---|---|---|
.../state | Evet | Sonradan açılan bir dashboard güncel state'i anında gösterir |
.../availability | Evet | Yeni aboneler hangi cihazların çevrimdışı olduğunu bilir |
.../set | Hayır | Retained bir komut her yeniden bağlantıda tekrar oynatılır: elektrik kesintisinden sonra hayalet açılmalar |
.../event | Hayır | "Düğmeye basıldı" yalnızca olduğu anda anlamlıdır |
homeassistant/.../config | Evet | Discovery yapılandırmaları Home Assistant yeniden başlatmalarından sonra da kalmalıdır |
Bir komut yanlışlıkla retained olarak gönderildiyse, aynı topic'e boş bir retained mesaj yayınlayarak temizleyin. Ayrıntılar için retained mesajlar.
Last Will ile erişilebilirlik
Her cihaz bağlanırken availability topic'ine bir Last Will ayarlar: payload offline, retained, QoS 1. Bağlandıktan hemen sonra online mesajını retained olarak yayınlar. Cihaz gücünü veya Wi-Fi'ını kaybederse broker, keep alive süresi dolduğunda (yaklaşık 1,5 × keep alive aralığı) offline yayınlar. Bkz. MQTT Last Will.
40 satırda bir cihaz
Bu Python script'i (paho-mqtt 2.x), düzeni izleyen kısılabilir bir lamba gibi davranır. Örnekler, paylaşılan bir test endpoint'inde güvenle çalışabilmeleri için testmqtt/ prefix'ini kullanıyor; kendi evinizde bunu kaldırırsınız.
import json, os
import paho.mqtt.client as mqtt
BASE = "testmqtt/home/kitchen/ceiling-light"
state = {"state": "OFF", "brightness": 0}
def publish_state(client):
client.publish(f"{BASE}/state", json.dumps(state), qos=1, retain=True)
def on_connect(client, userdata, flags, reason_code, properties):
client.publish(f"{BASE}/availability", "online", qos=1, retain=True)
client.subscribe(f"{BASE}/set", qos=1)
publish_state(client)
def on_message(client, userdata, msg):
try:
cmd = json.loads(msg.payload)
except ValueError:
cmd = {"state": msg.payload.decode(errors="replace").strip().upper()}
if not isinstance(cmd, dict):
cmd = {}
if cmd.get("state") in ("ON", "OFF"):
state["state"] = cmd["state"]
if isinstance(cmd.get("brightness"), int):
state["brightness"] = max(0, min(255, cmd["brightness"]))
publish_state(client) # always confirm with the real state
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="kitchen-ceiling-light")
if os.getenv("MQTT_USER"):
client.username_pw_set(os.environ["MQTT_USER"], os.getenv("MQTT_PASS"))
client.will_set(f"{BASE}/availability", "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=30)
client.loop_forever()State'i on_connect içinde yayınlamak önemlidir: her yeniden bağlantıdan sonra retained state yenilenir ve broker oturum tutmamış olsa bile abonelikler yeniden oluşturulur.
Düzeni test edin
Bir terminalde tüm cihazların state ve erişilebilirlik bilgisini izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -v \
-t 'testmqtt/home/+/+/state' -t 'testmqtt/home/+/+/availability'Diğerinden komut gönderin:
mosquitto_pub -h broker.connectmq.com -p 1883 -q 1 \
-t 'testmqtt/home/kitchen/ceiling-light/set' -m '{"state":"ON","brightness":180}'
mosquitto_pub -h broker.connectmq.com -p 1883 -q 1 \
-t 'testmqtt/home/kitchen/ceiling-light/set' -m 'off'Ardından düzenin vaat ettiği davranışları kontrol edin:
- Her komut tam olarak bir state mesajı üretir.
- Terminal 1'i yeniden başlatın: güncel state ve
onlineanında görünür (retained). - Script'i
kill -9ile sonlandırın: keep alive zaman aşımından sonraofflinegörünür. - Script'i yeniden başlatın: hiçbir komut tekrar oynatılmaz, çünkü
sethiçbir zaman retained değildi.
Aynısını tarayıcıda online MQTT istemcisi ile yapabilir, herhangi bir abonelik desenini topic'lerinize karşı topic matcher ile kontrol edebilirsiniz.
İşe yarar abonelikler
| İhtiyaç | Abonelik |
|---|---|
| Evdeki her şey | home/# |
| Mutfaktaki her şey | home/kitchen/# |
| Tüm cihazların state'i | home/+/+/state |
| Hangi cihazlar çevrimdışı | home/+/+/availability |
| Tüm düğme basışları | home/+/+/event |
Derinlik sabit olduğu için tek seviyeli + wildcard'ları yeterlidir; hata ayıklama dışında #'e nadiren ihtiyaç duyarsınız. Bkz. MQTT wildcard'larına derinlemesine bakış.
Home Assistant discovery
Home Assistant, homeassistant/<component>/<object_id>/config altındaki retained yapılandırma mesajlarından otomatik olarak entity oluşturabilir. Düzen doğrudan discovery alanlarına karşılık gelir:
{
"name": "Kitchen ceiling light",
"unique_id": "kitchen_ceiling_light",
"state_topic": "home/kitchen/ceiling-light/state",
"value_template": "{{ value_json.state }}",
"command_topic": "home/kitchen/ceiling-light/set",
"payload_on": "ON",
"payload_off": "OFF",
"availability_topic": "home/kitchen/ceiling-light/availability"
}payload_available ve payload_not_available varsayılan olarak online ve offline değerlerini alır; yukarıdaki Last Will'in yayınladığı da tam olarak budur. Entegrasyonun tam kurulumu için Home Assistant ve MQTT yazısına bakın.
Düzeni izleyen ACL'ler
Tutarlı bir ağaç, izinleri kısa tutar:
| İstemci | Yazma | Okuma |
|---|---|---|
| Her cihaz | kendi state, availability, event topic'leri | kendi set topic'i |
| Home Assistant / otomasyon merkezi | home/+/+/set, homeassistant/# | home/# |
| Duvar tableti dashboard'u | home/+/+/set | home/+/+/state, home/+/+/availability |
| Misafir veya izleme kullanıcısı | hiçbir şey | home/+/+/availability |
Cihaz başına bir kimlik bilgisi, ele geçirilmiş bir akıllı prizin yalnızca kendisi hakkında yalan söyleyebileceği, ama ön kapı kilidinizi açamayacağı anlamına gelir.
Bu düzeni benimsemenin bir maliyeti yoktur ve her yeni cihazda karşılığını verir: sabit derinlik, ayrı state ve set, retained state ve erişilebilirlik, asla retained olmayan komutlar. Kuralları yazıya dökün, her yeni cihazı yukarıdaki dört kontrolle test edin; eviniz büyüdükçe otomasyonlarınız çalışmaya devam eder.
Sıkça sorulan sorular
MQTT komut topic'leri retained olmalı mı?
Hayır. Retained bir komut, cihaz her yeniden bağlandığında ona tekrar iletilir; böylece bir lamba elektrik kesintisinden sonra kendiliğinden yanabilir. State ve erişilebilirliği retained tutun, komutları retain bayrağı olmadan gönderin.
Oda topic'in bir parçası olmalı mı?
Tipik bir evde evet: home/kitchen/ceiling-light kolay okunur ve home/kitchen/# ile tüm odaya abone olmanızı sağlar. Dezavantajı, bir cihazı taşımanın topic'lerini değiştirmesidir. Büyük kurulumlar genellikle sabit cihaz ID'leri kullanır ve odayı metadata olarak tutar.
Tek bir JSON state topic'i mi, yoksa her özellik için ayrı topic mi?
Cihaz başına tek bir JSON state mesajını tutarlı tutmak daha kolaydır ve Home Assistant'ın JSON şablonlarının beklediği de budur. Özellik başına topic'ler çok küçük sensörler ve bazı araçlar için daha basittir. Bir stil seçin ve tüm cihazlarda onu kullanın.


