Sending Data From Arduino portenta with ble in my phone

I ve made a thread before , when i was using esp32 , but decided to swap to portenta since esp32 was giving me fatal error in uploading and i had to spam the boot key all the time.
Anyway ,using portenta, i downloaded all neessary libs and currently using ArduinoBLE to send sensor data to my phone .

code is here:

/*
 
  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#define SERVICE_UUID        "my uuid here"
#define CHARACTERISTIC_UUID_TX "and here another one for the characteristic"
#define sensorvalue A0

BLEService ECGservice(SERVICE_UUID );


BLEUnsignedIntCharacteristic ECGchar( CHARACTERISTIC_UUID_TX, BLERead | BLENotify );


long previousMillis = 0;  

void setup() {
  Serial.begin(9600);    // initialize serial communication
  pinMode(10, INPUT); // Setup for leads off detection LO +
  pinMode(11, INPUT); // Setup for leads off detection LO -
  while (!Serial);


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

    while (1);
  }

  /* Set a local name for the BLE device
     This name will appear in advertising packets
     and can be used by remote devices to identify this BLE device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("Ecg Rose");
  BLE.setAdvertisedService(ECGservice); // add the service UUID
  ECGservice.addCharacteristic(ECGchar); // add the battery level characteristic
  BLE.addService(ECGservice); // Add the battery service
  ECGchar.writeValue(sensorvalue); // set initial value for this characteristic

  /* Start advertising BLE.  It will start continuously transmitting BLE
     advertising packets and will be visible to remote BLE central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:


    // while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        ECGchar.writeValue(analogRead(A0));
        Serial.println("sensor value : " + String(analogRead(A0)));

      }
    }
    // when the central disconnects, turn off the LED:
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

Problem , as u can see i have these two lines ECGchar.writeValue(analogRead(A0));
Serial.println("sensor value : " + String(analogRead(A0)));

this one ECGchar.writeValue(analogRead(A0)); is to send data , though it doesnt send anything when i got to services in NRF app value is N/A.

this one Serial.println("sensor value : " + String(analogRead(A0))); prints me nicely the values of analog0 .

Whats the problem ? My guess is i had to put this into a char array and dtostrf , but its integer , why it doesnt read it ??

Imgur

Does your ESP32 have Analog pins?

Kind regards, Zeb

UUID's are not just any strings they are 16-bit or 128-bit numbers.

16-bit UUID's are defined by the Bluetooth SiG. You should only use them when you implement a service and characteristic as defined by the Bluetooth SiG.

If you want to create your own service, you must use 128-bit random UUIDs. They should be truly random to ensure nobody else uses the same UUID's in their application.

You can write your own script or use a UUID generator online. This page here seems to work.

A few other things I noted:

You have an unsigned int characteristic and directly write the analogRead value into it. analogRead returns an int. You should cast the values.

The following two lines are not doing what you intend.

ECGchar.writeValue(analogRead(A0));
Serial.println("sensor value : " + String(analogRead(A0)));

It triggers analogRead twice. Which is slow and you have two different values. Read the values into a variable and use that.

I also would recommend using characteristic in the variable name. Char is misleading because it has been used for decades for characters. It might also allow you to use less comments. Your comments are out of sync with your code. e.g.

ECGservice.addCharacteristic(ECGchar); // add the battery level characteristic

The following is also wrong

ECGchar.writeValue(sensorvalue); // set initial value for this characteristic

You define sensorvalue and therefore it is a constant. The value is A0. What you want is.

ECGchar.writeValue( 0 ); // set initial value for this characteristic

Additionally, I would recommend you use CAPITAL_UNDERSCORE naming convention for constant values. e.g.

#define SENSOR_PIN A0

You could also define the other pins you used in setup

pinMode(10, INPUT); // Setup for leads off detection LO +
pinMode(11, INPUT); // Setup for leads off detection LO -

e.g.

#define LO_PLUS_PIN 10

pinMode( LO_PLUS_PIN, INPUT );

In loop you use the global variable previousMillis. I would recommend you define it inside loop() as a static variable. This will allow you to reuse the variable name in other functions and copy functions from one sketch to another without looking for all the global variables. Only variables used in multiple functions need to be defined globally.

static unsigned long previousMillis = 0;

So first thing is to generate a correct UUID from the link.
I tried changing from Unsigned characteristic to just BLECharacteristic so i dont have to type cast an int to unsigned int, and i got compilation errors .
So anyway step 2 : Type cast analogRead(A0) to like uint8_t reading = analogRead(A0) ?? and use this .
step 3 : ECGchar.writeValue( 0 ); // set initial value for this characteristic.

I dont know if it has to do anything with this but , sensor reads int data in in ms , so can the BLE send all this data to a phone without losing any ?
Shall i add delay other than the one i have ?

I want to publish all this data i am getting to Thingspeak from my mobile app and the mobile app will get the values from arduino .

I really appreciate the help.

getsomehate:
I tried changing from Unsigned characteristic to just BLECharacteristic so i dont have to type cast an int to unsigned int, and i got compilation errors .

Just use a BLEIntCharacteristic. The BLECharacteristic needs a size. That's why you get an error.

getsomehate:
uint8_t reading = analogRead(A0) ??

uint8_t type is too small. Only 8-bit.

getsomehate:
I dont know if it has to do anything with this but , sensor reads int data in in ms , so can the BLE send all this data to a phone without losing any ?

The BLE stands for low energy. The protocol was designed for small amounts of data. Getting the most amount of data requires you to create a compound characteristic, so you can combine multiple values in one.

getsomehate:
Shall i add delay other than the one i have ?

You shall not use delay. :slight_smile: Delay is a function that you should avoid at any cost. On the Arduino Nano 33 BLE it will use sleep mode and could be used for power saving. But in general it is a waste of processing cycles.
Use the millis() function for timing your application. You already used it. Just create more variables to store previous millis values. Give them nice names.

Feel free to post your updated code.

I also recommend you have a look trough the Arduino Nano 33 BLE and IoT forum. There are examples I have written in some of them and other information you might find useful.

Nano Boards (NEW types)

Update :

Did everything mentioned Above and code looks like this :

/*

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#define SERVICE_UUID        "generated from link"
#define CHARACTERISTIC_UUID_TX "generated from link"
#define SENSOR_PIN A0
#define LO_PLUS_PIN 10
#define LO_PLUS_MIN 11

BLEService ECGservice(SERVICE_UUID );


BLEIntCharacteristic ECGchar( CHARACTERISTIC_UUID_TX, BLERead | BLENotify );

int Value = analogRead(A0);
static unsigned long previousMillis = 0;

void setup() {
  Serial.begin(9600);    // initialize serial communication
  pinMode(LO_PLUS_PIN, INPUT); // Setup for leads off detection LO +
  pinMode(LO_PLUS_MIN, INPUT); // Setup for leads off detection LO -
  while (!Serial);


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

    while (1);
  }

  /* Set a local name for the BLE device
     This name will appear in advertising packets
     and can be used by remote devices to identify this BLE device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("Ecg Rose");
  BLE.setAdvertisedService(ECGservice); // add the service UUID
  ECGservice.addCharacteristic(ECGchar); // add the ecg  characteristic
  BLE.addService(ECGservice); // Add the battery service
  ECGchar.writeValue( 0 ); // set initial value for this characteristic
  /* Start advertising BLE.  It will start continuously transmitting BLE
     advertising packets and will be visible to remote BLE central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:


    // while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        ECGchar.writeValue(Value);
        Serial.println(Value);

      }
    }
    // when the central disconnects, turn off the LED:
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

the output on my serial monitor is :

10:30:50.402 -> 460
10:30:50.607 -> 460
10:30:50.813 -> 460
10:30:50.982 -> 460
10:30:51.184 -> 460
10:30:51.388 -> 460
10:30:51.591 -> 460
10:30:51.795 -> 460
10:30:51.997 -> 460
10:30:52.198 -> 460
10:30:52.398 -> 460

which is probably due to very bad Sensor , or ECG electrodes not hooked up correctly.

But when i log and connect with Bluetooth , in services , value sent is still N/A.

all i wanna know is if this code is correct and sends data , so i can start fixing my APK file for mobile app and read value from there.

NOTICE : when i swapped Serial.println(Value); with Serial.println(analogRead(A0) );
Serial plotter plots a nice ECG but with Value its the same thing though.

getsomehate:
Update :

Did everything mentioned Above and code looks like this :

/*

This example code is in the public domain.
*/

