[作品提交] 【Follow me第二季第2期】基于Home Assistant的智能温湿度监测系统

慕容雪花   2024-9-27 10:26 楼主

fINAL

 

本次活动的板卡实物照片:

1.jpg

任务1:搭建环境并开启第一步Blink / 串口打印Hello EEWorld!

板载LED小灯连接到MCU P102引脚。

2.jpg

软件流程图:

流程图-任务1.png

接下来在Arduino环境里控制LED与串口打印:

// the setup function runs once when you press reset or power the board
void setup() {
  Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  Serial.println("Hello EEWorld!");
  digitalWrite(LED_BUILTIN, HIGH);  // turn the LED on (HIGH is the voltage level)
  delay(1000);                      // wait for a second
  digitalWrite(LED_BUILTIN, LOW);   // turn the LED off by making the voltage LOW
  delay(1000);                      // wait for a second
}

实物展示:

710604376

 

任务2-1 驱动12*8 LED矩阵

软件流程图:

流程图-任务2.png

UNO R4开发板提供了一个12*8矩阵的LED灯,这是非常奢侈的!以往开发板提供4个小灯不错了,哈哈。

image.png  

 

image.png 其实驱动起来是非常简单的事情。只需要仔细阅读Arduino官方文档:Using the Arduino UNO R4 WiFi LED Matrix https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix/#

然后使用官方提供的工具生成字模即可。

image.png  

点击右上角的下载,可以保存到本地。

#include "Arduino_LED_Matrix.h"   // Include the LED_Matrix library
#include "frames.h"               // Include a header file containing some custom icons

ArduinoLEDMatrix matrix;          // Create an instance of the ArduinoLEDMatrix class

void setup() {
  Serial.begin(115200);           // Initialize serial communication at a baud rate of 115200
  matrix.begin();                 // Initialize the LED matrix
}

void loop() {
  matrix.loadFrame(dian);
  delay(500);  // Pause for 500 milliseconds (half a second)

  matrix.loadFrame(zi);
  delay(500);

  matrix.loadFrame(gong);
  delay(500);

  matrix.loadFrame(cheng);
  delay(500);

    matrix.loadFrame(shi);
  delay(500);

    matrix.loadFrame(jie);
  delay(500);
  matrix.loadFrame(LEDMATRIX_HEART_BIG);
  delay(500);

  matrix.clear();
  delay(1000);

  Serial.println(millis());
}

实物展示:

1101657218

 

任务2-2 利用DAC生成正弦波

根据电路原理图,板载A0接口即为DAC输出接口。

image.png  

使用analogWave库,快速生成正弦波:

#include "analogWave.h" // Include the library for analog waveform generation

analogWave wave(DAC);   // Create an instance of the analogWave class, using the DAC pin

int freq = 1000;  // in hertz, change accordingly

void setup() {
  Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200
  wave.sine(freq);       // Generate a sine wave with the initial frequency
}

void loop() {
  wave.freq(freq);  // Set the frequency of the waveform generator to the updated value
}

实物展示:

556328857

 

任务2-3: 用OPAMP放大DAC信号

软件流程图:

流程图-任务3-1.png

运算放大器,模电的精髓,自从离开校园后没有再计算过运放增益!依稀记得虚短,虚断!

image.png  

 

至于放大倍数如何计算:

image.png  

 

手头刚好有两个10k电阻,这就搭建一个放大倍数为2的运放电路!

image.png  

在代码编写方面,简单的就是只有一行语句:

#include <OPAMP.h>

void setup () {
  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}

void loop() {}

这里有个不错的地方,就是可以利用前置任务DAC生成的sine信号作为输入,然后经过运放放大后,接入示波器。

#include "analogWave.h" // Include the library for analog waveform generation
#include <OPAMP.h>

analogWave wave(DAC);   // Create an instance of the analogWave class, using the DAC pin

int freq = 1000;  // in hertz, change accordingly

void setup() {
  Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200
  wave.sine(freq);       // Generate a sine wave with the initial frequency
  wave.amplitude(0.25);

  OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
}

void loop() {
  //wave.freq(freq);  // Set the frequency of the waveform generator to the updated value
}

实物展示:

image.png  

1068544000

 

任务2-4:使用ADC获取数据并波形展示

软件流程图:

流程图-任务3-2.png

在Arduino中使用ADC接口获取数据:

Serial.println(analogRead(A5));

放大前的信号:

image.png  

放大后的信号:

image.png  

 

