IoT Otomasyon

MQTT ile Akıllı Aydınlatma Kontrolü: Dimmer'lar, LED Şeritler, Sahneler ve Zamanlamalar

LED şeritleri ve dimmer'ları bir ESP32 ile MQTT üzerinden kontrol edin, yumuşak geçişli JSON komutları kullanın, sahneleri retained message olarak saklayın ve zamanlamaları küçük bir Python servisiyle çalıştırın.

Bir MQTT akıllı aydınlatma projesinde ESP32 ile kontrol edilen, masa altındaki kısılabilir LED şerit
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

MQTT ile akıllı aydınlatma kontrolü, herhangi bir uygulamanın, panonun veya otomasyonun yalnızca bir mesaj yayınlayarak bir ışığı kısmasına, bir sahneyi çağırmasına ya da bir zamanlama çalıştırmasına olanak tanır. Bu eğitimde LED şeritler için yumuşak geçişli bir ESP32 PWM dimmer yapacak, tek bir oda için de bütün bir bina için de işe yarayan topic'ler tasarlayacak, sahneleri retained message olarak saklayacak ve zamanlamaları bir ConnectMQ broker'ına bağlı küçük bir Python servisiyle çalıştıracaksınız.

MQTT için Aydınlatma Donanımı Seçimi

Firmware yazmadan önce hangi tür aydınlatmayı kontrol edeceğinize karar verin. Her seçenek MQTT'ye biraz farklı bir şekilde uyum sağlar.

Donanım MQTT'ye nasıl bağlanır Uygun olduğu yerler Dikkat edilmesi gerekenler
ESP32 PWM sürücülü düşük voltajlı LED şeritler Bu eğitimdeki gibi özel firmware Masalar, raflar, dolaplar, vurgu aydınlatması Güç kaynağı boyutlandırması ve uzun hatlarda voltaj düşümü
Adreslenebilir LED'ler (WS2812B ve benzerleri) Özel firmware veya WLED Efektler ve piksel başına renk Akım çekişi, veri hattı uzunluğu
MQTT firmware'li şebeke dimmer'ları ve röleler Tasmota, Shelly veya benzeri cihazlar Mevcut tavan lambaları Yalnızca sertifikalı donanım, lambaya uygun doğru dimmer tipi
DALI veya KNX aydınlatma Veri yolundan MQTT'ye köprü Ofisler ve ticari binalar Kontrolcü veri yolu olarak kalır; MQTT görünürlük ekler

Evlerde PWM şeritler ve akıllı röleler ihtiyaçların çoğunu karşılar. Ticari binalarda aydınlatma genellikle zaten DALI veya KNX üzerindedir ve doğru yaklaşım, bu veri yolunu değiştirmek yerine MQTT'ye köprülemektir. Aşağıdaki topic yapısı dördü için de çalışır; onu erkenden standartlaştırmanın asıl nedeni de budur.

Işıklar için Topic Tasarımı

Bir ışığın MQTT üzerinde üç şeye ihtiyacı vardır: bir komut topic'i, bir durum topic'i ve bir erişilebilirlik topic'i. Bunları ayrı tutmak geri besleme döngülerini önler ve panoların gerçek durumu göstermesini sağlar.

<prefix>/<room>/<light>/set          commands in (JSON)
<prefix>/<room>/<light>/state        actual state out (retained)
<prefix>/<room>/<light>/availability "online" / "offline" (retained, last will)
<prefix>/scenes/<scene>              scene definitions (retained)
<prefix>/<room>/scene/set            recall a scene by name

Komutlar JSON kullanır; böylece daha eski client'ları bozmadan onları ileride genişletebilirsiniz:

{"state": "ON", "brightness": 180, "transition": 2.0}

brightness 0 ile 255 arasında değişir, transition ise saniye cinsinden geçiş süresidir. Bu biçim, Home Assistant MQTT entegrasyonunun ışıklar için anladığı JSON şemasıyla örtüşür; böylece aynı dimmer firmware değişikliği olmadan Home Assistant'ta görünebilir.

Donanım

  • Bir ESP32 geliştirme kartı.
  • 12 V veya 24 V tek renkli bir LED şerit ve uyumlu bir güç kaynağı.
  • Kanal başına bir lojik seviyeli N kanallı MOSFET (örneğin IRLZ44N veya modül üzerinde AO3400) ya da hazır bir MOSFET sürücü kartı.
  • Kanal başına 220 ohm'luk bir gate direnci ve 10 kOhm'luk bir pull-down direnci.

MOSFET'in gate ucunu dirençle GPIO 25'e, source ucunu toprağa (ESP32 toprağıyla ortak) ve drain ucunu LED şeridin negatif ucuna bağlayın. Şeridin pozitif ucu güç kaynağının pozitifine gider. Bir şeridi asla ESP32'nin 5 V pininden beslemeyin.