#include <ArduinoBLE.h>
#define SERVICE_UUID        "generated from link"
#define CHARACTERISTIC_UUID_TX "generated from link"
#define SENSOR_PIN A0
#define LO_PLUS_PIN 10
#define LO_PLUS_MIN 11

BLEService ECGservice(SERVICE_UUID );

BLEIntCharacteristic ECGchar( CHARACTERISTIC_UUID_TX, BLERead | BLENotify );

int Value = analogRead(A0);
static unsigned long previousMillis = 0;

void setup() {
  Serial.begin(9600);    // initialize serial communication
  pinMode(LO_PLUS_PIN, INPUT); // Setup for leads off detection LO +
  pinMode(LO_PLUS_MIN, INPUT); // Setup for leads off detection LO -
  while (!Serial);

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

while (1);
  }

/* Set a local name for the BLE device
    This name will appear in advertising packets
    and can be used by remote devices to identify this BLE device
    The name can be changed but maybe be truncated based on space left in advertisement packet
  /
  BLE.setLocalName("Ecg Rose");
  BLE.setAdvertisedService(ECGservice); // add the service UUID
  ECGservice.addCharacteristic(ECGchar); // add the ecg  characteristic
  BLE.addService(ECGservice); // Add the battery service
  ECGchar.writeValue( 0 ); // set initial value for this characteristic
  /
Start advertising BLE.  It will start continuously transmitting BLE
    advertising packets and will be visible to remote BLE central devices
    until it receives a new connection */

