T-vK / ESP32-BLE-Keyboard

Bluetooth LE Keyboard library for the ESP32 (Arduino IDE compatible)
2.28k stars 379 forks source link

How to add a unique serial number to the BLEKeyboard Device Name? #178

Open creepscompilation opened 1 year ago

creepscompilation commented 1 year ago

I would like the BLE Keyboard to display a unique name when pairing by adding a serial number.

If I have multiple BLE keyboards paired, I need to be able to tell the difference between each one. Is there a unique MAC address or something in the code I can add to the command line below?

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("Bluetooth Device Name + (4-Digit) Serial Number" , "Company name",100);

Normally, I would simply generate a random number and add it to the name value, however, this command line must be executed above the "setup" section in Arduino and I am unable run that code in that section.

Also, I am unable to run the above command line within any other section in Arduino.

So, I am hoping there is an existing unique ID number somewhere in the code that I can use?

webmonkey commented 1 year ago

I use this function in my code that reads the MAC address of the ESP32 device.

// populates the deviceName char with the device Prefix plus a "unique" 4 char code
void getDeviceName(char* deviceName, char* devicePrefix) {
    uint64_t chipid = ESP.getEfuseMac();
    uint16_t shortid = chipid >> 32;
    char sprintfString[20] = "";
    strcat(sprintfString, devicePrefix);
    strcat(sprintfString, " %04X");

    sprintf(deviceName, sprintfString, shortid);
}

and call it like this:

    // derive a unique name
    char deviceName[20];
    getDeviceName(deviceName, "Device Name");
    bleKeyboard.setName(deviceName);
webmonkey commented 1 year ago

@T-vK suggest this can be closed now

ekoslav commented 1 year ago

I tried webmonkey's solution, and the unique name part does work nicely. However, the part that is supposed to set the device name bleKeyboard.setName(deviceName); does not work. I used it in the last line of "void setup()" The name of the device stays as defined in the BleKeyboard bleKeyboard("Macro_kbd_SN0CX","ESP32 DEVKIT V1", 98);

webmonkey commented 1 year ago

You need to set the device name before the bleKeyboard.begin() call.

Are you able to share the code you're using?

ekoslav commented 1 year ago

Thanks! That actually did the trick!

Here is the section in the working version in the "void setup()": ` // Apply name based on MAC

char deviceName[20];

getDeviceName(deviceName, "Macro_kbd");

bleKeyboard.setName(deviceName);

bleKeyboard.begin();`

As for the code, it is a bit long, but here: https://github.com/ekoslav/ESP32_Password_keyboard/tree/main/ESP32_4x4MatKBD_SPIFS

creepscompilation commented 1 year ago

Hello ekoslav,

Thank you very much for the help, I have it running on my application and it is working well, except it does not seem to show up anymore on Apple iPad or iPhone as an available Bluetooth device now.

It does show up on Android, Windows 8, and Windows 10 systems for some reason.

Does this work for you on iOS devices? Maybe my device name is too long now? It adds up to 16 characters. Here is the Bluetooth device name on Android and Windows "9xx_BLE_v1.0_B087"

creepscompilation commented 1 year ago

Here is all the code:

////////////////////////////////////////////////////////////////////////////////////

include

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("9xx_BLE_v1.0","Company Name",100);

// populates the deviceName char with the device Prefix plus a "unique" 4 char code void getDeviceName(char deviceName, char devicePrefix) { uint64_t chipid = ESP.getEfuseMac(); uint16_t shortid = chipid >> 32; char sprintfString[20] = ""; strcat(sprintfString, devicePrefix); strcat(sprintfString, " %04X");

sprintf(deviceName, sprintfString, shortid);

}

////////////////////////////////////////////////////////////////////////////////////

