发帖
1 0 0

【BW21-CBV-Kit 开发套件测评】OLED蓝牙温湿度计与Home Assistant连接

无垠的广袤
论坛元老

25

主题

26

回帖

3060

积分

论坛元老

积分
3060
QQ
小安派·BW21-CBV-KIt 16 1 昨天 23:10

【BW21-CBV-Kit 开发套件测评】OLED蓝牙温湿度计与Home Assistant连接

本文介绍了安信可 BW21-CBV-Kit 开发套件实现 OLED 蓝牙温湿度计 并与 Home Assistant 智能家居平台连接的项目设计。

OLED蓝牙温湿度计

设计思路

基于前面关于 蓝牙温湿度计OLED 显示 的测试,进一步扩展,将两种功能融合,实现 OLED 实时显示的蓝牙温湿度计,使之更贴近产品级的应用。

硬件连接

OLED_SCL -> 12

OLED_SDA -> 13

DHT11_DATA -> 8

示意图

dht11_oled_connect.jpg

此外,需要手机安装 Bluefruit Connect 应用和 Home Assistant 应用,便于后续测试的实现。

代码

结合例程 Examples - AmebaWire - OLED_SSD1306Examples - AmebaBLE - DHT_over_BLEUart ,实现OLED蓝牙温湿度计。

