[SOLVED] Reading advertising data via ArduinoBLE hack for ATC_MiThermometer

Hi,

Per the attached image from the android nRF Connect app, I am trying to access service data UUID 0x181A for this BLE thermometer/humidity device.

Using the AndroidBLE provided Central -> Scan Example, there are no "Service UUIDs" listed for my BLE device, in contrast to what nRF connect shows. Other devices in range possess short and long service UUIDs.

I tried to connect to the device to try other things like querying characteristics, but the connect fails. I don't think I need to connect though, because the temp and humidity is part of the BLE advertising as I understand it.

Any suggestions?

Thanks!
M

Following is the unmodified provided Scan example code:

/*
  Scan

  This example scans for BLE peripherals and prints out their advertising details:
  address, local name, adverised service UUID's.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

void setup() {
  Serial.begin(9600);
  while (!Serial);

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  Serial.println("BLE Central scan");

  // start scanning for peripheral
  BLE.scan();
}

void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();

  if (peripheral) {
    // discovered a peripheral
    Serial.println("Discovered a peripheral");
    Serial.println("-----------------------");

    // print address
    Serial.print("Address: ");
    Serial.println(peripheral.address());

    // print the local name, if present
    if (peripheral.hasLocalName()) {
      Serial.print("Local Name: ");
      Serial.println(peripheral.localName());
    }

    // print the advertised service UUIDs, if present
    if (peripheral.hasAdvertisedServiceUuid()) {
      Serial.print("Service UUIDs: ");
      for (int i = 0; i < peripheral.advertisedServiceUuidCount(); i++) {
        Serial.print(peripheral.advertisedServiceUuid(i));
        Serial.print(" ");
      }
      Serial.println();
    }

    // print the RSSI
    Serial.print("RSSI: ");
    Serial.println(peripheral.rssi());

    Serial.println();
  }
}

Just to make sure, you can only have one central connect to a peripheral. Make sure you are not connected to the device with your phone when you run your scan example.

Can you connect to the ATC1441 with any BLE app?

What is the serial output of the scan example?

mpinch:
I don't think I need to connect though, because the temp and humidity is part of the BLE advertising as I understand it.

Advertising data and characteristics are two different things. To read the characteristics you need to connect. As far as I know, reading custom advertisement data is not supported by the library. You get the standard information e.g. address, name and advertisement service UUID.

Do you have a second Arduino e.g. a Nano 33 IoT or BLE to load a peripheral example?

Thanks Klaus!! Your answer pointed me in the right direction and I solved the problem.

This solution would apply to ALL custom advertising data solutions, not just Custom firmware for the Xiaomi Thermometer LYWSD03MMC and Telink Flasher via USB to Serial converter

Klaus_K:
As far as I know, reading custom advertisement data is not supported by the library.

I added the following code to ArduinoBLE...

BLEDevice.h

  int getAdvertisement(uint8_t value[], int length);

BLEDevice.cpp

int BLEDevice::getAdvertisement(uint8_t value[], int length)
{
  if (_eirDataLength) {
    memcpy(value, _eirData, _eirDataLength);
  }

  return _eirDataLength;
}

Now I have access to the custom advertising data. I should submit as a request to be added to the base. Maybe getRawAdvertisement might be better.

Usage / Output:

BLE Central scan
Discovered a peripheral
-----------------------
Address: a4:c1:38:38:b1:91
Local Name: ATC_38B191
Advertisement 0x16: 0x1A18A4C13838B1910F53757BB226
RSSI: -69

Usage / Code

#include <ArduinoBLE.h>


/*
  Scan


  This example scans for BLE peripherals and prints out their advertising details:
  address, local name, adverised service UUID's.


  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.


  This example code is in the public domain.
*/


#include <ArduinoBLE.h>


void setup() {
  Serial.begin(9600);
  while (!Serial);


  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");


    while (1);
  }


  Serial.println("BLE Central scan");


  // start scanning for peripheral
  BLE.scan();
}


void loop() {
  // check if a peripheral has been discovered
  BLEDevice peripheral = BLE.available();


  // Scan only for ATC_ devices
  if (peripheral && peripheral.hasLocalName() && peripheral.localName().startsWith("ATC_")) {
    // discovered a peripheral
    Serial.println("Discovered a peripheral");
    Serial.println("-----------------------");


    // print address
    Serial.print("Address: ");
    Serial.println(peripheral.address());




    // print the local name, if present
    if (peripheral.hasLocalName()) {
      Serial.print("Local Name: ");
      Serial.println(peripheral.localName());
    }


    uint8_t advertisement[64] = {0};
    int adLength = peripheral.getAdvertisement(advertisement,64);
    Serial.print("Advertisement 0x16: 0x");
    uint8_t sensorAdvertisementData[64];  // TODO - allocate according to length or spec


   // zero out array, though really only first byte (length byte) needs to be zeroed
   for (int x = 0; x < sizeof(sensorAdvertisementData); x++)
   {
     sensorAdvertisementData[x] = 0;
   }


   for (int i = 0; i < 64;) {
     int eirLength = advertisement[i++];
     int eirType = advertisement[i++];


     if (eirType == 0x16) {  // ATC advertisement type


       // Copy length byte since this is not a String
       sensorAdvertisementData[0] = eirLength;
       for (int j = 0; j < (eirLength - 1); j++) {
         uint8_t thisByte = advertisement[i + j];
         sensorAdvertisementData[j+1] = thisByte;  // offset 1 due to length byte
         Serial.print(thisByte,HEX);
         
       }
       break;
     }
     i += (eirLength - 1);
   }


   Serial.println();
   
    // print the RSSI
    Serial.print("RSSI: ");
    Serial.println(peripheral.rssi());


    Serial.println();
  }
}
1 Like

I submitted the AndroidBLE feature request via Issue 123 (which sounds made up, bit it is not :slight_smile: )