进阶任务主要使用的是Arduino UNO R4 WiFi板子的ESP32S3 WiFi模块。尽管我对这一领域的知识尚浅,但通过与Arduino、上位机软件、HomeAssistant(HA)这一开源智能家居平台,以及MQTT协议和EMQX消息服务器的深入交互,我得以构建了一个多平台联动的智能系统。这一过程充满了挑战,但也充满了成就感。在本文中,我将分享我的探索之旅,包括遇到的困难和解决方案,希望能为同样走在这条道路上的你提供一些启示和帮助。
为了实现我们智能家居项目的核心功能,我们首先需要安装并配置Home Assistant(HA),这是一个流行的开源智能家居平台。详细的安装和使用教程可以在【Home Assistant (home-assistant.io)】找到。按照“Get Started”的指引,我们可以进入官方教程,了解HA支持的多种安装方式。
我们选择列表中的第一个镜像,并通过执行docker pull homeassistant/home-assistant命令来拉取它。请注意,拉取过程可能需要一些时间,并且有时会因为网络问题而中断。如果遇到失败,只需重新尝试即可。
拉取完成后,我们需要配置Docker容器在本地的存储位置,并运行容器。与官方教程稍有不同,由于我们已经提前拉取了容器,因此不需要再次从镜像源下载。我们可以直接使用以下命令来运行容器:
docker run -d --name homeassistant -v /path/to/local/config:/config -p 8123:8123 homeassistant/home-assistant
请将/path/to/local/config替换为你本地存放容器配置文件的实际路径,并将端口号8123替换为你希望使用的端口。
运行上述命令后,你可以在Docker Engine中看到名为homeassistant的容器。通过访问http://localhost:8123,你可以进入Home Assistant的Web界面。
在首次访问时,系统会提示你创建你的智能家居。按照提示完成一系列信息注册后,重新登录Home Assistant,你就可以进入主界面了。
完成后重新登录HomeAssistant,主页显示的相关信息如下:
2. EMQX平台的安装和配置
MQTT协议是一种轻量级的、基于发布/订阅模式的消息传输协议,广泛用于物联网和分布式系统中。它具有简单易实现、支持多种服务质量(QoS)、报文精简、基于TCP/IP等特性,特别适合于带宽有限和网络不稳定的环境。EMQX平台是一个高性能、可扩展的MQTT消息服务器,支持大规模分布式物联网设备的连接,能够实时处理和移动大量消息和事件流数据。
EMQX的具体信息可以在其官方网站【EMQX 文档】查看,里面也提供了使用MQTT协议的相关教程。我们还是采用docker拉取容器的方式,参考【通过 Docker 运行 EMQX | EMQX文档】的文档说明。我们在指令栏中输入docker search emqx来查找可供拉取的容器列表。
没有看到说明文档中提到的带版本号的emqx容器,就直接拉取第一个根目录,使用docker pull emqx来进行拉取。
拉取完成后,我们可以使用以下命令来运行EMQX容器:
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 -v /path/to/local/config:/opt/emqx/data emqx/emqx:5.8.0
请将/path/to/local/config替换为您本地存放容器配置文件的实际路径。此时可以看到docker的容器列表中新增了emqx容器。
使用https://localhost:18083端口可以打开EMQX平台,参考以下文档进行初步的测试【快速开始 | EMQX文档】,平台默认的账号是admin,密码是public,即可登录EMQX Dashboard,界面如下:
接下来,我们需要在EMQX Dashboard中创建客户端认证,并添加用户作为HA平台的接入。
完成后,我们需要在HA平台中配置MQTT服务,填写相关的配置信息,包括EMQX平台的IP、用户名和密码等。EMQX节点的名称可以在集群概览中查看,比如这边是emqx@172.17.0.2。
通过HA平台的设置菜单,配置新的设备与服务,选择MQTT。
配置完成后,我们可以通过HA平台的设置菜单,配置新的设备与服务,选择MQTT,并填写相关的配置信息。这样,HA平台就可以通过MQTT协议与EMQX平台进行通信了。
最后,我们可以通过检查EMQX平台的在线连接数来验证HA平台是否已经成功接入EMQX集群。如果连接数从0变为1,说明HA平台已经成功接入。接下来,我们可以通过MQTT协议将Arduino接入EMQX平台,实现Arduino和HA之间的通信和数据传输。
3. 进阶任务(必做):ArduinoWifi连接并通过MQTT协议接入到HomeAssistant平台
我们将探讨如何将Arduino UNO R4 WiFi开发板通过WiFi连接,并利用MQTT协议接入HomeAssistant平台。这一过程不仅涉及到硬件的配置,还包括了软件的集成,是对我们技能的一次全面考验。
首先,我们需要启动Arduino的WiFi模块。可以参考官方文档【docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples】,里面提供了Arduino连接Wifi的示例。我们创建一个arduino_secret.h的保密文件,用于存储连接WiFi路由器的敏感信息,如网络名称(SSID)和密码等。
由于我在学校连接校园网需要特定的账号和密码,这一部分在Arduino中实现较为复杂,因此我们选择了一个更为简便的方法:使用手机作为热点,让Arduino通过热点进行连接。
我们直接采用官方例程中的代码,配置WiFi模块。主要包括以下几个部分:引入必要的头文件WiFiS3.h;使用WiFi.begin(ssid, pass)启用WiFi并连接;确认WiFi连接状态并打印相关信息,如网络名称、IP地址、MAC地址等。
#include <WiFiS3.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS; // the WiFi radio's status
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
printCurrentNet();
printWifiData();
}
void loop() {
// check the network connection once every 10 seconds:
delay(10000);
printCurrentNet();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
printMacAddress(mac);
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial.print("Encryption Type:");
Serial.println(encryption, HEX);
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) {
Serial.print(":");
}
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
}
Serial.println();
}
将代码烧录到Arduino中,我们可以看到WiFi模块成功连接到了手机热点,并且打印出了网络信息。同时手机上也显示ESP32S3模块的连接。至此完成了wifi模块的使用。
接下来,我们需要在Arduino IDE中安装MQTT和HomeAssistant相关的库文件。可以在Library管理器中搜索并安装home-assistant-integration库。
安装好所有所需的库文件和插件,我们可以查看一下其中涉及MQTT相关操作的例程,因为后面可选任务涉及光照和温湿度传感器的使用,所以我们以模拟传感器的例程为参考【
】,我们使用Arduino内置的DAC来暂时模拟一下传感器的输出。
由于我们已经配置好了EMQX平台,接下来需要在arduino_secret.h文件中增加EMQX平台的用户名、密码等信息,具体如下:
//arduino_secrets.h header file
#define SECRET_SSID "Galaxy S24+ 6927"
#define SECRET_PASS "LYQ1234567890"
#define MQTT_SERVER "192.168.40.250"
#define MQTT_PORT 1883
#define MQTT_CLIENT_ID "arduino"
#define MQTT_USERNAME "admin"
#define MQTT_PASSWORD "admin"
#define TOPIC_SUBSCRIBE "UNO/arduino/sensor"
因为EMQX平台是基于电脑的IP搭建的,其中MQTT_SERVER后的地址就是当前电脑无线网络的IP地址,可以在指令栏中通过ipconfig/all来查询,如下:
将相关信息全部录入arduino_secret.h头文件,然后仿照上面的例程。因为例程中使用的Ethernet以太网,所以我们只需要学习其中涉及MQTT相关的部分,将其合并到上面的Wifi连接的程序中。
现在,我们将WiFi连接代码与MQTT代码整合在一起。首先,我们引入ArduinoHA.h头文件,以便使用HomeAssistant平台。
我们使用HADevice device(MQTT_CLIENT_ID)和HAMqtt mqtt(client, device)来创建HA设备启用MQTT协议。然后我们实例化了几个HA订阅的传感器,比如按钮、模拟传感器和更新时间传感器等,这些可以根据后面任务的需求进行调整。也可以通过device.XX或者某个具体定义的传感器的字段进行修改,来自定义传感器在HA平台的UI上呈现的形式(比如图标、是否附加单位等)。
以上的初始设置完成以后,我们在Wifi代码的基础上增加以下代码:
Serial.println("\nStart connecting to MQTT server");
if (!mqtt.begin(MQTT_SERVER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD)){
Serial.print("Connection falied");
Serial.print(mqtt.getState());
Serial.println("Try again in 5 seconds");
delay(5000);
}
核心为mqtt. begin()用于启动MQTT的连接,需要输入服务器的地址、端口以及我们预设好的用户名和密码。完成后需要在程序的主循环中通过mqtt.loop()使其使用MQTT协议进行信息的发送。后面我们就仿照例程中发送传感器数据的方式,添加了两个每间隔1000ms进行一次更新采集数据和时间的代码,完整代码如下:
#include <WiFiS3.h>
#include <ArduinoHA.h>
#include "arduino_secrets.h"
#include "analogWave.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS; // the WiFi radio's status
unsigned long lastUpdateAt = 0;
int freq = 1;
WiFiClient client;
HADevice device(MQTT_CLIENT_ID);
HAMqtt mqtt(client, device);
HASensorNumber analogSensor("myAnalogInput", HASensorNumber::PrecisionP1);
HASensorNumber uptimeSensor("myUptime");
HAButton buttonA("myButtonA");
HAButton buttonB("myButtonB");
analogWave wave(DAC);
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
printCurrentNet();
printWifiData();
Serial.println("\nStart connecting to MQTT server");
if (!mqtt.begin(MQTT_SERVER, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD)){
Serial.print("Connection falied");
Serial.print(mqtt.getState());
Serial.println("Try again in 5 seconds");
delay(5000);
}
wave.sine(freq);
wave.amplitude(0.5);
analogReadResolution(14);
device.setName("Arduino");
device.setSoftwareVersion("1.0.0");
buttonA.setIcon("mdi:fire");
buttonA.setName("Click me A");
buttonB.setIcon("mdi:home");
buttonB.setName("Click me B");
}
void loop() {
// check the network connection once every 10 seconds:
mqtt.loop();
if ((millis() - lastUpdateAt) > 1000) { // 1000ms debounce time
uint16_t reading = analogRead(A0);
float voltage = reading * 5.f / 16383.f; // 0.0V - 5.0V
Serial.print("Volt:");
Serial.println(voltage);
analogSensor.setValue(voltage);
unsigned long uptimeValue = millis() / 1000;
Serial.print("Uptime:");
Serial.println(uptimeValue);
uptimeSensor.setValue(uptimeValue);
lastUpdateAt = millis();
}
}
全部代码完成以后,将其烧录,同时启动docker中的HA容器和EMQX容器,并通过对应的端口号打开其网页。烧录需要花费很多时间,电脑因为开了太多的东西已经卡顿不堪了,最终结果如下:
我们可以看到Arduino首先成功连接了wifi,并输出wifi的相关信息,然后尝试建立MQTT的连接并且成功连接,Arduino通过串口发送了采集到的传感器电压,以及更新时间。
在HA平台的服务器上,我们可以看到Arduino已经成功接入并开始更新采样到的电压和时间信息。
至此,我们成功完成了Arduino通过WiFi连接并通过MQTT协议接入HomeAssistant平台的任务,属实不易。具体信息的动态展示可以查看随附的视频。
05-Wifi+MQTT接入HA平台