为了把两个波形展示在一个图框里,可以采用下面的代码:

  Serial.print("Variable_1:");
  Serial.print(analogRead(A4));
  Serial.print(",");
  Serial.print("Variable_2:");
  Serial.println(analogRead(A5));

效果:

image.png  

 

进阶任务(必做):通过Wi-Fi,利用MQTT协议接入到开源的智能家居平台HA(HomeAssistant)

流程图-任务4.png

HomeAssistant是非常知名的智能家居平台,早有耳闻,但是一直没有尝试过。这也是参加本期FM活动的动力!

安装HA有很多种方式,可以参考官网链接:https://www.home-assistant.io/installation/windows/。本文选择的是去下载官网提供的VMware文件,然后直接使用VMWare Workstation来加载这个虚拟机。

 

安装过程有很多参考文章,在此不再赘述。

image.png  

看到上面的标志性界面后,就可以打开主机上的浏览器,然后输入http://homeassistant.local:8123/ 来进入到HA Os里面。之后就是漫长的等待,真的是漫长。

image.png  

添加EMQX,目的是在HA里面搭建一个MQTT服务器或者BROKER代理。

image.png  

稍后进入到EMQX平台,需要用户名和密码:

image.png  

 

接着配置认证方式:

image.png  

image.png  

EMQX里面创建一个用户名和密码,稍后在HA设备与服务->MQTT配置参数的时候可用到。后续还可以添加更多的用户:

image.png  

接着配置一个MQTT应用。这个应用会连接到上一步中创建的MQTT BROKER。

image.png  

在HA->Settings->Device and Service->Add Integration ->MQTT->Manually add MQTT

image.png  

 

完整的测试代码:

/*
  ArduinoMqttClient - WiFi Simple Sender

  This example connects to a MQTT broker and publishes a message to
  a topic once a second.

  The circuit:
  - Arduino MKR 1000, MKR 1010 or Uno WiFi Rev2 board

  This example code is in the public domain.
*/

#include <ArduinoMqttClient.h>
#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)

// To connect with SSL/TLS:
// 1) Change WiFiClient to WiFiSSLClient.
// 2) Change port value from 1883 to 8883.
// 3) Change broker value to a server with a known SSL/TLS root certificate 
//    flashed in the WiFi module.

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.0.102";
int        port     = 1883;
const char topic[]  = "mqttx2emqx";

const long interval = 1000;
unsigned long previousMillis = 0;

int count = 0;

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
  }

  // attempt to connect to WiFi network:
  Serial.print("Attempting to connect to WPA SSID: ");
  Serial.println(ssid);
  while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
    // failed, retry
    Serial.print(".");
    delay(5000);
  }

  Serial.println("You're connected to the network");
  Serial.println(ssid);
  printWifiStatus();
  Serial.println();

  // You can provide a unique client ID, if not set the library uses Arduino-millis()
  // Each client must have a unique client ID
   mqttClient.setId("clientIdmurong");

  // You can provide a username and password for authentication
//   mqttClient.setUsernamePassword("arduinoUnoBoard", "arduinoUnoBoard");
  mqttClient.setUsernamePassword("Sensorhub", "sensorhub");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);


while (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    delay(100);
  }


  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
}

void loop() {
  // call poll() regularly to allow the library to send MQTT keep alives which
  // avoids being disconnected by the broker
  mqttClient.poll();

  // to avoid having delays in loop, we'll use the strategy from BlinkWithoutDelay
  // see: File -> Examples -> 02.Digital -> BlinkWithoutDelay for more info
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= interval) {
    // save the last time a message was sent
    previousMillis = currentMillis;

    Serial.print("Sending message to topic: ");
    Serial.println(topic);
    Serial.print("hello ");
    Serial.println(count);

    // send message, the Print interface can be used to set the message contents
    mqttClient.beginMessage(topic);
    mqttClient.print("hello ");
    mqttClient.print(count);
    mqttClient.endMessage();

    Serial.println();

    count++;
  }
}

