Se rendre au contenu

Variateur AC via MQTT avec ESP32 et ESP8266

Contrôler la luminosité d'une charge AC par MQTT — s'abonner à un topic, recevoir des valeurs 0–100, régler le variateur. Fonctionne avec Home Assistant, Node-RED, AWS IoT et tout broker MQTT.

En bref : Installez rbdimmerESP32 (pour ESP32) ou RBDdimmer (pour ESP8266) plus PubSubClient. Connectez-vous à votre broker MQTT, abonnez-vous à un topic de luminosité et appelez rbdimmer_set_level() dans le callback. Republiez le niveau actuel comme topic d'état.



Fonctionnement

text
ESP32  ──WiFi──►  Broker MQTT  ◄──────  Home Assistant / Node-RED
  │                   │
  │  abonnement : dimmer/level/set
  │  publication : dimmer/level/state
  │
  └──ISR──►  Gâchette TRIAC  ──►  Charge (lampe, chauffage…)

L'ESP32 s'abonne à un topic de commande. Lorsque HA publie une valeur (0–100), le callback l'applique au variateur. L'ESP32 publie aussi son niveau actuel pour que HA reste synchronisé.




Matériel

Composant Exemple
MCU ESP32 (double cœur) ou ESP8266
Variateur Tout module rbdimmer 1CH/2CH/4CH
Pin ZC GPIO 5 (tout GPIO sur ESP32)
Pin DIM GPIO 4 (tout GPIO sur 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




Bibliothèques requises

Installation via Arduino Library Manager ou PlatformIO :

Bibliothèque Rôle Carte
rbdimmerESP32 Contrôle ISR du variateur AC ESP32 uniquement
RBDdimmer Contrôle ISR du variateur AC Arduino, ESP8266
PubSubClient Client MQTT Toutes
WiFi.h WiFi (intégrée) RBDdimmer (ancienne)
ESP8266WiFi.h WiFi (intégrée) ESP8266

PlatformIO (platformio.ini) :

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



Code complet — 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();
}



Code complet — ESP8266

Pour l'ESP8266, remplacez la bibliothèque et l'en-tête WiFi. La logique MQTT est identique.

cpp
// Variateur AC + MQTT sur ESP8266 — sketch complet
#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();
}



Structure des topics MQTT

Topic Direction Valeur Exemple
dimmer/level/set → ESP32 0100 75
dimmer/level/state ← ESP32 0100 75

Pour plusieurs variateurs, utilisez des préfixes de topics uniques par appareil :

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



Configuration Home Assistant

Ajoutez un light MQTT dans configuration.yaml (ou utilisez 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" — lorsque vous allumez la lumière depuis HA, la valeur de luminosité est envoyée comme payload MQTT (par ex. 75) au lieu de la chaîne "ON". Le firmware reçoit directement un nombre et l'applique au variateur.

Après ajout, redémarrez HA. Le variateur apparaît comme une entité lumière dimmable avec un curseur de luminosité 0–100 %.




MQTT multi-canal

Pour les modules 2CH ou 4CH, créez des paires de topics et des descripteurs de canaux supplémentaires. Chaque canal dispose de sa propre paire abonnement/publication :

cpp
// Canal supplémentaire
rbdimmer_channel_t ch2;
const char* TOPIC_SET2   = "dimmer/ch2/level/set";
const char* TOPIC_STATE2 = "dimmer/ch2/level/state";
// Dans onMessage() : vérifier le topic, diriger vers le bon canal
if (strcmp(topic, TOPIC_SET) == 0) {
    rbdimmer_set_level(dimmerCh, level);
} else if (strcmp(topic, TOPIC_SET2) == 0) {
    rbdimmer_set_level(ch2, level);
}



Articles connexes



Encore des questions ?

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

Partager cet article
Se connecter pour laisser un commentaire.