御坂10032号 发表于 2024-10-18 01:37

【2024 DigiKey 创意大赛】ESP-32C6- 室内数据集成 + 自动化补光

本帖最后由 御坂10032号 于 2024-10-20 15:40 编辑

<p><strong><span style="font-size:22px;">简介</span></strong></p>

<p>&nbsp;</p>

<p>本章节主要在上一个章节的代码上修改使其支持BH1750, 然后将数据集成到HA并且配置HA实现自动化操作,自动补光等。</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:22px;">正文</span></strong></p>

<p>&nbsp;</p>

<p>在上个章节中我们实现了使用C6读取AHT10并且将数据上报到MQTT,由于AHT10和BH1750都是使用IIC通讯, 因为我们可以将SCL和SDA接到这两个传感器上(接相同的SCL和SDA)然后通过I2C的Address 来选择和哪个传感器进行通讯。虽然也可以使用其他的IIC或者是使用软件模拟的方式来模拟IIC时序,但是为了方便我们直接采用之前的IIC总线。</p>

<p> &nbsp;</p>

<p>那么为了读取BH1750,我们需要首先在Arduino IDE中来添加BH1750的库</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>在安装完库文件之后,我们需要在上一章节的代码中进行修改,使其支持BH1750的数据上报。</p>

<p>&nbsp;</p>

<p>代码如下:</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">#include &lt;Wire.h&gt;
#include &lt;Adafruit_AHTX0.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;ArduinoMqttClient.h&gt;
#include &lt;Arduino_JSON.h&gt;
#include &lt;BH1750.h&gt;// 添加 BH1750 库

const char *ssid = "ImmortalWrt";
const char *password = "mazha1997";

#define SDA_PIN 21// 定义 SDA 引脚
#define SCL_PIN 22// 定义 SCL 引脚
#define CONTROL_PIN 4// 定义控制引脚,用于输出高低电平

Adafruit_AHTX0 aht;
BH1750 lightMeter;// 创建 BH1750 实例

WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);

const char broker[] = "192.168.1.142";
int port = 1883;
const char switchTopic[] = "switch";   // 主题1
const char sensorTopic[] = "sensor";   // 主题2

void setup() {
Serial.begin(115200);// 初始化串口,用于调试
pinMode(CONTROL_PIN, OUTPUT);// 设置控制引脚为输出模式
digitalWrite(CONTROL_PIN, LOW);// 初始状态设为低电平

// 初始化 I2C,使用自定义引脚
Wire.begin(SDA_PIN, SCL_PIN);

if (!aht.begin()) {
    Serial.println("Could not find AHT? Check wiring");
    while (1) delay(10);
}
Serial.println("AHT10 or AHT20 found");

if (!lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &amp;Wire)) {
    Serial.println("Error initializing BH1750. Check wiring or I2C address.");
    while (1) delay(10);
}
Serial.println("BH1750 initialized");

WiFi.begin(ssid, password);

int tryDelay = 500;
int numberOfTries = 20;

// Wait for the WiFi event
while (true) {
    switch (WiFi.status()) {
      case WL_NO_SSID_AVAIL: Serial.println(" SSID not found"); break;
      case WL_CONNECT_FAILED:
      Serial.println(" Failed - WiFi not connected! Reason: ");
      return;
      break;
      case WL_CONNECTION_LOST: Serial.println(" Connection was lost"); break;
      case WL_DISCONNECTED: Serial.println(" WiFi is disconnected"); break;
      case WL_CONNECTED:
      Serial.println(" WiFi is connected!");
      Serial.print(" IP address: ");
      Serial.println(WiFi.localIP());
      Serial.print("Attempting to connect to the MQTT broker: ");
      Serial.println(broker);

      mqttClient.setUsernamePassword("root", "mazha1997");
      if (!mqttClient.connect(broker, port)) {
          Serial.print("MQTT connection failed! Error code = ");
          Serial.println(mqttClient.connectError());
          while (1);
      }

      Serial.println("You're connected to the MQTT broker!");
      mqttClient.onMessage(onMqttMessage);// 设置消息接收回调

      Serial.print("Subscribing to topic: ");
      Serial.println(switchTopic);
      mqttClient.subscribe(switchTopic);// 订阅开关主题

      return;
      default:
      Serial.print(" WiFi Status: ");
      Serial.println(WiFi.status());
      break;
    }
    delay(tryDelay);
    if (numberOfTries &lt;= 0) {
      Serial.println(" Failed to connect to WiFi!");
      WiFi.disconnect();
      return;
    } else {
      numberOfTries--;
    }
}
}

void loop() {
// 保证处理 MQTT 消息
mqttClient.poll();

// 获取 AHT10/20 传感器数据
sensors_event_t humidity, temp;
aht.getEvent(&amp;humidity, &amp;temp);// 获取温度和湿度数据

// 获取 BH1750 光照强度数据
float lux = lightMeter.readLightLevel();
Serial.print("Light: ");
Serial.print(lux);
Serial.println(" lx");

// 创建JSON对象来存储数据
JSONVar sensorData;
sensorData["temperature"] = String(temp.temperature, 2);// 保留两位小数
sensorData["humidity"] = String(humidity.relative_humidity, 2);// 保留两位小数
sensorData["lux"] = String(lux, 2);// 保留两位小数的光照强度

// 将JSON数据转换为字符串并发布到"sensor"主题
String payload = JSON.stringify(sensorData);
mqttClient.beginMessage(sensorTopic);
mqttClient.print(payload);
mqttClient.endMessage();

delay(1000);// 每秒刷新一次
}

