Transfer multiple data to App Inventor via BLE

Hello,

I am trying to multiple data from 33ble to App Inventor via BLE. I searched for references, only found samples for single data transfer like only accel_x. I want to transfer all accel, gyro and mag data at high frequency. Would anyone please let me know how to modify my code and App Inventor?

#include <Arduino_LSM9DS1.h>
#include <ArduinoBLE.h>

BLEService gyroService("180F");
BLEFloatCharacteristic accelxLevelChar("2A11", BLERead | BLEWrite);
//BLEFloatCharacteristic accelyLevelChar("2A12", BLERead | BLEWrite);
//BLEFloatCharacteristic accelzLevelChar("2A13", BLERead | BLEWrite);
//BLEFloatCharacteristic gyroxLevelChar("2A14", BLERead | BLEWrite);
//BLEFloatCharacteristic gyroyLevelChar("2A15", BLERead | BLEWrite);
//BLEFloatCharacteristic gyrozLevelChar("2A16", BLERead | BLEWrite);
//BLEFloatCharacteristic magxLevelChar("2A17", BLERead | BLEWrite);
//BLEFloatCharacteristic magyLevelChar("2A18", BLERead | BLEWrite);
//BLEFloatCharacteristic magzLevelChar("2A19", BLERead | BLEWrite);

void setup() {
 Serial.begin(9600);
 if (!IMU.begin()) { //LSM9DS1 check
   Serial.println("LSM9DS1 error!");
   while (1);
 }
 if (!BLE.begin()) {
   Serial.println("BLE error!");
   while (1);
 }
 // set advertised local name and service UUID:
 BLE.setAdvertisedService(gyroService); // add the service UUID
 gyroService.addCharacteristic(accelxLevelChar);
 //gyroService.addCharacteristic(accelyLevelChar);
 //gyroService.addCharacteristic(accelzLevelChar);
 //gyroService.addCharacteristic(gyroxLevelChar);
 //gyroService.addCharacteristic(gyroyLevelChar);
 //gyroService.addCharacteristic(gyrozLevelChar);
 //gyroService.addCharacteristic(magxLevelChar);
 //gyroService.addCharacteristic(magyLevelChar);
 //gyroService.addCharacteristic(magzLevelChar);
 BLE.addService(gyroService);
 // start advertising
 BLE.setLocalName("gyro");
 // start advertising
 BLE.advertise();
}

float accel_x, accel_y, accel_z;
//float gyro_x, gyro_y, gyro_z;
//float mag_x, mag_y, mag_z;
//long previousMillis = 0;  // last time the gyro level was checked, in ms

void updategyroLevel() {
 if (IMU.accelerationAvailable()) {
   IMU.readAcceleration(accel_x, accel_y, accel_z);
   accelxLevelChar.writeValue(accel_x);
//   accelyLevelChar.writeValue(accel_y);
//   accelzLevelChar.writeValue(accel_z);
 }
// if (IMU.gyroscopeAvailable()) {
//   IMU.readGyroscope(gyro_x, gyro_y, gyro_z);
//   gyroxLevelChar.writeValue(gyro_x);
//   gyroyLevelChar.writeValue(gyro_y);
//   gyrozLevelChar.writeValue(gyro_z);
// }
// if (IMU.magneticFieldAvailable()) {
//   IMU.readMagneticField(mag_x, mag_y, mag_z);
//   magxLevelChar.writeValue(mag_x);
//   magyLevelChar.writeValue(mag_y);
//   magzLevelChar.writeValue(mag_z);
// }
}

void loop() {
 // listen for BLE peripherals to connect:
 BLEDevice central = BLE.central();
 // if a central is connected to peripheral:
 if (central) {
   while (central.connected()) {
       updategyroLevel();
       delay(100);
     }
   }
}

Sung

Most of the code you have does what you need it to do. There is one thing you need to understand. In BLE you do not send data to somebody, but you store the data in a structure called the GATT and someone can connect to your server and read the data. So, there are two points that define the data update rate. One is the server which updates the data at a specific rate, and one is the client. It can choose to read the data at what rate it wants. Of course, this cannot be faster than the server update rate.

To help your client find out when the data is updated you can use the Notify feature for the characteristic.

BLEFloatCharacteristic accelxLevelChar("2A11", BLERead | BLENotify);

Just change that for your characteristics and uncomment the other values. I tested your sketch with all 3 axis.

Note: You should not use short UUIDs unless you looked up the value on the Bluetooth website. For custom UUID you should use random 128bit values. I use defines to make sure I do not need to write the numbers more than once.