// start advertising
  BLE.advertise();

Serial.println("Bluetooth device active, waiting for connections...");
}

void loop() {
  // wait for a BLE central
  BLEDevice central = BLE.central();

// if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:

// while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        ECGchar.writeValue(Value);
        Serial.println(Value);

}
    }
    // when the central disconnects, turn off the LED:
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}






the output on my serial monitor is :



10:30:50.402 -> 460
10:30:50.607 -> 460
10:30:50.813 -> 460
10:30:50.982 -> 460
10:30:51.184 -> 460
10:30:51.388 -> 460
10:30:51.591 -> 460
10:30:51.795 -> 460
10:30:51.997 -> 460
10:30:52.198 -> 460
10:30:52.398 -> 460



which is probably due to very bad Sensor , or ECG electrodes not hooked up correctly.

But when i log and connect with Bluetooth , in services , value sent is still N/A but the value above is looking like : 0xE1-01-00-00 ETC , changing every time 

all i wanna know is if this code is correct and sends data , so i can start fixing my APK file for mobile app and read value from there.


NOTICE : when i swapped Serial.println(Value); with Serial.println(analogRead(A0) );
Serial plotter plots a nice ECG but with Value its the same thing though.

The issue is that you are not updating the sensor value.

#define ECG_SENSOR_INTERVALL 200

while ( central.connected() ) 
{
  long currentMillis = millis();
  if ( currentMillis - previousMillis >= ECG_SENSOR_INTERVALL ) 
  {
    previousMillis = currentMillis;

    int ecgSensorValue = analogRead( ECG_SENSOR_PIN );
    ECGchar.writeValue( ecgSensorValue );
    Serial.println( ecgSensorValue );
  }
}

