下面是一个基于 Home Assistant (HA) 的 MQTT 协议来实现电工、照明设备集成和客户端兼容性开发的详细方案和示例代码。该方案重点在于:
- 使用 MQTT 协议与 Home Assistant 进行集成;
- 利用 Home Assistant 提供的 MQTT Discovery 功能,实现设备自动发现与接入;
- 设计一种标准化的 MQTT Topic 和 Payload 格式,适用于电工类(例如开关、插座)和照明类(灯具、调光器)设备;
- 给出参考代码(以ESP32为例)实现 MQTT 客户端,并与 Home Assistant 进行通信;
- 使用 Home Assistant 前端查看和控制设备状态。
1. 系统组成与总体思路
1.1 系统组成
-
主控设备(例如ESP32):
- 连接本地网络(通过 Wi-Fi)
- 运行 MQTT 客户端,通过 MQTT Broker 与 Home Assistant 通信
- 控制电工和照明外设(例如:继电器驱动开关,LED调光,电量传感器等)
- 接收来自 Home Assistant 的指令,更新状态并上报数据
-
MQTT Broker:
- 使用 Eclipse Mosquitto 等常用MQTT Broker,通常与 Home Assistant 在同一局域网中
- 主控设备和 Home Assistant 都通过该 Broker 通信
-
Home Assistant:
- 通过 MQTT Discovery 自动发现设备
- 在界面中显示开关、灯具控制面板
- 发送MQTT消息控制设备(开关、亮度、色温等)
1.2 功能目标
-
支持电工类设备(如智能插座、继电器开关):
- 状态上报(ON/OFF)
- 接收控制指令(ON/OFF)
-
支持照明类设备(如智能灯具):
- 上报当前亮度、色温、开关状态
- 接收控制指令调整亮度、色温和开关
-
借助 MQTT Discovery ,无需手动在 Home Assistant 中配置,设备上线后自动出现在前端界面。
1.3 MQTT Topic 与 负载设计
参考 Home Assistant MQTT Discovery 文档(https://www.home-assistant.io/docs/mqtt/discovery/),对于开关类实体和灯光类实体,需要在特定的 discovery topic 下发布 JSON 配置。
1.3.1 MQTT Discovery Topic 格式
- Discovery Prefix:
homeassistant
- 设备类别:
- 开关:
switch
- 灯:
light
- 开关:
- 实例ID:设备的唯一ID(如
my_device_01
)
例如,一个开关设备的配置发布主题:
homeassistant/switch/my_device_01/config
灯设备的配置发布主题:
homeassistant/light/my_device_01/config
1.3.2 配置消息(config payload)示例
开关(switch) config payload示例:
{
"name": "My Smart Switch",
"unique_id": "my_device_01_switch",
"command_topic": "my_device_01/switch/cmnd",
"state_topic": "my_device_01/switch/state",
"payload_on": "ON",
"payload_off": "OFF",
"retain": false
}
灯(light) config payload示例(包含亮度、色温支持):
{
"name": "My Smart Light",
"unique_id": "my_device_01_light",
"command_topic": "my_device_01/light/cmnd",
"state_topic": "my_device_01/light/state",
"brightness_command_topic": "my_device_01/light/brightness/cmnd",
"brightness_state_topic": "my_device_01/light/brightness/state",
"color_temp_command_topic": "my_device_01/light/color_temp/cmnd",
"color_temp_state_topic": "my_device_01/light/color_temp/state",
"payload_on": "ON",
"payload_off": "OFF",
"brightness": true,
"color_temp": true,
"max_mireds": 500,
"min_mireds": 153,
"retain": false
}
1.3.3 状态与指令Topic约定
-
开关类:
- 状态主题:
my_device_01/switch/state
(payload: “ON”/“OFF”) - 控制主题:
my_device_01/switch/cmnd
(payload: “ON”/“OFF”)
- 状态主题:
-
灯类:
- 开关状态主题:
my_device_01/light/state
(payload: “ON”/“OFF”) - 开关控制主题:
my_device_01/light/cmnd
(payload: “ON”/“OFF”) - 亮度状态主题:
my_device_01/light/brightness/state
(payload: 整数0-255) - 亮度控制主题:
my_device_01/light/brightness/cmnd
(payload: 整数0-255) - 色温状态主题:
my_device_01/light/color_temp/state
(payload: 整数153-500) - 色温控制主题:
my_device_01/light/color_temp/cmnd
(payload: 整数153-500)
- 开关状态主题:
2. 设备端(ESP32)软件设计
2.1 初始化步骤
- 初始化NVS、Wi-Fi,连接到本地网络。
- 初始化MQTT客户端,连接MQTT Broker。
- 发布Home Assistant Discovery配置消息(config)到相应的config topic。
- 订阅控制话题(
my_device_01/.../cmnd
)等待指令下发。
2.2 状态上报与控制逻辑
- 当设备启动完成后,发布 config 消息使 Home Assistant 自动发现设备。
- 设备定期或在状态变化时,发布状态到
state
话题。 - 当收到
cmnd
话题指令时,解析指令并执行本地控制(如控制GPIO驱动继电器),然后更新状态。
2.3 硬件交互示例
- 开关类设备:使用GPIO驱动继电器(例如GPIO 5接继电器模块)控制电源通断。
- 照明类设备:使用PWM调光LED,改变占空比实现亮度调节,使用CCT调光器件实现色温调节。
3. Home Assistant 配置
使用 MQTT Discovery,无需在 Home Assistant 中手动配置,只需确保HA中已启用MQTT集成,并在 configuration.yaml
中包含:
mqtt:
discovery: true
discovery_prefix: homeassistant
4. 示例代码(基于ESP-IDF + MQTT + FreeRTOS)
下面的代码示例为简化版本,用ESP-IDF,假设您已有Wi-Fi连接代码以及使用idf.py menuconfig
配置好MQTT Broker地址。请根据实际环境修改。
main.c 示例
#include <string.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "mqtt_client.h"
#include "esp_wifi.h"
#include "driver/ledc.h"
#include "driver/gpio.h"
#define TAG "MQTT_HA"
// 请根据实际修改
#define MQTT_URI "mqtt://192.168.1.100:1883"
#define DEVICE_ID "my_device_01"
// GPIO定义(示例)
#define RELAY_GPIO (5)
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_TIMER LEDC_TIMER_0
#define LED_GPIO (4)
static esp_mqtt_client_handle_t client = NULL;
static bool light_on = false;
static int light_brightness = 128; // 0-255
static int light_color_temp = 300; // 153-500之间
static bool switch_on = false;
// 发布config消息(在连接MQTT后调用)
static void publish_discovery_config()
{
// 发布开关设备的config
const char *switch_config_topic = "homeassistant/switch/" DEVICE_ID "_switch/config";
const char *switch_config_payload =
"{"
"\"name\": \"My Smart Switch\","
"\"unique_id\": \"" DEVICE_ID "_switch\","
"\"command_topic\": \"" DEVICE_ID "/switch/cmnd\","
"\"state_topic\": \"" DEVICE_ID "/switch/state\","
"\"payload_on\": \"ON\","
"\"payload_off\": \"OFF\","
"\"retain\": false"
"}";
esp_mqtt_client_publish(client, switch_config_topic, switch_config_payload, 0, 1, 1);
// 发布灯设备的config
const char *light_config_topic = "homeassistant/light/" DEVICE_ID "_light/config";
const char *light_config_payload =
"{"
"\"name\": \"My Smart Light\","
"\"unique_id\": \"" DEVICE_ID "_light\","
"\"command_topic\": \"" DEVICE_ID "/light/cmnd\","
"\"state_topic\": \"" DEVICE_ID "/light/state\","
"\"brightness_command_topic\": \"" DEVICE_ID "/light/brightness/cmnd\","
"\"brightness_state_topic\": \"" DEVICE_ID "/light/brightness/state\","
"\"color_temp_command_topic\": \"" DEVICE_ID "/light/color_temp/cmnd\","
"\"color_temp_state_topic\": \"" DEVICE_ID "/light/color_temp/state\","
"\"payload_on\": \"ON\","
"\"payload_off\": \"OFF\","
"\"brightness\": true,"
"\"color_temp\": true,"
"\"max_mireds\": 500,"
"\"min_mireds\": 153,"
"\"retain\": false"
"}";
esp_mqtt_client_publish(client, light_config_topic, light_config_payload, 0, 1, 1);
}
// 更新状态到MQTT
static void update_switch_state()
{
const char *topic = DEVICE_ID "/switch/state";
const char *payload = switch_on ? "ON" : "OFF";
esp_mqtt_client_publish(client, topic, payload, 0, 1, 0);
}
static void update_light_state()
{
// light开关状态
esp_mqtt_client_publish(client, DEVICE_ID "/light/state", light_on ? "ON" : "OFF", 0, 1, 0);
// 亮度状态:转化为字符串
char brightness_str[8];
snprintf(brightness_str, sizeof(brightness_str), "%d", light_brightness);
esp_mqtt_client_publish(client, DEVICE_ID "/light/brightness/state", brightness_str, 0, 1, 0);
// 色温状态
char color_temp_str[8];
snprintf(color_temp_str, sizeof(color_temp_str), "%d", light_color_temp);
esp_mqtt_client_publish(client, DEVICE_ID "/light/color_temp/state", color_temp_str, 0, 1, 0);
}
// 根据light_on、light_brightness、light_color_temp控制硬件(PWM LED)
static void apply_light_settings()
{
// 设置PWM占空比,实现亮度控制
int duty = (light_brightness * 8191) / 255; // LEDC分辨率13bit
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL, duty);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL);
// 对色温可添加相应控制逻辑(需双通道LED实现CCT调整,这里仅示例)
// 如果只有单色LED,这里忽略色温实际控制
// 开关控制:如果light_on=false,则 duty=0
if (!light_on) {
ledc_set_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL, 0);
ledc_update_duty(LEDC_HIGH_SPEED_MODE, LEDC_CHANNEL);
}
}
// 根据switch_on控制继电器GPIO
static void apply_switch_state()
{
gpio_set_level(RELAY_GPIO, switch_on ? 1 : 0);
}
// MQTT事件回调
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT connected");
// 发布discovery
publish_discovery_config();
// 订阅控制话题
esp_mqtt_client_subscribe(client, DEVICE_ID "/switch/cmnd", 1);
esp_mqtt_client_subscribe(client, DEVICE_ID "/light/cmnd", 1);
esp_mqtt_client_subscribe(client, DEVICE_ID "/light/brightness/cmnd", 1);
esp_mqtt_client_subscribe(client, DEVICE_ID "/light/color_temp/cmnd", 1);
// 更新当前状态到MQTT
update_switch_state();
update_light_state();
break;
case MQTT_EVENT_DATA: {
// 收到控制数据
char topic[128];
char data[128];
snprintf(topic, event->topic_len+1, "%s", event->topic);
snprintf(data, event->data_len+1, "%s", event->data);
if (strcmp(topic, DEVICE_ID "/switch/cmnd") == 0) {
if (strcmp(data, "ON") == 0) switch_on = true;
else if (strcmp(data, "OFF") == 0) switch_on = false;
apply_switch_state();
update_switch_state();
} else if (strcmp(topic, DEVICE_ID "/light/cmnd") == 0) {
if (strcmp(data, "ON") == 0) light_on = true;
else if (strcmp(data, "OFF") == 0) light_on = false;
apply_light_settings();
update_light_state();
} else if (strcmp(topic, DEVICE_ID "/light/brightness/cmnd") == 0) {
int val = atoi(data);
if (val < 0) val = 0;
if (val > 255) val = 255;
light_brightness = val;
apply_light_settings();
update_light_state();
} else if (strcmp(topic, DEVICE_ID "/light/color_temp/cmnd") == 0) {
int val = atoi(data);
if (val < 153) val = 153;
if (val > 500) val = 500;
light_color_temp = val;
apply_light_settings();
update_light_state();
}
break;
}
default:
break;
}
return ESP_OK;
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base,
int32_t event_id, void *event_data)
{
mqtt_event_handler_cb(event_data);
}
// Wi-Fi连接逻辑省略,假设已连接成功
void app_main(void)
{
// 初始化NVS、事件循环
nvs_flash_init();
esp_event_loop_create_default();
// 初始化Wi-Fi代码省略(请根据实际连接到MQTT服务器的内网Wi-Fi)
// ...
// 初始化GPIO、PWM
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << RELAY_GPIO),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = false,
.pull_down_en = false,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&io_conf);
ledc_timer_config_t ledc_timer = {
.speed_mode = LEDC_HIGH_SPEED_MODE,
.duty_resolution = LEDC_TIMER_13_BIT,
.timer_num = LEDC_TIMER,
.freq_hz = 5000
};
ledc_timer_config(&ledc_timer);
ledc_channel_config_t ledc_channel_conf = {
.channel = LEDC_CHANNEL,
.duty = 0,
.gpio_num = LED_GPIO,
.speed_mode = LEDC_HIGH_SPEED_MODE,
.hpoint = 0,
.timer_sel = LEDC_TIMER
};
ledc_channel_config(&ledc_channel_conf);
// 初始化MQTT
esp_mqtt_client_config_t mqtt_cfg = {
.uri = MQTT_URI
};
client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
// 主循环可空转或做其他处理
while (true) {
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
5. 测试步骤
- 启动 MQTT Broker(例如在同网段的PC上运行 Mosquitto)。
- 启动 Home Assistant,并确保
mqtt:
配置已启用 discovery。 - 烧录上面的代码到 ESP32,启动后ESP32连接Wi-Fi,连接MQTT。
- Home Assistant 几秒后应自动发现新设备:
My Smart Switch
和My Smart Light
。 - 在 Home Assistant 前端控制该开关和灯,观察ESP32串口日志,以及实际继电器和LED的变化。
6. 扩展与优化
- 可增加更多传感器(温度、功率计量)并通过MQTT Sensor Discovery发布数据给HA。
- 增加离线检测机制,当MQTT断开时自动重连。
- 根据实际硬件结构实现更复杂的灯光控制方案(如CCT双路PWM)和电工测量(电流传感器等)。
以上是基于 Home Assistant 的 MQTT 协议整合电工、照明及客户端开发的详细方案与参考代码。