espressif / arduino-esp32

Arduino core for the ESP32
GNU Lesser General Public License v2.1
13.52k stars 7.39k forks source link

BLEScan reports wrong MAC address -- Arduino ESP32 version 2.0.12 #8609

Closed dpnebert closed 1 year ago

dpnebert commented 1 year ago

Board

ESP32-WROOM-32E

Device Description

ESP32 dev boards with ESP32-WROOM-32E modules.

Hardware Configuration

Nothing.

Version

other

IDE Name

Arduino IDE

Operating System

Windows 11 Pro

Flash frequency

40MHz

PSRAM enabled

no

Upload speed

921600

Description

Synopsis: Printing to the serial monitor (and also running "espefuse.py --port COM15 summary", which I'll talk about later), the ESP32's MAC address shows: "54:43:b2:c9:8d:4c". Using another ESP32, scanning for BLE devices, found device MAC address shows: "54:43:b2:c9:8d:4e" I've attempting on multiple units, and each time the very last byte is always incremented by two. (4c -> 4e)

Detailed Explanation: I have a ESP32 acting as a "Controller", and I have an ESP32s acting as a "Remote".

Controller ESP32: Board: ESP32-PICO-DevKitM-2U Chip Model: ESP32-PICO-V3-02 Chip Revision: 3 Chip Cores: 2

Remote ESP32: Board: ESP32_DevKitc_V4 Chip Model: ESP32-D0WD-V3 Chip Revision: 3 Chip Cores: 2

The Controller scans for BLE devices, checks to see if the name contains "BLE Remote", then checks the MAC address, and if it matches a hardcoded string, will attempt to connect.

On the Remote, I have the following sketch that simply prints out the MAC address:

/*
 * Print out MAC address
 */ 
std::string getMacAddress() {
  std::string mac = "";
  unsigned char mac_base[6] = {0};
  if(esp_efuse_mac_get_default(mac_base) == ESP_OK) {
    char buffer[18]; // 6*2 characters for hex + 5 characters for colons + 1 character for null terminator
    sprintf(buffer, "%02X:%02X:%02X:%02X:%02X:%02X", mac_base[0], mac_base[1], mac_base[2], mac_base[3], mac_base[4], mac_base[5]);
    mac = buffer;
  }
  return mac;
}
void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println(getMacAddress().c_str());
}
void loop() {}

And this is what is printed to the serial monitor: 54:43:B2:C9:8D:4C

Here is the sketch for the Controller to scan for BLE devices:

/*
   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
   Ported to Arduino ESP32 by Evandro Copercini
*/

#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) {
      //Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
    }
};

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);  // less or equal setInterval value
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");

  /*
   * Start of my modifications
   */
  for(int i = 0; i < foundDevices.getCount(); i++) {
    if(foundDevices.getDevice(i).getName().find("BLE Remote") != std::string::npos) {
      Serial.print("BLE Remote MAC Address: ");Serial.println(foundDevices.getDevice(i).getAddress().toString().c_str());
    }
  }
  /*
   * End of my modifications
   */

  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

And here is the serial monitor output:

Scanning...
Devices found: 81
Scan done!
BLE Remote MAC Address: 54:43:b2:c9:8d:4e

My first thought was either the sketch to print out the MAC address or the sketch to scan for devices was not working correctly. So I opened up an ESP-IDF command window, created a new project called "dummy", navigated to that directory, and ran the following command: espefuse.py --port COM15 summary

Which gave me the summary for the eFuses. Here is the snippet for the MAC address:

Identity fuses:
MAC (BLOCK0):                                      Factory MAC Address
   = 54:43:b2:c9:8d:4c (CRC 0x5d OK) R/W

This issue has been the case for every ESP32 that I have attempted. I have dug in to find out why the last byte was always off by 2, but it's beginning to turn into a rabbit hole.

Sketch

/*
   Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
   Ported to Arduino ESP32 by Evandro Copercini
*/

#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) {
      //Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
    }
};

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);  // less or equal setInterval value
}

void loop() {
  // put your main code here, to run repeatedly:
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");

  /*
   * Start of my modifications
   */
  for(int i = 0; i < foundDevices.getCount(); i++) {
    if(foundDevices.getDevice(i).getName().find("BLE Remote") != std::string::npos) {
      Serial.print("BLE Remote MAC Address: ");Serial.println(foundDevices.getDevice(i).getAddress().toString().c_str());
    }
  }
  /*
   * End of my modifications
   */

  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

Debug Message

Too many MAC address from not development equipment to post sensitive info.

If you have two ESP32s, on the first, use 'espefuse.py summary' to get the MAC address, then flash the Arduino ESP32 BLE example 'BLE_server'.  On the second, modify the Arduino ESP32 BLE example 'BLE_scan' to print out the BLEAddress.

Other Steps to Reproduce

I have a small pile of ESP32_DevKitc_V4 boards I've been using, none match the scanner output. I have even tried using a 'ESP32-PICO-DevKitM-2U'

I have checked existing issues, online documentation and the Troubleshooting Guide

dpnebert commented 1 year ago

Of course, right after I post, I find a work around, but I'd still love to know why those two don't match up.

Workaround: 'BLEDevice' has the public method, 'getAddress()' which returns a 'BLEAddress'. I realized I truly only need to print out a Remote's MAC address when I am developing. It was so I could copy/paste the address in to the Controller's sketch so I can force a match. We could close this issue, but it would be cool to find out why those two are different.

VojtechBartoska commented 1 year ago

Can you please take a look and try to reproduce it @P-R-O-C-H-Y? Thanks

SuGlider commented 1 year ago

@dpnebert

This is documented at https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/misc_system_api.html#mac-address

dpnebert commented 1 year ago

@SuGlider Thank you! I do apologize for creating an issue for something clearly documented. This is my first project using the MAC address for identification, and reading others' forum post about how to get the MAC address seemed to me their answers were how to get the one MAC address. Now I see there is a MAC address for a specific network interface. Thank you!

SuGlider commented 1 year ago

Sure! I'm happy in helping you!

dpnebert commented 1 year ago

I wrote an example sketch named ‘MacAddress’ for show how to call for the default and interface specific MAC addresses. PR#8618

I’m using the BLE library so ‘BLEDevice::getAddress()’ is really all I need.