Şebeke dimmer'ları için şebeke voltajlı donanımı kendiniz yapmak yerine MQTT'yi zaten destekleyen Tasmota veya Shelly cihazı gibi sertifikalı bir ürün kullanın. Bu makaledeki topic tasarımı yine de geçerlidir; yükleme ve yapılandırma için Tasmota MQTT yazımıza bakın.

ESP32 Dimmer Firmware'i

Sketch, ESP32 Arduino core 3.x LEDC API'sini (ledcAttach ve ledcWrite), PubSubClient'ı ve ArduinoJson 7'yi kullanır. Kısmanın göze doğrusal görünmesi için bir gama eğrisi uygular, yumuşak geçiş yapar ve her değişiklikten sonra retained bir durum yayınlar.

#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <math.h>

const char* WIFI_SSID = "YOUR_WIFI";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* BROKER = "broker.connectmq.com";
const int   PORT = 1883;

#define PREFIX "connectmq/demo/light-8pz3/office-201/desk-strip"
const char* T_SET   = PREFIX "/set";
const char* T_STATE = PREFIX "/state";
const char* T_AVAIL = PREFIX "/availability";

const int LED_PIN = 25;
const int PWM_FREQ = 5000;   // Hz, görünür titremenin üzerinde
const int PWM_BITS = 12;     // 0..4095
const int PWM_MAX = (1 << PWM_BITS) - 1;

WiFiClient net;
PubSubClient mqtt(net);

bool on = false;
int brightness = 255;            // son parlaklık 1..255
float current = 0, target = 0;   // 0..255
float step = 0;
unsigned long lastStep = 0;

void writePwm(float level) {
  float norm = level / 255.0f;
  int duty = (int)(powf(norm, 2.2f) * PWM_MAX + 0.5f);   // gama düzeltmesi
  ledcWrite(LED_PIN, duty);
}

void publishState() {
  JsonDocument doc;
  doc["state"] = on ? "ON" : "OFF";
  doc["brightness"] = brightness;
  char buf[96];
  size_t n = serializeJson(doc, buf);
  mqtt.publish(T_STATE, (const uint8_t*)buf, n, true);
}

void startFade(float to, float seconds) {
  target = to;
  int steps = max(1, (int)(seconds * 50));     // saniyede 50 güncelleme
  step = (target - current) / steps;
  if (seconds <= 0) { current = target; writePwm(current); step = 0; }
}

void onMessage(char* topic, byte* payload, unsigned int len) {
  JsonDocument doc;
  if (deserializeJson(doc, payload, len)) return;

  float transition = doc["transition"] | 0.5f;
  if (doc["brightness"].is<int>()) {
    brightness = constrain(doc["brightness"].as<int>(), 1, 255);
    on = true;
  }
  if (doc["state"].is<const char*>()) {
    on = strcmp(doc["state"].as<const char*>(), "ON") == 0;
  }
  startFade(on ? brightness : 0, transition);
  publishState();
}

void connectMqtt() {
  while (!mqtt.connected()) {
    String id = "light-" + String((uint32_t)ESP.getEfuseMac(), HEX);
    if (mqtt.connect(id.c_str(), T_AVAIL, 1, true, "offline")) {
      mqtt.publish(T_AVAIL, "online", true);
      mqtt.subscribe(T_SET, 1);
      publishState();
    } else {
      delay(2000);
    }
  }
}

void setup() {
  ledcAttach(LED_PIN, PWM_FREQ, PWM_BITS);
  writePwm(0);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  mqtt.setServer(BROKER, PORT);
  mqtt.setCallback(onMessage);
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (step != 0 && millis() - lastStep >= 20) {
    lastStep = millis();
    current += step;
    if ((step > 0 && current >= target) || (step < 0 && current <= target)) {
      current = target;
      step = 0;
    }
    writePwm(current);
  }
}

Geçişin delay() olmadan loop() içinde çalıştığına dikkat edin; böylece cihaz kısma sırasında MQTT'ye yanıt vermeye devam eder. Son vasiyet (last will), ışık gücünü veya Wi-Fi bağlantısını kaybederse onu offline olarak işaretler.

Dimmer'ı Test Edin

# bu demo için her şeyi izle
mosquitto_sub -h broker.connectmq.com -p 1883 -i light-view-8pz3 -t "connectmq/demo/light-8pz3/#" -v

# 2 saniyelik geçişle yaklaşık yüzde 70'te aç
mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -q 1 \
  -t "connectmq/demo/light-8pz3/office-201/desk-strip/set" \
  -m '{"state":"ON","brightness":180,"transition":2}'

