BLE_scan: scans after first one don't return correct info
Posted: Wed Sep 30, 2020 12:48 am
Quick summary: BLE scans for advertising packets return something wrong after the first scan (first scan returns correct packets)
-------
running Neil Kolbans Examples>ESP32 BLE Arduino>BLE_Scan.ino example on a 1.0.4 ESP32 IDF, Arduino IDE 1.8.14 hourly 2020/09/23
Using it to passively scan for advertising packets from Govee H5074 thermometer+humidity sensors
https://www.amazon.com/Govee-Thermomete ... 473&sr=8-2
These send out a message every second, and every other or so message contains actual sensor data (temp, humidity) The other ones contain other manufacturer data.
For the sensor data containing packets I know that
esp_ble_gap_cb_param_t➟scan_rst.scan_rsp_len=11 and
esp_ble_gap_cb_param_t➟scan_rst.adv_data_len=29 total length = 40
And for the other packets
scan_rsp_len=27 and adv_data_len=29 total length = 56 (no sensor data)
When I run the code below, which is quite short, the first scan returns proper data as expected.
Here, each Govee_H5074_XXXX sensor is identified in its name by XXXX=last 4 digits of its device address
You can see that we regularly get an advertising packet from various devices with sensor data (and in between length 56 packets)
BUT:
after the first scan terminates and pBLEScan➟start() is called subsequently, the stack consistently returns
scan_rsp_len=0 and adv_data_len=29 total length=29
packets which is wrong.
Now, I don't know whether the bug exists in Neils C++ wrapper class or in the underlying esp_ble_**** calls.
It appears his BLEScan::start() basically does this:
https://github.com/nkolban/esp32-snippe ... LEScan.cpp
esp_ble_gap_set_scan_params(&m_scan_params);
esp_ble_gap_start_scanning(duration);
Is that correct, is it enough ? If so, is the failure to deliver any advertisements in subsequent scans with scan_rsp_len>0 in the handleGAPevent callback (ESP_GAP_SEARCH_INQ_RES_EVT) the fault of the esp_ble stack ?
-------
running Neil Kolbans Examples>ESP32 BLE Arduino>BLE_Scan.ino example on a 1.0.4 ESP32 IDF, Arduino IDE 1.8.14 hourly 2020/09/23
Using it to passively scan for advertising packets from Govee H5074 thermometer+humidity sensors
https://www.amazon.com/Govee-Thermomete ... 473&sr=8-2
These send out a message every second, and every other or so message contains actual sensor data (temp, humidity) The other ones contain other manufacturer data.
For the sensor data containing packets I know that
esp_ble_gap_cb_param_t➟scan_rst.scan_rsp_len=11 and
esp_ble_gap_cb_param_t➟scan_rst.adv_data_len=29 total length = 40
And for the other packets
scan_rsp_len=27 and adv_data_len=29 total length = 56 (no sensor data)
When I run the code below, which is quite short, the first scan returns proper data as expected.
Here, each Govee_H5074_XXXX sensor is identified in its name by XXXX=last 4 digits of its device address
You can see that we regularly get an advertising packet from various devices with sensor data (and in between length 56 packets)
BUT:
after the first scan terminates and pBLEScan➟start() is called subsequently, the stack consistently returns
scan_rsp_len=0 and adv_data_len=29 total length=29
packets which is wrong.
Now, I don't know whether the bug exists in Neils C++ wrapper class or in the underlying esp_ble_**** calls.
It appears his BLEScan::start() basically does this:
https://github.com/nkolban/esp32-snippe ... LEScan.cpp
esp_ble_gap_set_scan_params(&m_scan_params);
esp_ble_gap_start_scanning(duration);
Is that correct, is it enough ? If so, is the failure to deliver any advertisements in subsequent scans with scan_rsp_len>0 in the handleGAPevent callback (ESP_GAP_SEARCH_INQ_RES_EVT) the fault of the esp_ble stack ?
Starting scan...
{"name":"Govee_H5074_C0A6","celsius":24.3,"fahrenheit":75.8,"humidity":57.8,"battery":100}
Govee_H5074_C0A6 length[56] advertisement...no sensor data!
{"name":"Govee_H5074_C0A6","celsius":24.3,"fahrenheit":75.7,"humidity":57.8,"battery":100}
Govee_H5074_C0A6 length[56] advertisement...no sensor data!
{"name":"Govee_H5074_C0A6","celsius":24.3,"fahrenheit":75.8,"humidity":57.6,"battery":100}
Govee_H5074_C0A6 length[56] advertisement...no sensor data!
Starting scan...
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Starting scan...
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
Govee_H5074_C0A6 length[29] advertisement...no sensor data!
...and so on and so on
Code: Select all
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
BLEScan* pBLEScan;
long getLongFromByteArray(byte* bytes, int position) {
long result = bytes[position + 1] * 256 + bytes[position];
return result;
}
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
String deviceName( advertisedDevice.getName().c_str() );
// devicename is something like Govee_H5074_C0A6
// H5074= type of govee device
// C0A6 = last four digits of this device address
if ( deviceName.startsWith( "Govee_H5074_" ) ) {
unsigned long pll = advertisedDevice.getPayloadLength();
uint8_t* payload = advertisedDevice.getPayload();
if( pll!=40 )
Serial.printf( "%s length[%d] advertisement...no sensor data!\n", advertisedDevice.getName().c_str(), pll );
// we see length 29, 40, 56 packets for Govees (adv_data_len=29 always, scan_rsp_len=0,11,27 resp.
// only the length 40 packets actually contain sensor data in the ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE (0xFF)
// Sensor data for govee = 88:EC:00:19:09:5C:15:64:02
// ^^^^^ temperature
// ^^^^^ humidity
// ^^ battery level
if ( pll == 40 ) {
double celsius = ((double)getLongFromByteArray(payload, 34 )) / 100.0;
double fahrenheit = (celsius * 9.0 / 5.0) + 32.0;
double relativeHumidity = ((double)getLongFromByteArray(payload, 36)) / 100.0;
int battery = payload[38];
Serial.printf( "{\"name\":\"%s\",\"celsius\":%.1lf,\"fahrenheit\":%.1lf,\"humidity\":%.1lf,\"battery\":%d}\n",
deviceName.c_str(), celsius, fahrenheit, relativeHumidity, battery );
}
}
}
};
void setup() {
Serial.begin(115200);
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), true /* wantDuplicates ? yes */);
pBLEScan->setActiveScan(false); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void loop() {
int scanTime = 10; //In seconds
Serial.printf( "\nStarting scan...\n" );
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
pBLEScan->clearResults();
delay( 10000 );
}