For instance, 0x180F is reserved for battery service.

Thank you, I got it. How can I add multiple characteristics in App Inventor?

I have not worked with App Inventor. I have only seen an example on the appinventor web page. I guess you will need to duplicate the blocks and change the UUID.

I also found a post in the appinventor community that might help. Its for multiple connections, so multiple characteristics should be easy.

I made it like this. It shows all data in the serial print out screen. But something's wrong with BLEStringCharacteristic to send them through BLE.

#include <Arduino_LSM9DS1.h>
#include <ArduinoBLE.h>

BLEService gyroService("0000480f-0000-1000-8000-00805f9b34fb");
BLEStringCharacteristic LevelChar("00002a11-0000-1000-8000-00805f9b34fb", BLERead | BLENotify);

void setup() {
  Serial.begin(9600);
  if (!IMU.begin()) { //LSM9DS1 begin
    Serial.println("LSM9DS1 error!");
    while (1);
  }
  if (!BLE.begin()) {
    Serial.println("BLE error!");
    while (1);
  }
  // set advertised local name and service UUID:
  BLE.setAdvertisedService(gyroService); // add the service UUID
  gyroService.addCharacteristic(LevelChar);
  BLE.addService(gyroService);
  // start advertising
  BLE.setLocalName("gyro");
  // start advertising
  BLE.advertise();
}

float ac_x, ac_y, ac_z;
float gy_x, gy_y, gy_z;
float ma_x, ma_y, ma_z;
String Level_String;

void updategyroLevel() {
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(ac_x, ac_y, ac_z);
    Level_String="ST, "+String(ac_x,3)+", "+String(ac_y,3)+", "+String(ac_z,3);
  }
  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gy_x, gy_y, gy_z);
    Level_String+=", "+String(gy_x,3)+", "+String(gy_y,3)+", "+String(gy_z,3);
  }
  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(ma_x, ma_y, ma_z);
    Level_String+=", "+String(ma_x,3)+", "+String(ma_y,3)+", "+String(ma_z,3)+", EN";
  }
  LevelChar.writeValue(Level_String);
//  Serial.println(Level_String);
}

void loop() {
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();
  // if a central is connected to peripheral:
  if (central) {
    while (central.connected()) {
        updategyroLevel();
        delay(50);
      }
    }
}

And my App Inventor code to parse data from Arduino is like attached.

The issue is that the BLEStringCharacteristic only works with fixed length Strings. The following small change will fix the issue. I checked it on my smartphone and can see the data updating. You will need to check whether the AppInventor stuff works.

BLEStringCharacteristic LevelChar("00002a11-0000-1000-8000-00805f9b34fb", BLERead | BLENotify, 40);

Thank you.

I can send the string data to App Inventor. But the frequency of receiving data was less than 5 herz as follow. And there were corrupted data like additional dot or loss of dot. I don't know why [" and "] were added.

Klaus_K, do you mean you could get the data at high frequency without loss? Then, I have to consider using coding tools other than App Inventor.

Saved data by App Inventor at the 10 millisecond interval.
(millisecond : 9 data)

1583639352447 : ["-0.215,0.850,-0.450,-0.977,-1.282,0.061,-45.276,1.868,-80.347"]
1583639352761 : ["-0.216,0.853,-0.452,-0.793,-0.977,0.061,-45..739,1.868,-79.358"]
1583639353030 : ["-0.215,0.851,-0.450,-0.038,-0.977,0.000,-45..397,1.453,-80.383"]
1583639353301 : ["-0.215,0.851,-0.450,-0.854,-1.099,0.122,-44..592,1.379,-80.298"]
1583639353571 : ["-0.214,0.850,-0.450,-0.793,-1.038,0.122,-45.496,1.587,-80.505"]
1583639353840 : ["-0.215,0.851,-0.451,-0.793,-1.038,-0.061,-45.239,1.892,-80.994"]
1583639354111 : ["-0.215,0.852,-0.451,-0.793,-1.038,0.000,-44.642,1.611,-80.347"]
1583639354381 : ["-0.216,0.852,-0.453,-1.977,-0.977,0.000,-44..520,1.233,-80.920"]
1583639354651 : ["-0.215,0.850,-0.451,-0.916,-1.160,-0.122,-45251,0.928,-81.506"]
1583639354966 : ["-0.215,0.851,-0.451,-0.732,-0.916,-0.061,-45483,1.257,-80.933"]
1583639355235 : ["-0.216,0.852,-0.451,-0.610,-1.038,-0.122,-45995,1.074,-80.249"]
1583639355506 : ["-0.215,0.850,-0.450,-0.854,-1.221,0.000,-45..056,1.001,-80.603"]
1583639355775 : ["-0.215,0.850,-0.450,-0.793,-1.099,-0.061,-45.922,1.025,-80.981"]
1583639356045 : ["-0.214,0.851,-0.451,-0.671,-1.099,-0.061,-45398,1.489,-80.286"]

