Passa al contenuto

Dimmer AC via MQTT con ESP32 e ESP8266

Controllare la luminosità di un carico AC via MQTT — sottoscrivere un topic, ricevere valori 0–100, impostare il dimmer. Funziona con Home Assistant, Node-RED, AWS IoT e qualsiasi broker MQTT.

In breve: Installa rbdimmerESP32 (per ESP32) o RBDdimmer (per ESP8266) più PubSubClient. Connettiti al tuo broker MQTT, sottoscrivi un topic di luminosità e chiama rbdimmer_set_level() nel callback. Ripubblica il livello attuale come topic di stato.



Come funziona

text
ESP32  ──WiFi──►  Broker MQTT  ◄──────  Home Assistant / Node-RED
  │                   │
  │  sottoscrizione: dimmer/level/set
  │  pubblicazione:  dimmer/level/state
  │
  └──ISR──►  Gate TRIAC  ──►  Carico (lampada, riscaldatore…)

L'ESP32 sottoscrive un topic di comando. Quando HA pubblica un valore (0–100), il callback lo applica al dimmer. L'ESP32 pubblica anche il suo livello attuale per mantenere HA sincronizzato.




Hardware

Componente Esempio
MCU ESP32 (dual-core) o ESP8266
Dimmer Qualsiasi modulo rbdimmer 1CH/2CH/4CH
Pin ZC GPIO 5 (qualsiasi GPIO su ESP32)
Pin DIM GPIO 4 (qualsiasi GPIO su ESP32)
VCC 3,3V

⚠️ Use rbdimmerESP32 on dual-core ESP32. The older RBDdimmer library has no IRAM_ATTR on its ISR — it crashes when WiFi is active. rbdimmerESP32 pins the ISR to Core 0; WiFi runs on Core 1. See: Wrong Library: RBDdimmer vs rbdimmerESP32




Librerie necessarie

Installa tramite Arduino Library Manager o PlatformIO:

Libreria Scopo Scheda
rbdimmerESP32 Controllo ISR del dimmer AC Solo ESP32
RBDdimmer Controllo ISR del dimmer AC Arduino, ESP8266
PubSubClient Client MQTT Qualsiasi
WiFi.h WiFi (integrata) ESP32
ESP8266WiFi.h WiFi (integrata) ESP8266

PlatformIO (platformio.ini):

ini
lib_deps =
  https://github.com/robotdyn-dimmer/rbdimmerESP32
  knolleary/PubSubClient @ ^2.8



Codice completo — ESP32

cpp
// AC Dimmer + MQTT on ESP32 (dual-core)
// Library: rbdimmerESP32 + PubSubClient
// IMPORTANT: use rbdimmerESP32, NOT RBDdimmer, on ESP32
#include <WiFi.h>
#include <PubSubClient.h>
#include "rbdimmerESP32.h"
// ── Configuration ─────────────────────────────────────────────
const char* WIFI_SSID     = "YourSSID";
const char* WIFI_PASS     = "YourPassword";
const char* MQTT_SERVER   = "192.168.1.100"; // broker IP
const int   MQTT_PORT     = 1883;
const char* DEVICE_ID     = "dimmer_esp32_01"; // unique per device
// MQTT topics
const char* TOPIC_SET     = "dimmer/level/set";   // receive command
const char* TOPIC_STATE   = "dimmer/level/state"; // publish state
// Dimmer pins
#define ZC_PIN   5
#define DIM_PIN  4
// ── Globals ───────────────────────────────────────────────────
WiFiClient   wifiClient;
PubSubClient mqtt(wifiClient);
rbdimmer_channel_t dimmerCh;
int currentLevel = 0;
// ── MQTT callback ─────────────────────────────────────────────
void onMessage(char* topic, byte* payload, unsigned int length) {
    char buf[8];
    int len = min((int)length, 7);
    memcpy(buf, payload, len);
    buf[len] = '\0';
    int level = atoi(buf);
    level = constrain(level, 0, 100);
    rbdimmer_set_level(dimmerCh, level);
    currentLevel = level;
    // Publish confirmed state
    char stateStr[8];
    itoa(level, stateStr, 10);
    mqtt.publish(TOPIC_STATE, stateStr, true); // retained
}
// ── MQTT reconnect ────────────────────────────────────────────
void mqttReconnect() {
    while (!mqtt.connected()) {
        Serial.print("Connecting to MQTT…");
        if (mqtt.connect(DEVICE_ID)) {
            Serial.println(" connected.");
            mqtt.subscribe(TOPIC_SET);
            // Republish retained state on reconnect
            char stateStr[8];
            itoa(currentLevel, stateStr, 10);
            mqtt.publish(TOPIC_STATE, stateStr, true);
        } else {
            Serial.print(" failed, rc=");
            Serial.println(mqtt.state());
            delay(5000);
        }
    }
}
// ── Setup ─────────────────────────────────────────────────────
void setup() {
    Serial.begin(115200);
    // Connect WiFi
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500); Serial.print(".");
    }
    Serial.println("\nWiFi connected: " + WiFi.localIP().toString());
    // Init dimmer
    rbdimmer_init();
    rbdimmer_register_zero_cross(ZC_PIN, RBDIMMER_PHASE_DEFAULT);
    rbdimmer_config_t cfg = {
        .gpio_pin      = DIM_PIN,
        .phase         = RBDIMMER_PHASE_DEFAULT,
        .initial_level = 0,
        .curve_type    = RBDIMMER_CURVE_RMS
    };
    rbdimmer_create_channel(&cfg, &dimmerCh);
    // Setup MQTT
    mqtt.setServer(MQTT_SERVER, MQTT_PORT);
    mqtt.setCallback(onMessage);
}
// ── Loop ──────────────────────────────────────────────────────
void loop() {
    if (!mqtt.connected()) mqttReconnect();
    mqtt.loop();
}