/* -------------------------------------------------------------------------- */
void printWifiStatus() {
/* -------------------------------------------------------------------------- */  
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

实物展示:

MqttTest

在UNO通过MQTT连接HA过程中,也遇到了无法连接到HA的问题。原因是HA虚拟机使用的是NAT网络模式,导致HA的IP地址与UNO不在一个网段,无法PING通。解决方案是使用桥接,并且指定好主机的物理无线网卡接口即可!

 

扩展任务二:通过外部SHT40温湿度传感器,上传温湿度到HA,通过HA面板显示数据

上面已经在HA里面把MQTT给调通了,接下来增加温湿度数据给HA。

 

添加HA实体,通过在MQTTX里面发送如下内容至topic:  

温度topic:

homeassistant/sensor/SHT40_TEMP/config

温度内容:

{
    "device_class":"temperature",
    "name":"Temperature",
    "state_topic":"homeassistant/SHT40/state",
    "unit_of_measurement":"°C",
    "value_template":"{{ value_json.temperature}}",
    "unique_id":"temp_HA101",
    "device":{
        "identifiers":[
            "SHT40"
        ],
        "name":"SHT40-TEMP_HUMI"
    }
}

 

湿度topic:

homeassistant/sensor/SHT40_HUMI/config

湿度内容:

{
    "device_class":"humidity",
    "name":"Humidity",
    "state_topic":"homeassistant/SHT40/state",
    "unit_of_measurement":"rH%",
    "value_template":"{{ value_json.humidity}}",
    "unique_id":"hum_HA101",
    "device":{
        "identifiers":[
            "SHT40"
        ],
        "name":"SHT40-TEMP_HUMI"
    }
}

刷新HA:

image.png  

 

接下来添加SHT40的库,这里选择Adafruit家的:

image.png  

#include "Adafruit_SHT4x.h"

接着初始化SHT40设备:

Serial.println("Adafruit SHT4x Init");
  if (! sht4.begin(&Wire1)) {
    Serial.println("Couldn't find SHT4x");
    while (1) delay(1);
  }
  Serial.println("Found SHT4x sensor");
  Serial.print("Serial number 0x");
  Serial.println(sht4.readSerial(), HEX);

  // You can have 3 different precisions, higher precision takes longer
  sht4.setPrecision(SHT4X_HIGH_PRECISION);
  switch (sht4.getPrecision()) {
     case SHT4X_HIGH_PRECISION: 
       Serial.println("High precision");
       break;
     case SHT4X_MED_PRECISION: 
       Serial.println("Med precision");
       break;
     case SHT4X_LOW_PRECISION: 
       Serial.println("Low precision");
       break;
  }

  // You can have 6 different heater settings
  // higher heat and longer times uses more power
  // and reads will take longer too!
  sht4.setHeater(SHT4X_NO_HEATER);
  switch (sht4.getHeater()) {
     case SHT4X_NO_HEATER: 
       Serial.println("No heater");
       break;
     case SHT4X_HIGH_HEATER_1S: 
       Serial.println("High heat for 1 second");
       break;
     case SHT4X_HIGH_HEATER_100MS: 
       Serial.println("High heat for 0.1 second");
       break;
     case SHT4X_MED_HEATER_1S: 
       Serial.println("Medium heat for 1 second");
       break;
     case SHT4X_MED_HEATER_100MS: 
       Serial.println("Medium heat for 0.1 second");
       break;
     case SHT4X_LOW_HEATER_1S: 
       Serial.println("Low heat for 1 second");
       break;
     case SHT4X_LOW_HEATER_100MS: 
       Serial.println("Low heat for 0.1 second");
       break;
  }

在MQTT发布数据包里面,把温湿度数据添加进去:

    // send message, the Print interface can be used to set the message contents
    mqttClient.beginMessage(topic);
    mqttClient.print("{\"humidity\": ");
    mqttClient.print(humidity.relative_humidity);
    mqttClient.print(", \"temperature\": ");
    mqttClient.print(temp.temperature);
    mqttClient.print("}");
    mqttClient.endMessage();

实物展示:

-进阶

 

总结:

这次参加FOLLOW ME活动,体验了HA与MQTT,把SHT40温湿度数据成功上传到了云端。收获很大。期待能够把HA再玩的熟练些,控制小灯,开关等。

 

代码汇总:

https://download.eeworld.com.cn/detail/%E6%85%95%E5%AE%B9%E9%9B%AA%E8%8A%B1/634522

FollowMeCode.zip (5.32 KB)
(下载次数: 3, 2024-9-26 11:19 上传)
本帖最后由 慕容雪花 于 2024-10-31 13:56 编辑

回复评论 (2)

这些任务完成真是不错,还有自己的讲解,赞

期待楼主能够把HA再玩的熟练些,控制小灯,开关等,再来继续分享

点赞  2024-9-28 07:56
引用: Jacktang 发表于 2024-9-28 07:56 这些任务完成真是不错,还有自己的讲解,赞 期待楼主能够把HA再玩的熟练些,控制小灯,开关等,再来继续 ...

感谢坛友分享,第一次用HA,网段与UNO不在一起,折腾了半天,掉了2跟头发

点赞  2024-9-28 09:10
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复