[作品提交] 【Follow me第二季第2期】智能家居之智能书房

鲜de芒果   2024-10-2 17:29 楼主

1. 任务要求

  1. 通过外部LTR-329 环境光传感器,上传温湿度到HA,通过HA面板显示数据
  2. 通过外部AHT20温湿度传感器,上传温湿度到HA,通过HA面板显示数据
  3. 使用板载LED模拟台灯,可通过HA面板控制其开关与亮度调节
  4. 书房自动光线调节是一个智能书房的重要组成部分,它能够根据环境光线的变化自动调整台灯的亮度或开关状态,以确保阅读或工作时的光线既充足又舒适

    

2. 硬件准备

 

3. HomeAssistant集成

**MQTT** 设备的发现将使人们能够在 [HomeAssistant](https://www.home-assistant.io) 方面只需要很少的配置工作就可以使用 **MQTT** 设备。配置是在设备本身和设备使用的主题上完成的。

 

> MQTT 发现默认启用,但可以禁用。发现主题的前缀(默认:`homeassistant`)可以更改。配置详情请参阅 [MQTT 选项部分](https://www.home-assistant.io/integrations/mqtt#configure-mqtt-options)

 

3.1 配置主题

向 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"
  }
}

 

4. 代码实现

/**
 * 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;
    }
  }
}

 

5. 智能家居自动化

本项目中结合 Adafruit LTR-329 Light Sensor 环境光传感器模块作为书房环境光照监测。当光照低于阀值时,自动打开台灯(本例中没有对接真实的智能台灯,使用板载LED模拟,可以控制开关与亮度)。光照充足时自动关闭台灯。实现自动调整书房光线,无需手动干预。在节能方面,避免不必要的照明,节省电力。同时保持书房光线在最佳水平,保护眼睛,提高阅读和工作效率。

 

6. 效果展示

2024-09-08_20-44-40.png
2024-09-08_20-45-53.png

 

7. 演示视频


 

 

8. 结语

Arduino Uno R4 WiFi智能书房是一个基于Arduino Uno R4开发板和ESP8266 Wi-Fi模块的智能家居项目。这个项目的主要功能是通过Wi-Fi连接,实现对书房内环境以及各种设备的远程控制和管理。

通过这个项目,我们不仅提高了对物联网技术的理解和运用能力,也学会了如何将理论转化为解决实际问题的应用。希望这些经验和心得能为未来的项目提供参考和启发。

 

9. 参考资料

 

10. 传送门

 

11. 项目源码

源码.zip (7.76 KB)
(下载次数: 2, 2024-10-2 17:27 上传)


 

本帖最后由 鲜de芒果 于 2024-10-2 17:28 编辑

回复评论 (2)

感谢楼主分享的智能家居的技术知识,非常详细,通俗易懂,值得收藏学习

点赞  2024-10-2 19:51

创意和设计很好,分享的也很详细。学习了~~~

没有特别的幸运,就要特别的努力
点赞 (1) 2024-10-2 20:42
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复