// MQTT消息接收回调函数
void onMqttMessage(int messageSize) {
// 获取当前消息的主题
String topic = mqttClient.messageTopic();
Serial.print("Received a message with topic '");
Serial.print(topic);
Serial.print("', length ");
Serial.print(messageSize);
Serial.println(" bytes:");

String message = "";
while (mqttClient.available()) {
    message += (char)mqttClient.read();
}
Serial.println("Message content: " + message);

// 根据不同的主题处理消息
if (topic == switchTopic) {
    Serial.println("Message from topic: switchTopic");

    // 将接收到的消息转换为 JSON
    JSONVar parsedMessage = JSON.parse(message);

    // 检查解析是否成功
    if (JSON.typeof(parsedMessage) == "undefined") {
      Serial.println("Parsing input failed!");
      return;
    }

    // 获取 status 字段
    String status = (const char*)parsedMessage["status"];

    if (status == "ON") {
      digitalWrite(CONTROL_PIN, HIGH);// 设置 IO4 输出高电平
      Serial.println("Switch turned ON, IO4 set to HIGH");
    } else if (status == "OFF") {
      digitalWrite(CONTROL_PIN, LOW);// 设置 IO4 输出低电平
      Serial.println("Switch turned OFF, IO4 set to LOW");
    } else {
      Serial.println("Unknown status value");
    }
}
}
</code></pre>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>这里关于BH1750的代码主要的部分在于以下代码,其他的和上一个章节相同</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">BH1750 lightMeter;// 创建 BH1750 实例

//初始化BH1750
if (!lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x23, &amp;Wire)) {
    Serial.println("Error initializing BH1750. Check wiring or I2C address.");
    while (1) delay(10);
}

               
// 获取 BH1750 光照强度数据
float lux = lightMeter.readLightLevel();
Serial.print("Light: ");
Serial.print(lux);
Serial.println(" lx");
</code></pre>

<p>&nbsp;</p>

<p>上述代码分别初始化了 BH1750, 启动IIC通讯, 以及读取BH1750的数据。 之后便将数据整合到了之前的JSON object里然后上传到MQTT</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">// 创建JSON对象来存储数据
JSONVar sensorData;
sensorData["temperature"] = String(temp.temperature, 2);// 保留两位小数
sensorData["humidity"] = String(humidity.relative_humidity, 2);// 保留两位小数
sensorData["lux"] = String(lux, 2);// 保留两位小数的光照强度

// 将JSON数据转换为字符串并发布到"sensor"主题
String payload = JSON.stringify(sensorData);
mqttClient.beginMessage(sensorTopic);
mqttClient.print(payload);
mqttClient.endMessage();</code></pre>

<p>&nbsp;</p>

<p><strong><span style="font-size:22px;">数据集成和自动化配置</span></strong></p>

<p>&nbsp;</p>

<p>通常我比较喜欢晚上来写代码,但是晚上的时候虽然晚上打开了灯光,但是桌面的光照强度还是太弱了,十分累眼睛。 前一段时间买了一个可调光的台灯(20元)。 然后我直接把它拆了,留下了里面的LED灯板。 我把它通过和单片机相连,然后使用继电器控制, 当室内的环境光LUX低于一定强度的时候, 使其打开台灯进行补光。 上述的代码工作我们已经完成了,那么接下来就是数据的集成和自动化配置。</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>首先使用docker exec -it 命令进入 HA容器, 使用vi 编辑 configuration.yml 加入以下内容配置集成</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">mqtt:
sensor:
    - name: "Temperature"
      unique_id: "sensor_temp_01"
      state_topic: "sensor"
      suggested_display_precision: 1
      unit_of_measurement: "..C"
      value_template: "{{ value_json.temperature }}"
    - name: "Humidity"
      unique_id: "sensor_humidity_02"
      state_topic: "sensor"
      unit_of_measurement: "%"
      value_template: "{{ value_json.humidity }}"
    - name: "Illuminance"
      unique_id: "sensor_illuminance"
      state_topic: "sensor"
      unit_of_measurement: "lx"
      value_template: "{{ value_json.lux }}"</code></pre>

<p>&nbsp;</p>

<p>然后在开发者工具中检查和重载配置。</p>

<p>&nbsp;</p>

<p></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>之后便可以在默认的dashboard中找到配置的传感器信息。</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p>我们再额外配置一下继电器的控制</p>

<p>&nbsp;</p>

<pre>
<code class="language-cpp">switch:
    - name: "Light Switch"
      unique_id: "switch_light_01"
      state_topic: "switch/status"
      command_topic: "switch"
      payload_on: "ON"
      payload_off: "OFF"
      state_on: "ON"
      state_off: "OFF"
      qos: 1
      retain: true</code></pre>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>此时配置完成。</p>

<p>&nbsp;</p>

<p><strong><span style="font-size:22px;">自动化控制</span></strong></p>

<p>&nbsp;</p>

<p>我们希望在光照强度较低的时候自动开启补光。那么在HA中只用做一下的配置即可。</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>上述配置了关灯条件, 即光照强度低于100, 就执行下述操作</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>同样的道理我们配置一个开灯的操作。</p>

<p>&nbsp;</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>此时我们配置完成,让我们来看下现象。</p>

<p>&nbsp;</p>

<p>4a780256ec73197cbf6ecb674786e658<br />
&nbsp;</p>

<p>&nbsp;</p>
页: [1]
查看完整版本: 【2024 DigiKey 创意大赛】ESP-32C6- 室内数据集成 + 自动化补光