**MQTT** 设备的发现将使人们能够在 [HomeAssistant](https://www.home-assistant.io) 方面只需要很少的配置工作就可以使用 **MQTT** 设备。配置是在设备本身和设备使用的主题上完成的。
> MQTT 发现默认启用,但可以禁用。发现主题的前缀(默认:`homeassistant`)可以更改。配置详情请参阅 [MQTT 选项部分](https://www.home-assistant.io/integrations/mqtt#configure-mqtt-options)
向 MQTT 发送配置主题后, HomeAssistant 会自动发现当前传感器。 当前任务中使用了一个板载LED灯,作为 HomeAssistant 中的 Light 组件。该组件在 HomeAssistant 的 仪表盘 中可以远程控制板载LED的开和关。使用 MQTT 客户端向配置主题发送消息即可。本项目中使用了三个传感器 + 一个台灯,具体配置主题如下:
// 台灯 消息
{
"name":"table-lamp",
"device_class": "light",
"command_topic":"homeassistant/light/FollowMe2-2-table-lamp/switch",
"state_topic":"homeassistant/sensor/FollowMe2-2/state",
"brightness_command_topic": "homeassistant/light/FollowMe2-2-table-lamp/brightness/set",
"brightness_state_topic": "homeassistant/sensor/FollowMe2-2/state",
"state_value_template": "{{ value_json.builtinLed }}",
"brightness_value_template": "{{ value_json.brightness }}",
"unique_id":"FollowMe2-2-table-lamp",
"device":{
"identifiers":[
"Arduino UNO R4 WiFi"
],
"name":"UNO R4 WiFi",
"manufacturer": "Arduino",
"model": "UNO R4 WiFi",
"hw_version": "1.0"
}
}
// 书房 温度传感器 消息
{
"device_class":"temperature",
"state_topic":"homeassistant/sensor/FollowMe2-2/state",
"unit_of_measurement":"°C",
"value_template":"{{ value_json.temperature}}",
"unique_id":"FollowMe2-2-study-temperature",
"device":{
"identifiers":[
"Arduino UNO R4 WiFi"
],
"name":"UNO R4 WiFi",
"manufacturer": "Arduino",
"model": "UNO R4 WiFi",
"hw_version": "1.0"
}
}
// 书房 湿度传感器 消息
{
"device_class":"humidity",
"state_topic":"homeassistant/sensor/FollowMe2-2/state",
"unit_of_measurement":"%",
"value_template":"{{ value_json.humidity}}",
"unique_id":"FollowMe2-2-study-humidity",
"device":{
"identifiers":[
"Arduino UNO R4 WiFi"
],
"name":"UNO R4 WiFi",
"manufacturer": "Arduino",
"model": "UNO R4 WiFi",
"hw_version": "1.0"
}
}
// 书房 环境光传感器 消息
{
"device_class":"illuminance",
"state_topic":"homeassistant/sensor/FollowMe2-2/state",
"unit_of_measurement":"lx",
"value_template":"{{ value_json.ambientLight}}",
"unique_id":"FollowMe2-2-study-illuminance",
"device":{
"identifiers":[
"Arduino UNO R4 WiFi"
],
"name":"UNO R4 WiFi",
"manufacturer": "Arduino",
"model": "UNO R4 WiFi",
"hw_version": "1.0"
}
}
/**
* FollowMe 2-2 任务4:
* 1. 通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)
*/
#include <Wire.h>
#include <WiFiS3.h>
#include <ArduinoMqttClient.h>
#include <ArduinoJson.h>
#include <Adafruit_AHTX0.h>
#include <Adafruit_LTR329_LTR303.h>
#include "arduino_secrets.h"
#define LOOP_DELAY 10 // loop函数延时(单位:毫秒)
#define SENSOR_REPORT_INTERVAL 5 // 传感器数据更新间隔(单位:秒)
#define STATE_ON "ON" // HA LED开状态
#define STATE_OFF "OFF" // HA LED关状态
char ssid[] = SECRET_SSID; // WIFI SSID
char pass[] = SECRET_PASS; // WIFI PASSWD
int status = WL_IDLE_STATUS; // WIFI 状态
// MQTT
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
const char broker[] = "192.168.2.120"; // HomeAssistant MQTT服务器地址
int port = 1883; // HomeAssistant MQTT服务器端口
char mqtt_user[] = MQTT_USER; // MQTT 用户名
char mqtt_pass[] = MQTT_PASS; // MQTT 密码
// 订阅主题(接收 HomeAssistant 控制板载LED开关指令)
const char switch_subscribe_topic[] = "homeassistant/light/FollowMe2-2-table-lamp/switch";
// 订阅主题(接收 HomeAssistant 控制板载LED亮度调节指令)
const char brightness_subscribe_topic[] = "homeassistant/light/FollowMe2-2-table-lamp/brightness/set";
bool isNeedReportState = true; // 是否需要更新状态到HA
bool ledState = false; // 板载LED状态
// 发布主题(上报板载LED状态至 HomeAssistant的状态主题)
const char publish_topic[] = "homeassistant/sensor/FollowMe2-2/state";
uint32_t tick = 0; // loop循环次数
uint8_t brightness = 0; // 灯亮度调节
Adafruit_AHTX0 aht; // AHT20 传感器
float temperature = 0; // AHT20 采集到的温度值
float humidity = 0; // AHT20 采集到的湿度值
Adafruit_LTR329 ltr = Adafruit_LTR329(); // LTR329传感器
float ambientLight = 0; // 环境光强度
ltr329_gain_t gain = LTR3XX_GAIN_1; // ALS增益
ltr329_integrationtime_t integrationTime = LTR3XX_INTEGTIME_100; // 积分时间
float integrationTimeVal = 0.1;
uint16_t visible_plus_ir; // 可见光
uint16_t infrared; // 红外
/**
* 设置板载LED状态
*/
void setLightState() {
if (ledState) {
if(0 == brightness) {
brightness = 255;
}
analogWrite(LED_BUILTIN, brightness);
} else {
analogWrite(LED_BUILTIN, 0);
}
}
void setup() {
// 初始化串口
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT); // 初始化板载LED引脚为输出
// 初始化 QWIIC 接口的 I2C 总线
Wire1.begin();
// 检查WIFI模块
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("WiFi模块通信失败!");
while (true);
}
// 连接到WIFI
Serial.print("尝试连接到 WIFI SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
Serial.print(".");
delay(5 * 1000);
}
Serial.println("WIFI 连接成功!");
// 连接MQTT
mqttClient.setUsernamePassword(mqtt_user, mqtt_pass);
Serial.print("尝试连接到MQTT服务器: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT 连接失败! ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("MQTT连接成功!");
// 订阅主题
mqttClient.onMessage(onMqttMessage);
mqttClient.subscribe(switch_subscribe_topic);
mqttClient.subscribe(brightness_subscribe_topic);
// AHT20 初始化
if (!aht.begin(&Wire1)) {
Serial.println("未找到 AHTX0 传感器!");
while (1) delay(10);
}
Serial.println("AHTX0 传感器初始化成功!");
if (!ltr.begin(&Wire1)) {
Serial.println("未找到 LTR329 传感器!");
while (1) delay(10);
}
Serial.println("LTR329 传感器初始化成功!");
}
void loop() {
if(isNeedReportState) {
// 汇报当前板载LED状态到HA
char msg[100] = {0};
sprintf(msg, "{\"builtinLed\": \"%s\", \"brightness\": %d,\"temperature\":%.2f,\"humidity\":%.2f, \"ambientLight\":%.2f}",
ledState ? STATE_ON : STATE_OFF, brightness, temperature, humidity, ambientLight);
mqttClient.beginMessage(publish_topic);
mqttClient.print(msg);
mqttClient.endMessage();
isNeedReportState = false; // 上报板载LED状态到HA后重置汇报状态
}
if(0 == (tick % (SENSOR_REPORT_INTERVAL * 1000 / LOOP_DELAY))) { // 根据传感器数据更新间隔 SENSOR_REPORT_INTERVAL 宏定义进行上报传感器数据
// 读取 AHT20 传感器数据
sensors_event_t humi, temp;
aht.getEvent(&humi, &temp);
temperature = temp.temperature;
humidity = humi.relative_humidity;
// 读取 LTR329 传感器数据
if (ltr.newDataAvailable()) {
ltr.readBothChannels(visible_plus_ir, infrared);
// 环境光照度计算
float ratio = infrared / (visible_plus_ir + infrared);
if(ratio < 0.45) {
ambientLight = (1.7743 * visible_plus_ir + 1.1059 * infrared) / (1 << gain) / integrationTimeVal;
} else if(ratio < 0.64 && ratio >= 0.45) {
ambientLight = (4.2785 * visible_plus_ir - 1.9548 * infrared) / (1 << gain) / integrationTimeVal;
} else if(ratio < 0.85 && ratio >= 0.64) {
ambientLight = (0.5926 * visible_plus_ir + 0.1185 * infrared) / (1 << gain) / integrationTimeVal;
} else {
ambientLight = 0;
}
}
// 更新状态,更新传感器数据到HA
isNeedReportState = true;
}
// 更新板载LED状态
setLightState();
mqttClient.poll(); // 定期检查新MQTT消息
delay(LOOP_DELAY); // 主循环延时时长
tick ++;
}
// MQTT 订阅消息回调,接收HA控制板载LED的指令(ON:开,OFF:关)
void onMqttMessage(int messageSize) {
char topic[100] = {0};
String message;
// 打印消息主题
Serial.print("Received message from topic: ");
strcpy(topic, mqttClient.messageTopic().c_str());
Serial.println(topic);
// 读取消息内容
for (int i = 0; i < messageSize; i++) {
message += (char)mqttClient.read();
}
// 打印消息的内容
Serial.print("Received message: ");
Serial.println(message);
if(0 == strcmp(switch_subscribe_topic, topic)) {
// 开关
if(0 == strcmp(STATE_ON, message.c_str())) {
if(false == ledState) {
// 需要更新板载LED状态到HA
isNeedReportState = true;
}
ledState = true;
} else {
if(true == ledState) {
// 需要更新板载LED状态到HA
isNeedReportState = true;
}
ledState = false;
}
} else if(0 == strcmp(brightness_subscribe_topic, topic)) {
// 亮度
uint8_t b = message.toInt();
if (brightness < 0 || brightness > 255) { // 范围校验
// do nothing...
return;
} else {
brightness = b;
setLightState();
isNeedReportState = true;
}
}
}
本项目中结合 Adafruit LTR-329 Light Sensor 环境光传感器模块作为书房环境光照监测。当光照低于阀值时,自动打开台灯(本例中没有对接真实的智能台灯,使用板载LED模拟,可以控制开关与亮度)。光照充足时自动关闭台灯。实现自动调整书房光线,无需手动干预。在节能方面,避免不必要的照明,节省电力。同时保持书房光线在最佳水平,保护眼睛,提高阅读和工作效率。
Arduino Uno R4 WiFi智能书房是一个基于Arduino Uno R4开发板和ESP8266 Wi-Fi模块的智能家居项目。这个项目的主要功能是通过Wi-Fi连接,实现对书房内环境以及各种设备的远程控制和管理。
通过这个项目,我们不仅提高了对物联网技术的理解和运用能力,也学会了如何将理论转化为解决实际问题的应用。希望这些经验和心得能为未来的项目提供参考和启发。