Arduino code is as follow.

#include <Arduino_LSM9DS1.h>
#include <ArduinoBLE.h>

BLEService gyroService("0000480f-0000-1000-8000-00805f9b34fb");
BLEStringCharacteristic LevelChar("00002a11-0000-1000-8000-00805f9b34fb", BLERead | BLENotify,100);

void setup() {
  Serial.begin(9600);
  if (!IMU.begin()) { //LSM9DS1 begin
    Serial.println("LSM9DS1 error!");
    while (1);
  }
  if (!BLE.begin()) {
    Serial.println("BLE error!");
    while (1);
  }
  // set advertised local name and service UUID:
  BLE.setAdvertisedService(gyroService); // add the service UUID
  gyroService.addCharacteristic(LevelChar);
  BLE.addService(gyroService);
  // start advertising
  BLE.setLocalName("gyro");
  // start advertising
  BLE.advertise();
}

float ac_x, ac_y, ac_z;
float gy_x, gy_y, gy_z;
float ma_x, ma_y, ma_z;
String Level_String;

void updategyroLevel() {
  if (IMU.accelerationAvailable()) {
    IMU.readAcceleration(ac_x, ac_y, ac_z);
  }
  if (IMU.gyroscopeAvailable()) {
    IMU.readGyroscope(gy_x, gy_y, gy_z);
  }
  if (IMU.magneticFieldAvailable()) {
    IMU.readMagneticField(ma_x, ma_y, ma_z);
  }
  Level_String=String(ac_x,3)+","+String(ac_y,3)+","+String(ac_z,3)+","+String(gy_x,3)+","+String(gy_y,3)+","+String(gy_z,3)+","+String(ma_x,3)+","+String(ma_y,3)+","+String(ma_z,3);
//  Level_String+=","+String(gy_x,3)+","+String(gy_y,3)+","+String(gy_z,3);
//  Level_String+=","+String(ma_x,3)+","+String(ma_y,3)+","+String(ma_z,3);
  LevelChar.writeValue(Level_String);
//  Serial.println(Level_String);
}

void loop() {
  // listen for BLE peripherals to connect:
  BLEDevice central = BLE.central();
//  updategyroLevel();
//  delay(50);
  // if a central is connected to peripheral:
  if (central) {
    while (central.connected()) {
        updategyroLevel();
//        delay(100);
      }
    }
}

The BLE Scanner App on my iPhone seems to be updating faster than 5Hz.

I have setup a second Arduino Nano 33 BLE and read the data from your first code wit the 50ms delay. The code counts the number of notifications per second and prints them on the Serial Monitor. I get 17 messages per second consistently. Here is an output example. This seems consistent. 17 x 50ms is 850ms. The rest of the time is used by the application to prepare the data and store it in the BLE module.