#include "BLEDevice.h"
#include "DHT.h"
/* OLED */
#include <Wire.h>
#include <Adafruit_OLED_libraries/Adafruit_GFX.h>
#include <Adafruit_OLED_libraries/Adafruit_SSD1306.h>
​
#define SCREEN_WIDTH  128    // OLED display width, in pixels
#define SCREEN_HEIGHT 64     // OLED display height, in pixels
#define OLED_RESET     -1      // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C    ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
​
#define UART_SERVICE_UUID      "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
​
#define STRING_BUF_SIZE 100
​
// The digital pin we're connected to.
#define DHTPIN 8
​
// Uncomment whatever type you're using!
#define DHTTYPE DHT11    // DHT 11
// #define DHTTYPE DHT22   // DHT 22 (AM2302), AM2321
// #define DHTTYPE DHT21   // DHT 21 (AM2301)
​
DHT dht(DHTPIN, DHTTYPE);
​
BLEService UartService(UART_SERVICE_UUID);
BLECharacteristic Rx(CHARACTERISTIC_UUID_RX);
BLECharacteristic Tx(CHARACTERISTIC_UUID_TX);
BLEAdvertData advdata;
BLEAdvertData scndata;
bool notify = false;
​
void writeCB(BLECharacteristic* chr, uint8_t connID)
{
    printf("Characteristic %s write by connection %d :\n", chr->getUUID().str(), connID);
    if (chr->getDataLen() > 0) {
        Serial.print("Received string: ");
        Serial.print(chr->readString());
        Serial.println();
    }
}
​
void notifCB(BLECharacteristic* chr, uint8_t connID, uint16_t cccd)
{
    if (cccd & GATT_CLIENT_CHAR_CONFIG_NOTIFY) {
        printf("Notifications enabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        notify = true;
    } else {
        printf("Notifications disabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        notify = false;
    }
}
​
void setup()
{
    Serial.begin(115200);
​
    advdata.addFlags();
    advdata.addCompleteName("AMEBA_BLE_DEV");
    scndata.addCompleteServices(BLEUUID(UART_SERVICE_UUID));
​
    Rx.setWriteProperty(true);
    Rx.setWritePermissions(GATT_PERM_WRITE);
    Rx.setWriteCallback(writeCB);
    Rx.setBufferLen(STRING_BUF_SIZE);
    Tx.setReadProperty(true);
    Tx.setReadPermissions(GATT_PERM_READ);
    Tx.setNotifyProperty(true);
    Tx.setCCCDCallback(notifCB);
    Tx.setBufferLen(STRING_BUF_SIZE);
​
    UartService.addCharacteristic(Rx);
    UartService.addCharacteristic(Tx);
​
    BLE.init();
    BLE.configAdvert()->setAdvData(advdata);
    BLE.configAdvert()->setScanRspData(scndata);
    BLE.configServer(1);
    BLE.addService(UartService);
​
    BLE.beginPeripheral();
    dht.begin();
​
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
        Serial.println(F("SSD1306 allocation failed"));
        for (;;)
            ;    // Don't proceed, loop forever
    }
    delay(1000);
    display.clearDisplay();
    display.setTextColor(WHITE);
}
​
void loop()
{
    float h = dht.readHumidity();
    float t = dht.readTemperature();
​
    if (isnan(h) || isnan(t)) {
        Serial.println("Failed to read from DHT sensor!");
        return;
        // display error information
        display.clearDisplay();
        display.setTextSize(1);
        display.setCursor(0,0);
        display.print("Failed to read from DHT sensor!");
        display.display();
    }
​
    String msg = ("Humidity: " + String((int)h) + "%\t" + "Temperature: " + String((int)t) + "°C\n");
​
    Tx.writeString(msg);
    if (BLE.connected(0) && notify) {
        Tx.notify(0);
    }
​
    // clear display
    display.clearDisplay();
    // display temperature
    display.setTextSize(1);
    display.setCursor(0,0);
    display.print("Temperature: ");
    display.setTextSize(2);
    display.setCursor(0,17);
    display.print(String(t,2));
    display.print(" ");
    display.setTextSize(1);
    display.cp437(true);
    display.write(167);
    display.setTextSize(2);
    display.print("C");
​
    // display humidity
    display.setTextSize(1);
    display.setCursor(0, 35);
    display.print("Humidity: ");
    display.setTextSize(2);
    display.setCursor(0, 45);
    display.print(String(h,2));
    display.print(" %"); 
      
    display.display(); 
    delay(2000);
}

编译并上传固件,复位运行程序;

手机打开 Bluefruit Connect 应用,连接 AMEBA_BLE_DEV 蓝牙设备,选择 UART,即可接收蓝牙串口发送的数据。

效果

蓝牙串口发送温湿度数据,同时 OLED 显示温湿度

ble_dht11_oled.jpg

动态演示

ble_dht11_oled.gif

Home Assistant 连接

在例程 Examples - AmebaWire - OLED_SSD1306Examples - AmebaBLE - DHT_over_BLEUart 实现 OLED 蓝牙温湿度计的基础上,配合 Bluefruit Connect 应用的蓝牙串口 MQTT 传输功能,进一步实现 Home Assistant (HA)智能家居平台温湿度监测。

HA 环境搭建详见之前的帖子:蓝牙温湿度计 DIYHome Assistant 连接 .

设计思路

引入 <ArduinoJson.h> 库,实现温度和湿度数据的标准 JSON 格式转换。

Json

  • JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
  • JSON 是轻量级的文本数据交换格式

举例:

{"age":30}

最终蓝牙串口输出效果如下

{"temperature": "28.80","humidity": "44.00"}

代码

相较之前的代码,引入 <ArduinoJson.h> 库,并在 loop 中创建 JSON 装载即可

#include "BLEDevice.h"
#include "DHT.h"
/* OLED */
#include <Wire.h>
#include <Adafruit_OLED_libraries/Adafruit_GFX.h>
#include <Adafruit_OLED_libraries/Adafruit_SSD1306.h>
#include <ArduinoJson.h>
​
#define SCREEN_WIDTH  128    // OLED display width, in pixels
#define SCREEN_HEIGHT 64     // OLED display height, in pixels
#define OLED_RESET     -1      // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C    ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
​
#define UART_SERVICE_UUID      "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
​
#define STRING_BUF_SIZE 100
​
// The digital pin we're connected to.
#define DHTPIN 8
​
// Uncomment whatever type you're using!
#define DHTTYPE DHT11    // DHT 11
// #define DHTTYPE DHT22   // DHT 22 (AM2302), AM2321
// #define DHTTYPE DHT21   // DHT 21 (AM2301)
​
DHT dht(DHTPIN, DHTTYPE);
​
BLEService UartService(UART_SERVICE_UUID);
BLECharacteristic Rx(CHARACTERISTIC_UUID_RX);
BLECharacteristic Tx(CHARACTERISTIC_UUID_TX);
BLEAdvertData advdata;
BLEAdvertData scndata;
bool notify = false;
​
void writeCB(BLECharacteristic* chr, uint8_t connID)
{
    printf("Characteristic %s write by connection %d :\n", chr->getUUID().str(), connID);
    if (chr->getDataLen() > 0) {
        Serial.print("Received string: ");
        Serial.print(chr->readString());
        Serial.println();
    }
}
​
void notifCB(BLECharacteristic* chr, uint8_t connID, uint16_t cccd)
{
    if (cccd & GATT_CLIENT_CHAR_CONFIG_NOTIFY) {
        printf("Notifications enabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        notify = true;
    } else {
        printf("Notifications disabled on Characteristic %s for connection %d \n", chr->getUUID().str(), connID);
        notify = false;
    }
}
​
void setup()
{
    Serial.begin(115200);
​
    advdata.addFlags();
    advdata.addCompleteName("AMEBA_BLE_DEV");
    scndata.addCompleteServices(BLEUUID(UART_SERVICE_UUID));
​
    Rx.setWriteProperty(true);
    Rx.setWritePermissions(GATT_PERM_WRITE);
    Rx.setWriteCallback(writeCB);
    Rx.setBufferLen(STRING_BUF_SIZE);
    Tx.setReadProperty(true);
    Tx.setReadPermissions(GATT_PERM_READ);
    Tx.setNotifyProperty(true);
    Tx.setCCCDCallback(notifCB);
    Tx.setBufferLen(STRING_BUF_SIZE);
​
    UartService.addCharacteristic(Rx);
    UartService.addCharacteristic(Tx);
​
    BLE.init();
    BLE.configAdvert()->setAdvData(advdata);
    BLE.configAdvert()->setScanRspData(scndata);
    BLE.configServer(1);
    BLE.addService(UartService);
​
    BLE.beginPeripheral();
    dht.begin();
​
    // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
        Serial.println(F("SSD1306 allocation failed"));
        for (;;)
            ;    // Don't proceed, loop forever
    }
    delay(1000);
    display.clearDisplay();
    display.setTextColor(WHITE);
}
​
void loop()
{
    float h = dht.readHumidity();
    float t = dht.readTemperature();
​
    if (isnan(h) || isnan(t)) {
        Serial.println("Failed to read from DHT sensor!");
        return;
    }
​
    // Create JSON payload
    DynamicJsonDocument doc(256);
    doc["temperature"] = String(t,2);
    doc["humidity"] = String(h,2);
​
    char json_string[256];
    serializeJson(doc, json_string);
  
    Serial.print("Publishing: ");
    Serial.println(json_string);
​
    // define message: {"temperature":t,"humidity":h}
    String msg = (json_string);
​
    Tx.writeString(msg);
    if (BLE.connected(0) && notify) {
        Tx.notify(0);
    }
​
    // clear display
    display.clearDisplay();
    // display temperature
    display.setTextSize(1);
    display.setCursor(0,0);
    display.print("Temperature: ");
    display.setTextSize(2);
    display.setCursor(0,17);
    display.print(String(t,2));
    display.print(" ");
    display.setTextSize(1);
    display.cp437(true);
    display.write(167);
    display.setTextSize(2);
    display.print("C");
​
    // display humidity
    display.setTextSize(1);
    display.setCursor(0, 35);
    display.print("Humidity: ");
    display.setTextSize(2);
    display.setCursor(0, 45);
    display.print(String(h,2));
    display.print(" %"); 
      
    display.display(); 
    delay(2000);
}

此时连接 MQTTX 输出文本为标准 JSON 格式

MQTT_BLE_DHT11.jpg

YAML 代码

进入 HomeAssistant 配置文件夹,编辑 configuration.yaml 文件,添加如下代码

mqtt:
  sensor:
    - name: "DHT/Temperature"
      state_topic: "dht11"
      suggested_display_precision: 1
      unit_of_measurement: "C"
      value_template: "{{ value_json.temperature }}"
    - name: "DHT/Humidity"
      state_topic: "dht11"
      suggested_display_precision: 1
      unit_of_measurement: "%"
      value_template: "{{ value_json.humidity }}"

打开 HA 主页面,选择左侧标签栏中的 开发者工具 - 点击 所有 YAML 配置 加载修改后的配置文件,刷新网页,即可在 概览 界面看到新增的传感器。

ble_dht11_oled_ha_app.jpg

同时可在 HA 手机应用上获取传感器数据、历史变化曲线,以及 OLED 实时显示。

ha_curve_ble_dht11_oled.jpg

分析

该方案相较于 开发板 WiFi 直连实现 MQTT 数据传输 的方案的优点如下

  • 通过手机应用可以随时切换使用场景,不会受制于 WiFi 网络覆盖范围的限制;
  • MQTT 网络上传仅依赖于手机应用转发所需的网络;
  • 便于切换蓝牙从机设备的连接和查看(其他手机也可扫描蓝牙并连接)

总结

本文介绍了安信可 BW21-CBV-Kit 开发套件实现 OLED 蓝牙温湿度计 并与 Home Assistant 智能家居平台连接的项目设计,为小安派系列相关产品的物联网应用提供了参考。

──── 0人觉得很赞 ────

使用道具 举报

昨天 23:22
很棒,点赞!
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28574 个
  • 话题数: 40659 篇