# yavaş geçişle kapat
mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -q 1 \
  -t "connectmq/demo/light-8pz3/office-201/desk-strip/set" \
  -m '{"state":"OFF","transition":5}'

Herkese açık MQTT test broker'ı herkese açıktır; dolayısıyla bir yabancı demo ışığınızı açıp kapatabilir. Bir masada bunun zararı yoktur, ancak gerçek aydınlatmanın kimlik bilgileri olan özel bir broker üzerinde çalışması gerekmesinin nedeni tam olarak budur.

Retained Message Olarak Sahneler

Bir sahne, adlandırılmış bir ışık durumları kümesidir. Her sahneyi broker üzerinde retained message olarak saklamak, her kontrolcünün, panonun veya duvar panelinin aynı tanımları görmesi anlamına gelir; bir sahneyi yeni bir sürüm yayınlayarak düzenleyebilirsiniz.

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -r \
  -t "connectmq/demo/light-8pz3/scenes/focus" \
  -m '{"office-201/desk-strip":{"state":"ON","brightness":230},"office-201/ceiling":{"state":"ON","brightness":200}}'

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 -r \
  -t "connectmq/demo/light-8pz3/scenes/presentation" \
  -m '{"office-201/desk-strip":{"state":"ON","brightness":40},"office-201/ceiling":{"state":"OFF"}}'

Python ile Sahne Çağırma ve Zamanlamalar

Küçük bir servis sahne tanımlarına ve çağırma isteklerine abone olur, sahne çağrılarını tek tek ışıklara dağıtır ve günlük bir zamanlama çalıştırır. Yalnızca paho-mqtt 2.x ve standart kütüphaneyi kullanır.

import json
import time
import uuid
from datetime import datetime

import paho.mqtt.client as mqtt

BROKER, PORT = "broker.connectmq.com", 1883
PREFIX = "connectmq/demo/light-8pz3"

scenes = {}
SCHEDULE = [            # (SS:DD, hafta günleri 0=Pzt..6=Paz, sahne)
    ("08:00", range(0, 5), "focus"),
    ("12:30", range(0, 5), "presentation"),
    ("19:00", range(0, 7), "off"),
]
scenes["off"] = {"office-201/desk-strip": {"state": "OFF", "transition": 10}}


def recall(client, name):
    scene = scenes.get(name)
    if not scene:
        print("Unknown scene", name)
        return
    for light, cmd in scene.items():
        cmd = {"transition": 1.5, **cmd}
        client.publish(f"{PREFIX}/{light}/set", json.dumps(cmd), qos=1)
    print("Recalled", name)


def on_connect(client, userdata, flags, reason_code, properties):
    client.subscribe(f"{PREFIX}/scenes/+", qos=1)
    client.subscribe(f"{PREFIX}/+/scene/set", qos=1)


def on_message(client, userdata, msg):
    parts = msg.topic.split("/")
    if parts[-2] == "scenes":
        if msg.payload:
            scenes[parts[-1]] = json.loads(msg.payload)
    elif parts[-2] == "scene" and parts[-1] == "set":
        recall(client, msg.payload.decode().strip())


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"light-sched-{uuid.uuid4().hex[:6]}")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, 60)
client.loop_start()

last_run = None
while True:
    now = datetime.now()
    key = now.strftime("%Y-%m-%d %H:%M")
    if key != last_run:
        for hhmm, days, scene in SCHEDULE:
            if now.strftime("%H:%M") == hhmm and now.weekday() in days:
                recall(client, scene)
        last_run = key
    time.sleep(5)

Bir sahneyi elle şu şekilde çağırın:

mosquitto_pub -h broker.connectmq.com -p 1883 -i light-cmd-8pz3 \
  -t "connectmq/demo/light-8pz3/office-201/scene/set" -m "focus"

Zamanlamalar ve güneşe bağlı tetikleyiciler için görsel bir düzenleyici tercih ediyorsanız aynı topic'ler Node-RED'den veya Home Assistant otomasyonlarından da çalışır.

Ayarlanabilir Beyaz ve RGB'ye Genişletme

Aynı firmware yapısı çok kanallı şeritlere de ölçeklenir. Ayarlanabilir beyaz (tunable white) bir şeridin sıcak ve soğuk olmak üzere iki kanalı vardır; RGB veya RGBW bir şeridin ise üç ya da dört kanalı. Her renk pini için bir LEDC kanalı bağlayın ve JSON komutunu isteğe bağlı alanlarla genişletin; örneğin ayarlanabilir beyaz için mired cinsinden "color_temp": 300, RGB için "color": {"r": 255, "g": 140, "b": 0}. brightness değerini ayrı bir alan olarak tutun ve her kanalı bu değere göre ölçekleyin; böylece parlaklık ve renk birbirinden bağımsız değişebilir ve bir sahne ikisini de tek bir mesajda ayarlayabilir.

