Aclicee 发表于 2024-10-8 23:46

【Follow me第二期】扩展任务 - LTR329+SHT40传感器的使用并上传数据到HA平台

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;扩展任务为连接外部的环境光或者温湿度传感器,采集环境数据,然后通过Arduino上传到智能家居HA平台。在完成先前任务的基础上,本任务的难度相对较低。关键在于掌握如何配置环境光传感器LTR-329和温湿度传感器SHT40,并访问它们采集的数据。一旦这些传感器被正确配置,我们便可以利用在进阶任务中学到的代码,将模拟传感器的数据采集和上传流程应用于实际的传感器,从而实现数据的实时上传。</p>

<p><u><strong>1. 环境光传感器LTR329的使用</strong></u></p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了实现环境光数据的采集,我们选用了<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Arduino平台已经提供了LTR-329传感器的库支持。通过Arduino IDE左侧的Library manager搜索<strong><span style="color:#d35400;">&ldquo;Adafruit LTR329 and LTR303&rdquo;</span></strong>,即可找到并安装对应的库。</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;安装库之后,我们可以在例程中查看库函数的具体使用方法。首先,我们需要在代码中包含<strong><span style="color:#d35400;">Adafruit_LTR329_LTR303.h</span></strong>头文件,并实例化传感器对象ltr。后面是一些配置的代码,比如确认连接、设置传感器增益、采样时间间隔等等,我们都暂时保持默认即可。</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在主循环中,我们通过调用<strong><span style="color:#d35400;">ltr.readBothChannels(visible_plus_ir, infrared)</span></strong>来获取传感器采集的参数。LTR-329传感器提供两个通道的数据:可见光与红外光的叠加值,以及单独的红外光值。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由于我们使用了Qwiic缆线连接,因此在代码开头需要包含<strong><span style="color:#d35400;">Arduino Wire.h</span></strong>头文件,并在初始化时确认缆线的连接可用。完整的代码如下:</p>

<pre>
<code>#include "Adafruit_LTR329_LTR303.h"
#include &lt;Wire.h&gt;

Adafruit_LTR329 ltr = Adafruit_LTR329();

void setup() {
Serial.begin(9600);
Serial.println("Adafruit LTR-329 advanced test");

if ( ! ltr.begin(&amp;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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;运行上述代码后,我们可以通过串口监视器观察到光照强度信息的输出。随着环境光线的变化,例如手动遮挡光源,示数也会相应变化。</p>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态的数据接收过程请参考随附的视频。</p>

<p><u><strong>2. 温湿度传感器SHT40的使用</strong></u></p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;有了环境光传感器的经验,温湿度传感器只需要如法炮制即可。与环境光传感器类似,我们可以通过Arduino的库来简化集成过程。首先,通过Arduino IDE的Library manager搜索并安装<strong><span style="color:#d35400;">&ldquo;Adafruit SHT4X&rdquo;</span></strong>库。这个库为SHT40传感器提供了封装好的接口。</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;打开其中的例程,其实现的过程和环境光传感器是一样的。我们可以在代码中包含<strong><span style="color:#d35400;">Adafruit_SHT4X.h</span></strong>头文件,并实例化一个SHT40传感器对象sht4。</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;主循环部分,主要是通过<strong><span style="color:#d35400;">sht4.getEvent(&amp;humidity, &amp;temp)</span></strong>来获取温湿度的读数,然后通过串口分别发送。同样,我们因为通过Qwiic缆线来连接开发板和传感器,包含对应的头文件并检查确认其连接即可,具体的代码如下:</p>

<pre>
<code>#include "Adafruit_SHT4x.h"
#include &lt;Wire.h&gt;

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(&amp;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(&amp;humidity, &amp;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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;运行上述代码后,我们可以通过串口监视器观察到温湿度信息的输出。随着环境温湿度的变化,示数也会相应变化。温度传感器的结果将和扩展任务一同展示。动态的数据接收过程请参考随附的视频。</p>

<div style="text-align: center;"></div>

<p><u><strong>3. 扩展任务(必做):通过外部传感器上传信息到HA,并通过HA面板显示数据</strong></u></p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在成功集成环境光传感器LTR-329和温湿度传感器SHT40之后,我们的目标是将这些传感器的数据上传至Home Assistant (HA) 平台,并在HA界面上显示这些数据。由于我们只有一条Qwiic缆线,我们将以温湿度传感器SHT40为例进行演示。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;我们删除了上个任务中打印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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然后我们在初始化完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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后初始化SHT4X模块,我们把全部配置参数都设成默认,然后合并成一个<strong><span style="color:#d35400;">SHT40_init()</span></strong>函数。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在主循环中,我们直接使用例程中的温湿度数据获取的函数,然后通过<strong><span style="color:#d35400;">Sensor.setValue()</span></strong>函数显示到HA界面上。具体代码如下:</p>

<pre>
<code>    sensors_event_t humidity, temp;
    sht4.getEvent(&amp;humidity, &amp;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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;最后完整的代码如下:</p>

<pre>
<code>#include &lt;WiFiS3.h&gt;
#include &lt;ArduinoHA.h&gt;
#include &lt;Wire.h&gt;

#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 &lt; 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) &gt; 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(&amp;humidity, &amp;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(&amp;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(&amp;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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;完成代码编写后,我们启动Docker Engine,打开HA和EMQX平台的容器,并将代码烧录到Arduino。测试结果显示,我们可以看到网络连接和MQTT连接的信息,并确认了SHT40传感器的连接。传感器开始通过串口向上位机发送温湿度信息(截图时我已经把连接线断开了,所以显示了未连接)。</p>

<div style="text-align: center;"></div>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当我们打开HA平台时,可以看到设备增加了新的传感器,并且更新了数据单位信息,数据也会随时间不断更新。动态的展示请参考随附的视频。</p>

<div style="text-align: center;"></div>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;至此我们完成了本次Follow me活动的全部任务,汇总帖和视频正在全力整合中。</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ca5798636437d85f40691a7ef6521192</p>
页: [1]
查看完整版本: 【Follow me第二期】扩展任务 - LTR329+SHT40传感器的使用并上传数据到HA平台