I added a few suggestions to make the code easier to read.

  • define a constant for the interval with the name related to the reason for the value
  • make the ecgSensorValue variable local. It is only used inside loop. No reason for a global variable for now.
  • rename the Value variable so it is obvious, this allows spotting bugs better and you can extend the code without value1, value2 ...
  • you defined the pin, lets make use of the define in the analogRead :slight_smile:

Thnx a lot for adding to my code , I tried declare a clear int value that would read from
Sensor pin which is A0 , and I was getting same values .
With just analog read it was perfect but now the code is more of an example
Of how a code should be .
Thing is on my nRF app on services , I can see it sends values but it reads them with something like Unicode . E.g 0xE1-01-00-00 .
Now
If that’s the right way then I am fine by it , but I want to upload this values to iot platform via phone app and download the embedded graph .
Will this type of value be readable , or do I need to convert something ?

getsomehate:
Thing is on my nRF app on services , I can see it sends values but it reads them with something like Unicode . E.g 0xE1-01-00-00 .

Its not unicode. It is the 4 bytes (32-bit integer) written as hexadecimal values. 0x is the prefix for printing hexadecimal values. e.g 0x10 is not 10

getsomehate:
Will this type of value be readable , or do I need to convert something ?

That is what the UUIDs are for. When you read the characteristic you get the 16-bit or 128-bit UUID and in your case the 4 bytes. For 16-bit UUIDs you can search the documents on the Bluetooth SiG web page. For 128-bit UUIDs you need to tell the developer of the app what the UUID is and how the data is represented. Your app just shows you the raw data because it does not know your UUID.

I made a very simple
Mobile app , this means I have to enter my uuid on it when I read data from
Bluetooth ??
I will check the Sig web page as u said Klaus and then come back .
Thanks a lot.

I ve managed to connect to phone with my mobile App ,and i am uploading To my thingspeak Channel via APP.

I get 0 readings though , any idea ? i am saving the Hex values to Strings with the App and upload them to thingspeak .

Edit: Shall i try and convert em to Json ?
I havent understood the value iam sending to Thingspeak

getsomehate:
I get 0 readings though , any idea ? i am saving the Hex values to Strings with the App and upload them to thingspeak .

You need to convert the 4 bytes into a 32-bit integer value in your App. When you get the correct number you can continue with the thingspeak.

How do you write the code for the App? Are you creating an Android or iOS app?

What protocols are you using to send the data to thingspeak?

Its an android app .
Still prototyping so using ai2 and i follow the standard HTTP protocol for Thingspeak to write a value to a specific field.
I want to see first that the app is working like that and then jump to android studio.

And i still have no idea how to convert this 4byte to a 32bit integer.

Shall i convert sensor readings to bytes ?

Or maybe if i convert readings to string and then seperate them inside the app ?

getsomehate:
And i still have no idea how to convert this 4byte to a 32bit integer.

Don't give up. :slight_smile: There are multiple ways to do it in C/C++. Google "convert bytes to int".

getsomehate:
Shall i convert sensor readings to bytes ?

No, if AI2 is any good you should be able to do that. I have not used AI2. I have only seen pictures of blocks on the web page. Can you actually write code as well? What programming language is used?

getsomehate:
Or maybe if i convert readings to string and then seperate them inside the app ?

Nope.

Ai2 is unusually good .
It’s blockly language or something like that , but it’s based in Java . It has powerful
Extensions and it can read bytes or whatever as well . Very nice tool
If you wanna make an app fast and try it

Ok i need to send data from arduino as strings and then i can read the string as int with my phone app.

i tried

      EcgValue = analogRead(SENSOR_PIN);
      long currentMillis = millis();
      // Let's convert the value to a char array:
      char txString[4]; // make sure this is big enuffz
      dtostrf(EcgValue, 1, 2, txString); // int_val, min_width, digits_after_decimal, char_buffer


      if (currentMillis - previousMillis >= 200) {
        previousMillis = currentMillis;
        ECGchar.writeValue(txString);
        Serial.println(txString));

but dtostrf says its not declared in the scope , i guess i am missing a lib which i cant find .