İki pratik nokta ileride sorun yaşamanızı önler. Ayarlanabilir beyazı karıştırırken belirli bir parlaklık için iki kanalın toplamını sabit tutun; aksi halde ışık aralığın ortasında belirgin biçimde daha parlak olur. Ayrıca her komuttan sonra renk dahil ortaya çıkan tam durumu durum topic'inde yayınlayın, çünkü panolar ve Home Assistant renk seçicinin doğru konumunu çizmek için buna güvenir.

Üretim Kontrol Listesi

  1. TLS ile 8883 portunda özel bir broker'a geçin ve her dimmer'a kendi kimlik bilgilerini verin.
  2. Duvar anahtarlarının yerel olarak çalışmaya devam etmesini sağlayın; MQTT kontrol eklemeli, bir ışığı açmanın tek yolu olmamalıdır.
  3. Boş odaların otomatik olarak kapanması için aydınlatmayı ofis doluluk sensörleriyle birleştirin.
  4. KNX veya DALI bulunan binalarda anahtarlamayı mevcut veri yoluna bırakın ve KNX MQTT entegrasyonu yazımızdaki gibi onu MQTT'ye köprüleyin.
  5. Komutlar için QoS 1 kullanın ve her zaman mutlak değerler gönderin, asla "toggle" göndermeyin; böylece yinelenen bir teslimat zarar vermez.
Sık yapılan hata Belirti Çözüm
Gama düzeltmesi yok Görünür değişimin çoğu aralığın alt kısmında olur Sketch'teki gibi bir üs eğrisi uygulayın
delay() ile geçiş Işık geçişler sırasında komutları yok sayar Geçişi loop() içinde adım adım ilerletin
Durum retained değil Panolar yeniden bağlandıktan sonra bilinmiyor gösterir Durumu retain bayrağıyla yayınlayın
Komutlar durum topic'inde Işıklar salınır veya yankılanır set ve state topic'lerini ayırın
Düşük PWM frekansı Kamerada görünür titreme 1 kHz veya üzerini kullanın

Yönetilen bir MQTT broker, binada bir sunucu olmadan aydınlatma kontrolünü erişilebilir tutar; IoT otomasyon rehberi ise aydınlatmanın diğer bina sistemleriyle nasıl bütünleştiğini gösterir.

Aydınlatmanızı ConnectMQ Üzerinde Çalıştırın

app.connectmq.com adresinde kredi kartı gerektirmeden ücretsiz bir Serverless broker oluşturun. Dimmer'larınıza verilen kimlik bilgileriyle firmware yükleyin, ardından her odayı devreye alırken test komutları göndermek ve sahneleri çağırmak için ConnectMQ portalındaki tarayıcı içi MQTT client'ını kullanın.

Sık Sorulan Sorular

Neden düz ON ve OFF yerine JSON komutları kullanmalı?

JSON, tek bir mesajın durum, parlaklık ve geçiş süresini taşımasını sağlar; renk sıcaklığı gibi alanları da mevcut client'ları bozmadan sonradan ekleyebilirsiniz.

Işık durum topic'leri retained olmalı mı?

Evet. Retained bir durum, herhangi bir pano veya uygulamanın bir sonraki değişikliği beklemeden, abone olduğu anda doğru durumu göstermesini sağlar.

Şebeke ışıklarını bir ESP32 ile kontrol edebilir miyim?

Tasmota veya Shelly cihazı gibi MQTT destekleyen sertifikalı bir şebeke dimmer'ı veya röle modülü kullanın. Kendi şebeke voltajlı donanımınızı yapmak risklidir ve çoğu zaman mevzuata uygun değildir.

Zamanlayıcı çalışmıyorsa zamanlanmış sahnelere ne olur?

Işıklar mevcut durumlarını korur ve anahtarlarla ve doğrudan MQTT komutlarıyla kontrol edilebilir kalır. Kaçırılan olayların nadir olması için zamanlayıcıyı otomatik yeniden başlatmalı bir servis olarak çalıştırın.

İlgili yazılar

Zigbee2MQTT Kurulum Rehberi: Koordinatörden Panoya

Zigbee2MQTT'yi Docker ile kurun, koordinatörü ve MQTT bağlantısını yapılandırın, cihazları eşleştirip yeniden adlandırın, onları MQTT üzerinden kontrol edin ve durumlarını bir panoda görüntüleyin; önce ücretsiz herkese açık bir broker'da test edin.

7 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.