iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 21
0
IoT

制霸IoT 30Day!系列 第 21

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 發送到主機。

Blog 同步刊登


上一篇
Day 20 藍芽硬體開發
下一篇
Day 22 實際案例 空氣盒子專案(一)
系列文
制霸IoT 30Day!30

尚未有邦友留言

立即登入留言