05:10:32.049 -> Count: 17
05:10:32.049 -> ST, 0.027, -0.007, 1.016, 0.305, 0.000, 0.916, 27.075, -4.321, -53.406, EN
05:10:32.142 -> ST, 0.027, -0.006, 1.014, 0.122, -0.122, 0.916, 27.014, -4.639, -54.260, EN
05:10:32.189 -> ST, 0.027, -0.007, 1.016, 0.366, 0.000, 0.977, 27.576, -4.651, -54.968, EN
05:10:32.236 -> ST, 0.027, -0.008, 1.017, 0.305, -0.061, 0.977, 27.356, -4.724, -53.601, EN
05:10:32.283 -> ST, 0.027, -0.008, 1.018, 0.183, 0.183, 1.099, 27.271, -4.797, -53.735, EN
05:10:32.377 -> ST, 0.027, -0.008, 1.016, 0.305, -0.061, 0.854, 27.612, -4.578, -54.248, EN
05:10:32.424 -> ST, 0.026, -0.008, 1.016, 0.366, 0.000, 0.977, 27.808, -4.700, -55.566, EN
05:10:32.470 -> ST, 0.027, -0.006, 1.016, 0.244, 0.000, 1.038, 27.222, -5.127, -54.102, EN
05:10:32.517 -> ST, 0.027, -0.008, 1.016, 0.427, 0.061, 1.038, 27.795, -4.419, -53.882, EN
05:10:32.564 -> ST, 0.027, -0.008, 1.016, 0.305, 0.000, 1.038, 27.112, -4.431, -54.175, EN
05:10:32.658 -> ST, 0.027, -0.008, 1.015, 0.183, -0.061, 1.038, 27.124, -5.725, -55.957, EN
05:10:32.705 -> ST, 0.026, -0.007, 1.016, 0.244, -0.183, 0.916, 27.112, -4.846, -53.137, EN
05:10:32.752 -> ST, 0.027, -0.007, 1.015, 0.305, -0.122, 0.916, 26.929, -5.139, -53.137, EN
05:10:32.845 -> ST, 0.027, -0.007, 1.015, 0.305, -0.122, 1.099, 27.625, -4.736, -54.016, EN
05:10:32.892 -> ST, 0.027, -0.008, 1.015, 0.305, -0.061, 0.977, 27.271, -4.578, -53.589, EN
05:10:32.939 -> ST, 0.027, -0.008, 1.015, 0.244, 0.122, 0.977, 27.039, -4.883, -54.272, EN
05:10:32.986 -> ST, 0.026, -0.008, 1.014, 0.061, 0.000, 0.854, 27.393, -4.944, -53.333, EN
05:10:33.033 -> ST, 0.026, -0.007, 1.014, 0.122, -0.061, 0.977, 27.625, -4.700, -54.309, EN
05:10:33.127 -> Count: 17
05:10:33.127 -> ST, 0.026, -0.008, 1.016, 0.427, -0.122, 0.977, 27.832, -5.029, -54.187, EN
05:10:33.173 -> ST, 0.026, -0.008, 1.016, 0.122, -0.061, 0.916, 27.087, -4.675, -52.832, EN
05:10:33.220 -> ST, 0.026, -0.007, 1.016, 0.183, -0.061, 0.977, 27.612, -4.614, -54.846, EN
05:10:33.267 -> ST, 0.026, -0.006, 1.015, 0.183, 0.000, 1.038, 27.368, -4.736, -54.773, EN
05:10:33.361 -> ST, 0.026, -0.007, 1.016, 0.305, 0.000, 0.977, 27.283, -5.090, -53.589, EN
05:10:33.408 -> ST, 0.026, -0.007, 1.016, 0.244, -0.061, 0.977, 27.490, -4.944, -54.675, EN
05:10:33.455 -> ST, 0.026, -0.007, 1.015, 0.305, 0.000, 0.977, 27.148, -4.651, -53.931, EN
05:10:33.501 -> ST, 0.027, -0.007, 1.017, 0.122, 0.000, 1.038, 27.576, -4.077, -54.199, EN
05:10:33.548 -> ST, 0.026, -0.007, 1.016, 0.183, -0.061, 1.038, 27.002, -4.932, -54.297, EN
05:10:33.642 -> ST, 0.026, -0.007, 1.016, 0.305, 0.183, 0.977, 27.148, -5.212, -55.310, EN
05:10:33.689 -> ST, 0.026, -0.007, 1.015, 0.244, 0.061, 0.977, 27.063, -4.565, -54.883, EN
05:10:33.736 -> ST, 0.026, -0.007, 1.016, 0.183, 0.061, 0.977, 26.941, -5.286, -54.846, EN
05:10:33.783 -> ST, 0.027, -0.007, 1.015, 0.366, 0.122, 0.916, 27.612, -4.651, -53.857, EN
05:10:33.876 -> ST, 0.027, -0.007, 1.015, 0.244, 0.061, 0.793, 27.454, -5.273, -54.956, EN
05:10:33.923 -> ST, 0.027, -0.007, 1.016, 0.244, -0.061, 1.160, 27.356, -4.944, -53.760, EN
05:10:33.970 -> ST, 0.028, -0.007, 1.017, 0.061, 0.122, 1.038, 27.075, -5.200, -54.199, EN
05:10:34.064 -> ST, 0.026, -0.007, 1.016, 0.366, 0.000, 1.099, 26.917, -4.736, -54.663, EN
05:10:34.111 -> ST, 0.026, -0.008, 1.016, 0.488, 0.061, 0.977, 26.892, -4.688, -54.956, EN
05:10:34.158 -> Count: 17

I got the almost same sampling rate using nRF Connect App on my Android phone.

Thank you so much, Klaus_K.