void setup() { Serial.begin(115200); ////////////////////////////////////////////////////////////////////////////////////

char deviceName[20]; getDeviceName(deviceName, "9xx_BLE1.0"); bleKeyboard.setName(deviceName);

bleKeyboard.begin(); // Wait to Initialize delay(2000);

////////////////////////////////////////////////////////////////////////////////////
// END OF SETUP ////////////////////////////////////////////////////////////////////////////////////

creepscompilation commented 1 year ago

Note: I left this statement in the code because of the "Manufacturer Name and delay value

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("9xx_BLE_v1.0","Company Name",100);

Maybe this statement overrides the previous statement and leaving off the Manufacturer name is the problem? bleKeyboard.setName(deviceName);

Is there a way add the manufacturer name and delay value? I am almost 100% sure that this is the issue

creepscompilation commented 1 year ago

CONFIRMED: Ok the following code works on all operating systems. I commented out the new code after SETUP and now the device name shows up on all operating systems

I believe that iOS must require the manufacturer name and Windows does not. I also believe that the bleKeyboard.setName(deviceName); must be over-writing the manufacturers name.

include

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("9xx_BLE_v1.0","Company Name",100);

// char deviceName[20]; // getDeviceName(deviceName, "9xx_BLE1.0"); // bleKeyboard.setName(deviceName);

bleKeyboard.begin();

ekoslav commented 1 year ago

Looks like you have answered your own question while I was writing the reply. I tested my code on following: It does work for me on iPhone 6. On Android 11 (Redmi Note 8 Pro), it is visible and connects, however does not produce keystrokes. On Android 10 (Teclast P20HD), it is visible and connects, however does not produce keystrokes. On Android 4.4 it does work. Android 6 (Sony XA1) works. On all windows desktops it does work.

creepscompilation commented 1 year ago

Is there a way to set the manufacturer name ? If I lave my code as is, everything works..

include

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("9xx_BLE_v1.0","Company Name",100);

creepscompilation commented 1 year ago

The iPhone 11 I am testing with does not display the BLE keyboard without the manufacturer name.

creepscompilation commented 1 year ago

In my testing, the only statement that works on all Apple iOS devices is the following:

include

// Define the Display name of the BLE Device BleKeyboard bleKeyboard("BLE_KB_1.0","Company Name",100);

void setup() { bleKeyboard.begin(); { void loop() { {

This only works in the section above the setup section. I am not sure how to use a variable string instead of fixed text.

String product_name_string = "BLE_KB_1.0"; BleKeyboard bleKeyboard( product_name_string, "Company Name" ,100);

The serial number MAC address code works GREAT, except I have not found a way to replace the FIXED text "BLE_KB_1.0" with a string variable that contains the auto-generated MAC address.

HELP ?!?!?!

T-vK commented 1 year ago
  1. The device name must not exceed 15 characters in length. The constructor has code in place to trim the given name down to the first 15 characters, even if a longer name was specified. For the setName method unfortunately it was forgotton to do the same, so you have to make sure youself that you don't provide a name that's too long otherwise Apple devices will struggle. A MAC address is pretty long. Since the first 6 digits of a MAC address hold the vendor information and thus are not unique and probably the same for all ESPs anyway, I would advice to only use the last 6 digits.

  2. Make sure to call begin() after setName().

creepscompilation commented 1 year ago

Hello T-vk, Thank you for the assistance. The setName() function works GREAT !!!

I am able to implement it with the "setup" section and generate a unique Bluetooth name for each device.

I ran tests and the length of the name is not causing the problem with the Bluetooth device failing to show up on Apple iOS host devices.

I have confirmed that the Apple iOS host devices are requiring a manufacturer name of some kind before they allow the Bluetooth device to show up on the list of available device to connect to.

The function I have been using includes the manufacturer name but it can only be run before the "setup" section for some reason.. (see Below) BleKeyboard bleKeyboard( product_name_string, "Company Name" ,100);

This function assigns a Bluetooth product name, a manufacturer name, and also the battery level).

Question # 1: Is there a way to modify the library function for this function so it can be run within the "setup" section just like the setName() function does ???

Question # 2: If not, is there another function that can assign the "manufacturer" name ?

Question # 3: Is there another function that can assign and update the current battery level?

If this function can be modified to run with the "setup" section, then I can easily use variables to get the MAC address and assign the product name along with the manufacturer name and finally be able to update the battery level on the wireless keyboard.

I am hoping to resolve this issue and help other users in he future who will run into the same problems.

T-vK commented 1 year ago

For the battery level there is another function documented in the Readme. There is no other way to set the manufacturer name at the moment. You'd have to implement a new method for that on the class. If you set the manufacturer name in the constructor as you have shown, it should persist, even after calling setName.