Codice completo — ESP8266

Per ESP8266, sostituisci la libreria e l'header WiFi. La logica MQTT è identica.

cpp
// Dimmer AC + MQTT su ESP8266 — sketch completo
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <RBDdimmer.h>
const char* WIFI_SSID   = "YourSSID";
const char* WIFI_PASS   = "YourPassword";
const char* MQTT_SERVER = "192.168.1.100";
const int   MQTT_PORT   = 1883;
const char* DEVICE_ID   = "dimmer_esp8266_01";
const char* TOPIC_SET   = "dimmer/level/set";
const char* TOPIC_STATE = "dimmer/level/state";
#define ZC_PIN  5   // D1 (NodeMCU)
#define DIM_PIN 4   // D2
WiFiClient   wifiClient;
PubSubClient mqtt(wifiClient);
dimmerLamp   dimmer(DIM_PIN, ZC_PIN);
int currentLevel = 0;
void onMessage(char* topic, byte* payload, unsigned int length) {
    char buf[8];
    int len = min((int)length, 7);
    memcpy(buf, payload, len);
    buf[len] = '\0';
    int level = constrain(atoi(buf), 0, 100);
    dimmer.setPower(level);
    currentLevel = level;
    char stateStr[8];
    itoa(level, stateStr, 10);
    mqtt.publish(TOPIC_STATE, stateStr, true);
}
void mqttReconnect() {
    while (!mqtt.connected()) {
        if (mqtt.connect(DEVICE_ID)) {
            mqtt.subscribe(TOPIC_SET);
        } else {
            delay(5000);
        }
    }
}
void setup() {
    WiFi.begin(WIFI_SSID, WIFI_PASS);
    while (WiFi.status() != WL_CONNECTED) delay(500);
    dimmer.begin(NORMAL_MODE, ON);
    dimmer.setPower(0);
    mqtt.setServer(MQTT_SERVER, MQTT_PORT);
    mqtt.setCallback(onMessage);
}
void loop() {
    if (!mqtt.connected()) mqttReconnect();
    mqtt.loop();
}



Struttura dei topic MQTT

Topic Direzione Valore Esempio
dimmer/level/set → ESP32 0100 75
dimmer/level/state ← ESP32 0100 75

Per più dimmer, usa prefissi di topic unici per dispositivo:

text
dimmer/kitchen/level/set
dimmer/bedroom/level/set



Configurazione Home Assistant

Aggiungi un light MQTT in configuration.yaml (o usa MQTT Discovery):

yaml
mqtt:
  light:
    - name: "Living Room Dimmer"
      unique_id: "dimmer_esp32_01"
      command_topic: "dimmer/level/set"
      state_topic: "dimmer/level/state"
      brightness_command_topic: "dimmer/level/set"
      brightness_state_topic: "dimmer/level/state"
      brightness_scale: 100
      on_command_type: "brightness"
      retain: true
      optimistic: false

on_command_type: "brightness" — quando accendi la luce da HA, viene inviato il valore di luminosità come payload MQTT (ad es. 75) anziché la stringa "ON". Il firmware riceve direttamente un numero e lo applica al dimmer.

Dopo l'aggiunta, riavvia HA. Il dimmer appare come entità luce dimmerabile con uno slider di luminosità 0–100 %.




MQTT multicanale

Per moduli 2CH o 4CH, crea coppie di topic e descrittori di canale aggiuntivi. Ogni canale ottiene la sua coppia sottoscrizione/pubblicazione:

cpp
// Canale aggiuntivo
rbdimmer_channel_t ch2;
const char* TOPIC_SET2   = "dimmer/ch2/level/set";
const char* TOPIC_STATE2 = "dimmer/ch2/level/state";
// In onMessage(): verificare il topic, indirizzare al canale corretto
if (strcmp(topic, TOPIC_SET) == 0) {
    rbdimmer_set_level(dimmerCh, level);
} else if (strcmp(topic, TOPIC_SET2) == 0) {
    rbdimmer_set_level(ch2, level);
}



Articoli correlati



Hai ancora domande?

Ask on forum.rbdimmer.com or open a GitHub Issue.

Condividi articolo
Accedi per lasciare un commento