慕容雪花 发表于 2024-5-1 11:12

【FireBeetle 2 ESP32 C6开发板】-3- C6获取小米温湿度计2数据

本帖最后由 慕容雪花 于 2024-5-2 12:36 编辑

<p>小米温湿度计2 是从设备,同时也是BLE SERVER,部署了多个sevice,其中serviceUUID(&quot;ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6&quot;)里面的charUUID(&quot;ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6&quot;)就是温湿度数据。</p>

<p>&nbsp;</p>

<p>esp32c6是主设备,同时也是BLE CLIENT,通过BLE的协议来访问Server上的Characteristic,从而获取到温湿度数据。</p>

<p>C6启动后,会开始扫描周围的BLE设备,此时进行一个判断,设备名称是否为XiaomiDeviceName = &quot;LYWSD03MMC&quot;</p>

<pre>
<code> /**
   * Called for each advertising BLE server.
   */
void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.println("*-------------------------------------------------------------------*");
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());

    // We have found a device, let us now see if it contains the service we are looking for.

    Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
    Serial.println(advertisedDevice.getName().c_str());

    if(0 == advertisedDevice.getName().compareTo(XiaomiDeviceName)){
      Serial.println("Great, Found " + advertisedDevice.getName());

      Serial.println("advertisedDevice.getServiceUUIDCount() = " + String(advertisedDevice.getServiceUUIDCount()));

      BLEDevice::getScan()-&gt;stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;      
    }
} // onResult</code></pre>

<p>找到小米设备后,进行连接:</p>

<pre>
<code>bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice-&gt;getAddress().toString().c_str());
   
    BLEClient*pClient= BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient-&gt;setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient-&gt;connect(myDevice);// if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");
    pClient-&gt;setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient-&gt;getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService-&gt;getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      pClient-&gt;disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteCharacteristic-&gt;canRead()) {
      String value = pRemoteCharacteristic-&gt;readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteCharacteristic-&gt;canNotify())
      pRemoteCharacteristic-&gt;registerForNotify(notifyCallback);

    connected = true;
    return true;
}</code></pre>

<p>从小米设备获取到数据,共有5个字节。</p>

<pre>
<code>static void notifyCallback(
BLERemoteCharacteristic* pBLERemoteCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
    Serial.print("Notify callback for characteristic ");
    Serial.print(pBLERemoteCharacteristic-&gt;getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);


    uint16_t TempVal = pData*256 + pData;
    Serial.println("Temperature is: "+ String(TempVal/100) + "." + String(TempVal%100) + " degree");

    uint8_t HumidityVal = pData;
    Serial.println("Humidity is: " + String(pData) + "% ");

    uint16_t BatteryVal = pData*256 + pData;
    Serial.println("Battery Voltage is: "+ String(BatteryVal/100) + "." + String(BatteryVal%100) + " mV");


    Serial.println();
}</code></pre>

<p>注意数据为小端模式存储。</p>

<p>&nbsp;</p>

<p>&nbsp;&nbsp;</p>

<p>-------------------------------------------------------------------------------------------------------------------</p>

<p><span style="font-size:16px;"><strong>5.2日更新:</strong></span></p>

<p>上文中BLE SERVER notify上来的数据是没有问题的,温湿度值跟实际设备对比也是OK的,但是仔细观察设备启动,首次连接小米设备成功后,直接读取Characteristic的值,竟然是4??</p>

<p> &nbsp;</p>

<p>这个肯定是读取的姿势不对,我接下来一番笨丁解牛。</p>

<p>小米温湿度数据格式为:F2 07 4A C3 0A。也就是5个十六进制数据。仔细看当前的直接读取Characteristic值代码:</p>

<pre>
<code>    // Read the value of the characteristic.
    if(pRemoteCharacteristic-&gt;canRead()) {
      String value = pRemoteCharacteristic-&gt;readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }</code></pre>

<p>readValue()方法返回的是String类型变量,更合适的应该是:</p>

<pre>
<code>uint8_t* test = pRemoteCharacteristic-&gt;readRawData();</code></pre>

<p> &nbsp;</p>

<p>计算一下使用直接读取数据所对应的温湿度:</p>

<p> &nbsp;</p>

<p>&nbsp;</p>

<p>代码:</p>

<pre>
<code>uint8_t* test = pRemoteCharacteristic-&gt;readRawData();
      uint8_t i;
      uint8_ttest_temp_val={0};

      for(i = 0; i &lt; 5; i++){
      if(test != nullptr){
          Serial.print("The characteristic value using readRawData was: ");
          Serial.println(*test);
          test_temp_val = *test;
      }else{
          Serial.println("pRemoteCharacteristic-&gt;readRawData() returns NULL PTR");
      }
      test++;
      }

    static uint16_t Test_TempVal = test_temp_val*256 + test_temp_val;
    Serial.println("Test Temperature is: "+ String(Test_TempVal/100) + "." + String(Test_TempVal%100) + " degree");

    static uint8_t Test_HumidityVal = test_temp_val;
    Serial.println("Test Humidity is: " + String(test_temp_val) + "% ");

    static uint16_t Test_BatteryVal = test_temp_val*256 + test_temp_val;
    Serial.println("Test Battery Voltage is: "+ String(Test_BatteryVal/100) + "." + String(Test_BatteryVal%100) + " mV");      
</code></pre>

<p>参考:</p>

<p>读取小米蓝牙温湿度计2数据 <a href="https://www.cnblogs.com/qsbye/p/15913753.html" target="_blank">https://www.cnblogs.com/qsbye/p/15913753.html</a></p>

chejm 发表于 2024-5-1 17:49

<p>感谢楼主分享的技术内容,有机会一定买块板子动手测试一下这些例子</p>

lugl4313820 发表于 2024-5-1 22:49

<p>C6启动后,会开始扫描周围的BLE设备,此时进行一个判断,设备名称是否为XiaomiDeviceName = &quot;LYWSD03MMC&quot;</p>

<p>不会吧,直接可以读出小米的东西吗?</p>

慕容雪花 发表于 2024-5-2 08:52

lugl4313820 发表于 2024-5-1 22:49
C6启动后,会开始扫描周围的BLE设备,此时进行一个判断,设备名称是否为XiaomiDeviceName = &quot;LYWSD03MMC ...

<p>可以的大佬,是我太菜了。我尝试扫描周围设备,想直接根据SERVICE UUID来锁定小米温湿度度计2,但可能小米设备的广播报文里面并没有包含serviceUUID(&quot;ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6&quot;)。所以才直接根据设备名称来锁定小米设备。</p>
页: [1]
查看完整版本: 【FireBeetle 2 ESP32 C6开发板】-3- C6获取小米温湿度计2数据