制霸 IoT 30Day! Day 21 藍芽硬體連結
藍芽硬體連結
上一篇我們介紹硬體的藍芽開發介紹,今天介紹與其他藍芽做資料讀取。
ESP32 藍芽 scan
直接上代碼,各位可以看到並不會太多複雜的。
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 30; //In seconds
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
  void onResult(BLEAdvertisedDevice advertisedDevice)
  {
    Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
  }
};
void setup()
{
  Serial.begin(115200);
  Serial.println("Scanning...");
  BLEDevice::init("");
  BLEScan *pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  BLEScanResults foundDevices = pBLEScan->start(scanTime);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
}
void loop()
{
  // put your main code here, to run repeatedly:
  delay(2000);
}
這邊是執行結果可以看到掃描到的裝置。
ets Jun  8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5828
entry 0x400806ac
Scanning...
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
Advertised Device: Name: MJ_HT_V1, Address: 4c:65:a8:da:1f:cc, serviceUUID: 0000180f-0000-1000-8000-00805f9b34fb
Devices found: 2
Scan done!
ESP32 藍芽讀取廣播資料 溫濕度
我們這邊依樣示範讀取小米的藍芽溫濕度。
#include <Arduino.h>
#include <sstream>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 5; //In seconds
BLEScan *pBLEScan;
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
  void onResult(BLEAdvertisedDevice advertisedDevice)
  {
    if (advertisedDevice.haveName() && advertisedDevice.haveServiceData() && !advertisedDevice.getName().compare("LYWSD02"))
    {
      std::string strServiceData = advertisedDevice.getServiceData();
      Serial.printf("\n\nAdvertised Device: %s\n", advertisedDevice.toString().c_str());
      std::string uuid = advertisedDevice.getServiceDataUUID().toString();
      Serial.println(uuid.c_str());
      if (uuid.compare("0000fe95-0000-1000-8000-00805f9b34fb"))
      {
        return;
      }
      uint8_t cServiceData[100];
      char charServiceData[100];
      strServiceData.copy((char *)cServiceData, strServiceData.length(), 0);
      for (int i = 0; i < strServiceData.length(); i++)
      {
        sprintf(&charServiceData[i * 2], "%02x", cServiceData[i]);
      }
      bool is_mijia = (cServiceData[1] & 0x20) == 0x20 && cServiceData[2] == 0xAA && cServiceData[3] == 0x01;
      bool is_lywsd02 = (cServiceData[1] & 0x20) == 0x20 && cServiceData[2] == 0x5b && cServiceData[3] == 0x04;
      if (is_mijia)
      {
        Serial.println("is_mijia!");
      }
      if (is_lywsd02)
      {
        uint8_t raw_offset = is_mijia ? 11 : 12;
        const uint8_t raw_type = cServiceData[raw_offset];
        const uint8_t data_length = cServiceData[raw_offset + 2];
        const uint8_t *data = &cServiceData[raw_offset + 3];
        const uint8_t expected_length = data_length + raw_offset + 3;
        const uint8_t actual_length = advertisedDevice.getServiceData().size();
        if (expected_length != actual_length)
        {
          return;
        }
        // Serial.println("is_lywsd02!");
        switch (raw_type)
        {
        case 0x0D:
        { // temperature+humidity, 4 bytes, 16-bit signed integer (LE) each, 0.1 °C, 0.1 %
          if (data_length != 4)
            return;
          const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
          const int16_t humidity = uint16_t(data[2]) | (uint16_t(data[3]) << 8);
          Serial.print("temperature=");
          Serial.println(temperature / 10.0f);
          Serial.print("humidity=");
          Serial.println(humidity / 10.0f);
          return;
        }
        case 0x06:
        { // humidity, 2 bytes, 16-bit signed integer (LE), 0.1 %
          if (data_length != 2)
            return;
          const int16_t humidity = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
          Serial.print("humidity=");
          Serial.println(humidity / 10.0f);
          return;
        }
        case 0x04:
        { // temperature, 2 bytes, 16-bit signed integer (LE), 0.1 °C
          if (data_length != 2)
            return;
          const int16_t temperature = uint16_t(data[0]) | (uint16_t(data[1]) << 8);
          Serial.print("temperature=");
          Serial.println(temperature / 10.0f);
          return;
        }
        default:
          return;
        }
      }
    }
  }
};
void setup()
{
  Serial.begin(115200);
  Serial.println("Scanning...");
  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);
}
void loop()
{
  BLEScanResults foundDevices = pBLEScan->start(scanTime);
  delay(2000);
}
這邊是執行結果可以看到溫度濕度資訊。
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
0000fe95-0000-1000-8000-00805f9b34fb
humidity=56.00
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
0000fe95-0000-1000-8000-00805f9b34fb
temperature=27.80
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
0000fe95-0000-1000-8000-00805f9b34fb
humidity=56.00
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
0000fe95-0000-1000-8000-00805f9b34fb
temperature=27.80
Advertised Device: Name: LYWSD02, Address: 3f:5b:7d:80:b0:d1, serviceUUID: 0000181a-0000-1000-8000-00805f9b34fb
0000fe95-0000-1000-8000-00805f9b34fb
humidity=56.00
這邊有踩到坑浪費我好幾小時,藍芽掃描廣播資訊時。這個程式庫會複寫得到的裝置 serviceUUID(依該説它只會存一筆單個 service)…所以要調整掃描區間給他縮短讓他收集到不同資料。
結語
今天介紹直接開發藍芽裝置去讀取其他藍芽的溫濕度!如果你還想延伸可以再將資料透過 MQTT 發送到主機。