【Follow me第二期】扩展任务 - LTR329+SHT40传感器的使用并上传数据到HA平台
<p> 扩展任务为连接外部的环境光或者温湿度传感器,采集环境数据,然后通过Arduino上传到智能家居HA平台。在完成先前任务的基础上,本任务的难度相对较低。关键在于掌握如何配置环境光传感器LTR-329和温湿度传感器SHT40,并访问它们采集的数据。一旦这些传感器被正确配置,我们便可以利用在进阶任务中学到的代码,将模拟传感器的数据采集和上传流程应用于实际的传感器,从而实现数据的实时上传。</p><p><u><strong>1. 环境光传感器LTR329的使用</strong></u></p>
<p> 为了实现环境光数据的采集,我们选用了<strong><span style="color:#d35400;">LTR-329</span></strong>环境光传感器。关于该传感器的具体参数和管脚配置,可以参考官方提供的规格书【<a href="https://mm.digikey.com/Volume0/opasdata/d220001/medias/docus/5062/5591_Web.pdf" rev="en_rl_none">5591.pdf (digikey.com)</a>】。为了简化连接过程,我们采用了Qwiic缆线连接方式,将传感器与Arduino开发板相连。</p>
<p> Arduino平台已经提供了LTR-329传感器的库支持。通过Arduino IDE左侧的Library manager搜索<strong><span style="color:#d35400;">“Adafruit LTR329 and LTR303”</span></strong>,即可找到并安装对应的库。</p>
<div style="text-align: center;"></div>
<p> 安装库之后,我们可以在例程中查看库函数的具体使用方法。首先,我们需要在代码中包含<strong><span style="color:#d35400;">Adafruit_LTR329_LTR303.h</span></strong>头文件,并实例化传感器对象ltr。后面是一些配置的代码,比如确认连接、设置传感器增益、采样时间间隔等等,我们都暂时保持默认即可。</p>
<div style="text-align: center;"></div>
<p> 在主循环中,我们通过调用<strong><span style="color:#d35400;">ltr.readBothChannels(visible_plus_ir, infrared)</span></strong>来获取传感器采集的参数。LTR-329传感器提供两个通道的数据:可见光与红外光的叠加值,以及单独的红外光值。</p>
<p> 由于我们使用了Qwiic缆线连接,因此在代码开头需要包含<strong><span style="color:#d35400;">Arduino Wire.h</span></strong>头文件,并在初始化时确认缆线的连接可用。完整的代码如下:</p>
<pre>
<code>#include "Adafruit_LTR329_LTR303.h"
#include <Wire.h>
Adafruit_LTR329 ltr = Adafruit_LTR329();
void setup() {
Serial.begin(9600);
Serial.println("Adafruit LTR-329 advanced test");
if ( ! ltr.begin(&Wire1) ) {
Serial.println("Couldn't find LTR sensor!");
while (1) delay(10);
}
Serial.println("Found LTR sensor!");
ltr.setGain(LTR3XX_GAIN_2);
Serial.print("Gain : ");
switch (ltr.getGain()) {
case LTR3XX_GAIN_1: Serial.println(1); break;
case LTR3XX_GAIN_2: Serial.println(2); break;
case LTR3XX_GAIN_4: Serial.println(4); break;
case LTR3XX_GAIN_8: Serial.println(8); break;
case LTR3XX_GAIN_48: Serial.println(48); break;
case LTR3XX_GAIN_96: Serial.println(96); break;
}
ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);
Serial.print("Integration Time (ms): ");
switch (ltr.getIntegrationTime()) {
case LTR3XX_INTEGTIME_50: Serial.println(50); break;
case LTR3XX_INTEGTIME_100: Serial.println(100); break;
case LTR3XX_INTEGTIME_150: Serial.println(150); break;
case LTR3XX_INTEGTIME_200: Serial.println(200); break;
case LTR3XX_INTEGTIME_250: Serial.println(250); break;
case LTR3XX_INTEGTIME_300: Serial.println(300); break;
case LTR3XX_INTEGTIME_350: Serial.println(350); break;
case LTR3XX_INTEGTIME_400: Serial.println(400); break;
}
ltr.setMeasurementRate(LTR3XX_MEASRATE_200);
Serial.print("Measurement Rate (ms): ");
switch (ltr.getMeasurementRate()) {
case LTR3XX_MEASRATE_50: Serial.println(50); break;
case LTR3XX_MEASRATE_100: Serial.println(100); break;
case LTR3XX_MEASRATE_200: Serial.println(200); break;
case LTR3XX_MEASRATE_500: Serial.println(500); break;
case LTR3XX_MEASRATE_1000: Serial.println(1000); break;
case LTR3XX_MEASRATE_2000: Serial.println(2000); break;
}
}
void loop() {
bool valid;
uint16_t visible_plus_ir, infrared;
if (ltr.newDataAvailable()) {
valid = ltr.readBothChannels(visible_plus_ir, infrared);
if (valid) {
Serial.print("CH0 Visible + IR: ");
Serial.print(visible_plus_ir);
Serial.print("\t\tCH1 Infrared: ");
Serial.println(infrared);
}
}
delay(100);
}</code></pre>
<p> 运行上述代码后,我们可以通过串口监视器观察到光照强度信息的输出。随着环境光线的变化,例如手动遮挡光源,示数也会相应变化。</p>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<p> 动态的数据接收过程请参考随附的视频。</p>
<p><u><strong>2. 温湿度传感器SHT40的使用</strong></u></p>
<p> 有了环境光传感器的经验,温湿度传感器只需要如法炮制即可。与环境光传感器类似,我们可以通过Arduino的库来简化集成过程。首先,通过Arduino IDE的Library manager搜索并安装<strong><span style="color:#d35400;">“Adafruit SHT4X”</span></strong>库。这个库为SHT40传感器提供了封装好的接口。</p>
<div style="text-align: center;"></div>
<p> 打开其中的例程,其实现的过程和环境光传感器是一样的。我们可以在代码中包含<strong><span style="color:#d35400;">Adafruit_SHT4X.h</span></strong>头文件,并实例化一个SHT40传感器对象sht4。</p>
<div style="text-align: center;"></div>
<p> 主循环部分,主要是通过<strong><span style="color:#d35400;">sht4.getEvent(&humidity, &temp)</span></strong>来获取温湿度的读数,然后通过串口分别发送。同样,我们因为通过Qwiic缆线来连接开发板和传感器,包含对应的头文件并检查确认其连接即可,具体的代码如下:</p>
<pre>
<code>#include "Adafruit_SHT4x.h"
#include <Wire.h>
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
void setup() {
Serial.begin(9600);
while (!Serial)
delay(10); // will pause Zero, Leonardo, etc until serial console opens
Serial.println("Adafruit SHT4x test");
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;
}
}
void loop() {
sensors_event_t humidity, temp;
uint32_t timestamp = millis();
sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data
timestamp = millis() - timestamp;
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
Serial.print("Read duration (ms): ");
Serial.println(timestamp);
delay(1000);
}
</code></pre>
<p> 运行上述代码后,我们可以通过串口监视器观察到温湿度信息的输出。随着环境温湿度的变化,示数也会相应变化。温度传感器的结果将和扩展任务一同展示。动态的数据接收过程请参考随附的视频。</p>
<div style="text-align: center;"></div>
<p><u><strong>3. 扩展任务(必做):通过外部传感器上传信息到HA,并通过HA面板显示数据</strong></u></p>
<p> 在成功集成环境光传感器LTR-329和温湿度传感器SHT40之后,我们的目标是将这些传感器的数据上传至Home Assistant (HA) 平台,并在HA界面上显示这些数据。由于我们只有一条Qwiic缆线,我们将以温湿度传感器SHT40为例进行演示。</p>
<p> 我们删除了上个任务中打印wifi信息的相关函数,因为我们暂时不需要显示这些,来精简一下代码。我们包含了所有必要的头文件,并开始配置HA平台。我们将新添加的传感器实例化为模拟信号传感器,具体代码如下:</p>
<pre>
<code>HASensorNumber analogSensor("AnalogInput", HASensorNumber::PrecisionP1);
HASensorNumber uptimeSensor("Uptime");
HASensorNumber TempSensor("Temperature", HASensorNumber::PrecisionP2);
HASensorNumber HumidSensor("Humid", HASensorNumber::PrecisionP3);
//HASensorNumber LightSensor("Light", HASensorNumber::PrecisionP2);
HAButton buttonA("myButtonA");
HAButton buttonB("myButtonB");</code></pre>
<p> 然后我们在初始化完wifi模块和MQTT的连接以后,具体方法参考上一则报告【<a href="https://bbs.eeworld.com.cn/thread-1295429-1-1.html" rev="en_rl_none">【Follow me第二期】进阶任务 - WiFi+MQTT协议连接智能家居HA平台 - DigiKey得捷技术专区 - 电子工程世界-论坛 (eeworld.com.cn)</a>】,给HA界面上各传感器的显示增加更多细节,包括进行命名的区分以及增加具体的单位,代码如下:</p>
<pre>
<code>analogSensor.setName("Analog voltage");
analogSensor.setUnitOfMeasurement("V");
uptimeSensor.setName("Update Time");
uptimeSensor.setUnitOfMeasurement("s");
TempSensor.setName("Temperature");
TempSensor.setUnitOfMeasurement("degrees C");
HumidSensor.setName("Humidity");
HumidSensor.setUnitOfMeasurement("% rH");
//LightSensor.setUnitOfMeasurement("lkx");</code></pre>
<p> 最后初始化SHT4X模块,我们把全部配置参数都设成默认,然后合并成一个<strong><span style="color:#d35400;">SHT40_init()</span></strong>函数。</p>
<p> 在主循环中,我们直接使用例程中的温湿度数据获取的函数,然后通过<strong><span style="color:#d35400;">Sensor.setValue()</span></strong>函数显示到HA界面上。具体代码如下:</p>
<pre>
<code> sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println("degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
TempSensor.setValue(temp.temperature);
HumidSensor.setValue(humidity.relative_humidity);</code></pre>
<p> 最后完整的代码如下:</p>
<pre>
<code>#include <WiFiS3.h>
#include <ArduinoHA.h>
#include <Wire.h>
#include "arduino_secrets.h"
#include "analogWave.h"
#include "Adafruit_SHT4x.h"
#include "Adafruit_LTR329_LTR303.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("AnalogInput", HASensorNumber::PrecisionP1);
HASensorNumber uptimeSensor("Uptime");
HASensorNumber TempSensor("Temperature", HASensorNumber::PrecisionP2);
HASensorNumber HumidSensor("Humid", HASensorNumber::PrecisionP3);
//HASensorNumber LightSensor("Light", HASensorNumber::PrecisionP2);
HAButton buttonA("myButtonA");
HAButton buttonB("myButtonB");
analogWave wave(DAC);
Adafruit_SHT4x sht4 = Adafruit_SHT4x();
Adafruit_LTR329 ltr = Adafruit_LTR329();
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");
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");
analogSensor.setName("Analog voltage");
analogSensor.setUnitOfMeasurement("V");
uptimeSensor.setName("Update Time");
uptimeSensor.setUnitOfMeasurement("s");
TempSensor.setName("Temperature");
TempSensor.setUnitOfMeasurement("degrees C");
HumidSensor.setName("Humidity");
HumidSensor.setUnitOfMeasurement("% rH");
//LightSensor.setUnitOfMeasurement("lkx");
SHT40_init();
//LTR329_init();
}
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);
sensors_event_t humidity, temp;
sht4.getEvent(&humidity, &temp);
Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println("degrees C");
Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH");
TempSensor.setValue(temp.temperature);
HumidSensor.setValue(humidity.relative_humidity);
// bool valid;
// uint16_t visible_plus_ir, infrared;
// if (ltr.newDataAvailable()) {
// valid = ltr.readBothChannels(visible_plus_ir, infrared);
// if (valid) {
// Serial.print("CH0 Visible + IR: ");
// Serial.print(visible_plus_ir);
// Serial.print("\t\tCH1 Infrared: ");
// Serial.println(infrared);
// }
// LightSensor.setValue(visible_plus_ir);
// }
lastUpdateAt = millis();
}
}
void SHT40_init() {
Serial.println("Adafruit SHT4x test");
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);
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;
}
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;
}
}
void LTR329_init() {
Serial.println("Adafruit LTR-329 advanced test");
if ( ! ltr.begin(&Wire1) ) {
Serial.println("Couldn't find LTR sensor!");
while (1) delay(10);
}
Serial.println("Found LTR sensor!");
ltr.setGain(LTR3XX_GAIN_2);
Serial.print("Gain : ");
switch (ltr.getGain()) {
case LTR3XX_GAIN_1: Serial.println(1); break;
case LTR3XX_GAIN_2: Serial.println(2); break;
case LTR3XX_GAIN_4: Serial.println(4); break;
case LTR3XX_GAIN_8: Serial.println(8); break;
case LTR3XX_GAIN_48: Serial.println(48); break;
case LTR3XX_GAIN_96: Serial.println(96); break;
}
ltr.setIntegrationTime(LTR3XX_INTEGTIME_100);
Serial.print("Integration Time (ms): ");
switch (ltr.getIntegrationTime()) {
case LTR3XX_INTEGTIME_50: Serial.println(50); break;
case LTR3XX_INTEGTIME_100: Serial.println(100); break;
case LTR3XX_INTEGTIME_150: Serial.println(150); break;
case LTR3XX_INTEGTIME_200: Serial.println(200); break;
case LTR3XX_INTEGTIME_250: Serial.println(250); break;
case LTR3XX_INTEGTIME_300: Serial.println(300); break;
case LTR3XX_INTEGTIME_350: Serial.println(350); break;
case LTR3XX_INTEGTIME_400: Serial.println(400); break;
}
ltr.setMeasurementRate(LTR3XX_MEASRATE_200);
Serial.print("Measurement Rate (ms): ");
switch (ltr.getMeasurementRate()) {
case LTR3XX_MEASRATE_50: Serial.println(50); break;
case LTR3XX_MEASRATE_100: Serial.println(100); break;
case LTR3XX_MEASRATE_200: Serial.println(200); break;
case LTR3XX_MEASRATE_500: Serial.println(500); break;
case LTR3XX_MEASRATE_1000: Serial.println(1000); break;
case LTR3XX_MEASRATE_2000: Serial.println(2000); break;
}
}</code></pre>
<p> 完成代码编写后,我们启动Docker Engine,打开HA和EMQX平台的容器,并将代码烧录到Arduino。测试结果显示,我们可以看到网络连接和MQTT连接的信息,并确认了SHT40传感器的连接。传感器开始通过串口向上位机发送温湿度信息(截图时我已经把连接线断开了,所以显示了未连接)。</p>
<div style="text-align: center;"></div>
<div style="text-align: center;"></div>
<p> 当我们打开HA平台时,可以看到设备增加了新的传感器,并且更新了数据单位信息,数据也会随时间不断更新。动态的展示请参考随附的视频。</p>
<div style="text-align: center;"></div>
<p> 至此我们完成了本次Follow me活动的全部任务,汇总帖和视频正在全力整合中。</p>
<p> ca5798636437d85f40691a7ef6521192</p>
页:
[1]