Can't set BLE characteristic name?

I am sending data from Arduino Nano 33 BLE Sense to Raspberry Pi 4 over BLE.

I am using ArduinoBLE.h library.

The data I send is acceleration data. I defined my characteristic as follow:

BLEShortCharacteristic accelerometerCharacteristic_X( BLE_UUID_ACCELEROMETER_X, BLERead | BLENotify );

This is what I read from my Pi:
{"uuid":"2101","name":null,"type":null,"properties":["read","notify"]}

I realised when defining a characteristic there is no place to define the name and if you define the data type (short in this case) before hand, you can only provide properties and UUID:

BLECharacteristic::BLECharacteristic(const char* uuid, uint8_t properties, int valueSize, bool fixedLength) :
  BLECharacteristic(new BLELocalCharacteristic(uuid, properties, valueSize, fixedLength))
{
}

BLECharacteristic::BLECharacteristic(const char* uuid, uint8_t properties, const char* value) :
  BLECharacteristic(new BLELocalCharacteristic(uuid, properties, value))
{
}

I have thought the const char* value indicates a characteristic name, but it is not, it is just an another way to define size, I did not even understand why that exists:

BLELocalCharacteristic::BLELocalCharacteristic(const char* uuid, uint8_t properties, const char* value) :
  BLELocalCharacteristic(uuid, properties, strlen(value))
{
  writeValue(value);
}

Then, I came across with this thread.

I bet if you create a descriptor with ID 0x2901 (attached to your characteristic) and set its value to "My Chracteristic", then Characteristc.Name will be "My Chracteristic" in your C# code.

So, I have created a descriptor and added to my characteristic:

BLEDescriptor accelerationXDescriptor("2901", "AccelerationX");
accelerometerCharacteristic_X.addDescriptor(accelerationXDescriptor);

But, I did not see any changes. So my question is how can I define the characteristic name?

Also what is the best way to send acceleration data? I need to send all X, Y, Z, but I will the processing them separately, so I created a characteristic for each, but I am not sure, it that is the best method.

I am reading the data at Pi using node.js.

You are posting snippets, so it is hard to help. Based on the posted info, do you know exactely what nodejs interprets as "name" in the posted json? Could it be a device name or an object name instead of what you expect it to be?

ArduinoBLE - 16bit UUID Numbers.

Hi @Danois90,

It is the characteristic name actually.

If I send temperature data using predefined UUIDs, temperature is written there.

So, I am pretty sure, it is a characteristic name.

You use Characteristic Descriptors to store a user-readable descriptions for a characteristic. For example, 0x2901 is used for the Characteristic User Description.

Hi @gerrikoio, so based on my post, why I did not see any changes?

Can you elaborate. I usually use the free nRFConnect Android app to test. What did you use?

As in, what code or command did you use with the Raspberry Pi.

I did a quick search online. Not sure if this is the Nodejs library you're using. I see they have a test for descriptors... @hkayann did you use this or something similar?

I am using my own npm package that I developed to read BLE data. The package depends on

@abandonware/noble.. I am using node-red as a platform.

My package is available in GitHub. Also you can install via npm as well.

Based on @Danois90 comment as well, it is better If I post more complete code I guess:

My code in Arduino (only related parts):

#define BLE_UUID_ACCELEROMETER_SERVICE            "1101"
#define BLE_UUID_ACCELEROMETER_X                  "2101"
#define BLE_DEVICE_NAME                           "Nano"
#define BLE_LOCAL_NAME                            "Nano"

BLEShortCharacteristic accelerometerCharacteristic_X( BLE_UUID_ACCELEROMETER_X, BLERead | BLENotify );
BLEDescriptor accelerationXDescriptor("2901", "AccelerationX");
// set advertised local name and service UUID
BLE.setDeviceName( BLE_DEVICE_NAME );
BLE.setLocalName( BLE_LOCAL_NAME );
BLE.setAdvertisedService( accelerometerService );
//Add Descriptors
accelerometerCharacteristic_X.addDescriptor(accelerationXDescriptor)
// BLE add characteristics
accelerometerService.addCharacteristic( accelerometerCharacteristic_X );
// add service
BLE.addService( accelerometerService );

The function I use to discover services and characteristics:
const ALL = await peripheralArray[index].discoverSomeServicesAndCharacteristicsAsync(serviceValues, characteristicValues).catch(e => send(e));

The one you linked is deprecated, has many issues etc. I use @abandonware/noble.

Based on the above code, there is no reason why you would not be able to see the 2901 descriptor. The best way to confirm is to use a BLE utility app, like nRFconnect. Once you've confirmed that your Arduino code is correct, then you could determine why the Node Red code is not working... from the look of things your nodejs function code to discover services and characteristics is missing the functions to extract the descriptor information.

See: Descriptor documentation section

There is an another function to extract the descriptor information. But, if I do that, I will still see null at character.name.

How you define the name of your custom characteristic using ArduinoBLE @gerrikoio? Using descriptors?

The variable name (such as accelerometerCharacteristic_X) is internal to your ArduinoBLE code:

BLEShortCharacteristic accelerometerCharacteristic_X( BLE_UUID_ACCELEROMETER_X, BLERead | BLENotify );

The UUID (BLE_UUID_ACCELEROMETER_X) however is exchanged with the central device once it has connected to the peripheral device.

To make this characteristic meaningful to any central device you create Descriptors (there are a number of different options available). This information is exchanged upon a read request.

I totally know all of these. Maybe this example will clarify my question in a better way.

If I use pre-defined characteristic like temperature:

#define BLE_UUID_TEMPERATURE                      "2A6E"
BLEShortCharacteristic temperatureCharacteristic( BLE_UUID_TEMPERATURE, BLERead | BLENotify );

This is what I read via node.js:
{"uuid":"2A6E","name":temperature...}
So here, characteristic name does exist already, without the need of further defining any descriptors.

But If I send my own custom characteristic, this is what I get:
{"uuid":"2101","name":null...}

So, my question is, how to setup that name so it will not be a null for custom characteristics.

What I understand from your comments, that is only possible with descriptors, hence, whatever I do, that place will be a null. I can only provide such an info with descriptor, which requires reading them.

If you look at the source code for noble, especially the characteristics.json file, it holds a table with name and type of selected characteristics and that is how noble knows that "Temperature" is the name for "2A6E".

I've only looked briefly, but I see nowhere that noble is fetching descriptor "2901" in order to use its value for the name of the characteristic it belongs to, which means that the problem is not in the Arduino end of your project.

2 Likes

I see, it is in descriptors.json., this confirms whatever we do in Arduino side, that thing will return null. Thanks @Danois90.

That source link is deprecated one. I am putting the correct source just in case.