Nano 33 IOT ArduinoBle - send data to mobile

Hi

Currently I can connect to the Arduino from the mobile and send data, but how can i send it back to the mobile. Forgetting the mobile side of things.

So here is some of my code:

BLEUnsignedCharCharacteristic buttonCharacteristic(“2102”, BLERead | BLEWrite | BLENotify);

// handle Characteristic Written Handler
buttonCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
// central wrote new value to characteristic, see if care, etc.
Serial.print("Characteristic event, written: ");
Serial.println(characteristic.uuid());
// see if this is the Button Characteristic
if (characteristic.uuid() == “2102”)
{
characteristic.readValue(buttonValue);
Serial.print("new value ");
Serial.println(buttonValue);
if (buttonValue == 1)
{
delay(500);

  buttonCharacteristic.writeValue(1);   //Send data to mobile??????
}

}
}

Thanks

Please post your complete code and use code tags. Use the </> button to get the right tag characters inserted for you. Your code should look like this.


// Example code

uint32_t variable = 0; // with automatic syntax highlighting.

Also try Tools → Auto Format in the Arduino IDE to get proper code indentation.

A few points about BLE:

  • In BLE there are two sides. One is called peripheral or server. This is usually a low power device without a screen. The other side is called central or client. This side is often more powerful e.g. a smartphone or tablet, but can also be an Arduino.

  • The peripheral provides the data and sets the access rules ( Read, Write, Notify …).

  • The client decides what data it is interested in, at what time and how often it wants to access the data. The peripheral has no say it that. It can only notify the client that the data has changed but the client can ignore that.

  • So, you cannot send data to a phone. You update the characteristic using write(). When you use notify, the phone can describe to that and read the data when the data changes.

About your code:

  • Communication stacks really do not work together with delay(). delay() is a bad software practice in general and should be avoided. Have a look at the following example to learn how to time parts of your code.

File → Examples → 02.Digital → BlinkWithoutDelay

  • You use button and switch. Do you mean two different things, or did you just mix it up?

  • You use 16-bit UUID. They are reserved for services and characteristics defined by the Bluetooth SiG. For your self-defined services and characteristics, you must use 128-bit random UUIDs.

Here is the full code listing:

<
#include <ArduinoBLE.h>

// create a service to expose our service to BLE Central Devices
BLEService garageDoorService(“fa01”);

BLEUnsignedCharCharacteristic buttonCharacteristic(“2102”, BLERead | BLEWrite | BLENotify);

byte buttonValue = 0x00;
int commandIterations = 0;

#define BUTTONSWITCHPIN 10

void setup() {
Serial.begin(9600);
while (!Serial);

pinMode(BUTTONSWITCHPIN, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
if (!BLE.begin())
{
Serial.println(“starting BLE failed!”);
while (1);
}

String address = BLE.address();
Serial.println(“Our address is [” + address + “]”);

BLE.setDeviceName(“IBM Garage Opener”); // this sets Characteristic 0x2a00 of Service 0x1800
// Service 0x1800 is the Generic Access Profile
// Characteristic 0x2a00 is the Device Name
// Characteristic 0x2a01 is the “Appearance”
BLE.setAppearance(384); // BLE_APPEARANCE_GENERIC_REMOTE_CONTROL

BLE.setLocalName(“BLE Garage Opener”); // this sets the local name for the advertising data

// tell the world about us
BLE.setAdvertisedService(garageDoorService);
garageDoorService.addCharacteristic(buttonCharacteristic);
BLE.addService(garageDoorService);

buttonCharacteristic.writeValue(buttonValue); // start with a zero

// advertise to the world so we can be found
BLE.advertise();

Serial.println(“Bluetooth device active, waiting for connections…”);

// register new connection handler
BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);

// registeer disconnect handler
BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

// handle Characteristic Written Handler
buttonCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
// central wrote new value to characteristic, see if care, etc.
Serial.print("Characteristic event, written: ");
Serial.println(characteristic.uuid());
// see if this is the Button Characteristic
if (characteristic.uuid() == “2102”)
{
characteristic.readValue(buttonValue);
Serial.print("new value ");
Serial.println(buttonValue);
if (buttonValue == 1)
{
digitalWrite(BUTTONSWITCHPIN, HIGH);
delay(500);
commandIterations++;
buttonCharacteristic.writeValue(1); // <<<<<<< here is what i think should be sending the value 1 to the mobile???
}
digitalWrite(BUTTONSWITCHPIN, LOW);
}
}

void blePeripheralConnectHandler(BLEDevice central) {
// central connected event handler
Serial.print("Connected event, central: ");
Serial.println(central.address());
digitalWrite(LED_BUILTIN, HIGH); // indicate that we have a connection
digitalWrite(BUTTONSWITCHPIN, LOW); // make sure our button is NOT pressed
}

void blePeripheralDisconnectHandler(BLEDevice central) {
// central disconnected event handler
Serial.print("Disconnected event, central: ");
Serial.println(central.address());
digitalWrite(LED_BUILTIN, LOW); // indicate that we no longer have a connection
digitalWrite(BUTTONSWITCHPIN, LOW); // make sure our button is NOT pressed
}

void loop()
{
BLEDevice central = BLE.central();

if (central)
{
while (central.connected()) {

  if (buttonCharacteristic.written()) {
    Serial.println("changed");

  }


  if (scaledValueChar.valueUpdated())
  {
    Serial.println("changed");
  }
  delay(200);
}

}
}

/>

Can you please enclose the code with code tags. Click on the </> button and do not use the characters. The button will give you three ` characters twice and tell you where to paste the code. You should see this in the browser window.

```
type or paste code here
```

Right now the code does not compile because it has a lot of invisible characters from the new forum formatting inside. When you use the code tags the code can be copied without issues.

You can modify your post #3. After you update, it should look just like what I described before.

#include <ArduinoBLE.h>

// create a service to expose our service to BLE Central Devices
BLEService garageDoorService("fa01");

BLEUnsignedCharCharacteristic buttonCharacteristic("2102", BLERead | BLEWrite | BLENotify);


byte buttonValue = 0x00;
int commandIterations = 0;

#define  BUTTONSWITCHPIN 10

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(BUTTONSWITCHPIN, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  if (!BLE.begin())
  {
    Serial.println("starting BLE failed!");
    while (1);
  }

  String address = BLE.address();
  Serial.println("Our address is [" + address + "]");

  BLE.setDeviceName("IBM Garage Opener");      // this sets Characteristic 0x2a00 of Service 0x1800
  // Service 0x1800 is the Generic Access Profile
  // Characteristic 0x2a00 is the Device Name
  // Characteristic 0x2a01 is the "Appearance"
  BLE.setAppearance(384);                      // BLE_APPEARANCE_GENERIC_REMOTE_CONTROL

  BLE.setLocalName("BLE Garage Opener");       // this sets the local name for the advertising data

  // tell the world 
  BLE.setAdvertisedService(garageDoorService);
  garageDoorService.addCharacteristic(buttonCharacteristic);
  BLE.addService(garageDoorService);

  buttonCharacteristic.writeValue(buttonValue);      // start with a zero

  // advertise to the world so we can be found
  BLE.advertise();

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

  // register new connection handler
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);

  // registeer disconnect handler
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // handle Characteristic Written Handler
  buttonCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, see if care, etc.
  Serial.print("Characteristic event, written: ");
  Serial.println(characteristic.uuid());
  // see if this is the Button Characteristic
  if (characteristic.uuid() == "2102")
  {
    characteristic.readValue(buttonValue);
    Serial.print("new value ");
    Serial.println(buttonValue);
    if (buttonValue == 1)                                
    {
      digitalWrite(BUTTONSWITCHPIN, HIGH);
      delay(500);
      commandIterations++;
      buttonCharacteristic.writeValue(1);		// <<<<<<< here is what i think should be sending the value 1 to the mobile??????
    }
    digitalWrite(BUTTONSWITCHPIN, LOW);
  }
}

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
  digitalWrite(LED_BUILTIN, HIGH);    // indicate that we have a connection
  digitalWrite(BUTTONSWITCHPIN, LOW);         //  make sure our button is NOT pressed
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
  digitalWrite(LED_BUILTIN, LOW);     // indicate that we no longer have a connection
  digitalWrite(BUTTONSWITCHPIN, LOW);         //  make sure our button is NOT pressed
}

void loop()
{
  BLEDevice central = BLE.central();

  if (central)
  {
    while (central.connected()) {

      if (buttonCharacteristic.written()) {
        Serial.println("changed");

      }


      if (scaledValueChar.valueUpdated())
      {
        Serial.println("changed");
      }
      delay(200);
    }
  }
}

Thanks for posting the code with tags.

I did a few modifications to your sketch because it did not compile. scaledValueChar was not defined. Looking at the code I realized you do not need any of the code you placed in loop(). All you need to do is call BLE.poll() on a regular basis. I chose 2ms interval for now.

#include <ArduinoBLE.h>

// create a service to expose our service to BLE Central Devices
BLEService garageDoorService( "fa01" ); // you must not use 16-bit UUIDs for custom services, use 128-bit random UUIDs

BLEUnsignedCharCharacteristic buttonCharacteristic( "2102", BLERead | BLEWrite | BLENotify ); // see above 16-bit UUID


byte buttonValue = 0x00;
int commandIterations = 0;

#define  BUTTONSWITCHPIN 10

void setup()
{
  Serial.begin( 9600 );
  while ( !Serial );

  pinMode( BUTTONSWITCHPIN, OUTPUT );
  pinMode( LED_BUILTIN, OUTPUT );
  if ( !BLE.begin() )
  {
    Serial.println( "starting BLE failed!" );
    while ( 1 );
  }

  String address = BLE.address();
  Serial.println( "Our address is [" + address + "]" );

  BLE.setDeviceName( "IBM Garage Opener" );    // this sets Characteristic 0x2a00 of Service 0x1800
  // Service 0x1800 is the Generic Access Profile
  // Characteristic 0x2a00 is the Device Name
  // Characteristic 0x2a01 is the "Appearance"
  BLE.setAppearance( 384 );                    // BLE_APPEARANCE_GENERIC_REMOTE_CONTROL

  BLE.setLocalName( "BLE Garage Opener" );     // this sets the local name for the advertising data

  // tell the world
  BLE.setAdvertisedService( garageDoorService );
  garageDoorService.addCharacteristic( buttonCharacteristic );
  BLE.addService( garageDoorService );

  buttonCharacteristic.writeValue( buttonValue );    // start with a zero

  // advertise to the world so we can be found
  BLE.advertise();

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

  // register new connection handler
  BLE.setEventHandler( BLEConnected, blePeripheralConnectHandler );

  // registeer disconnect handler
  BLE.setEventHandler( BLEDisconnected, blePeripheralDisconnectHandler );

  // handle Characteristic Written Handler
  buttonCharacteristic.setEventHandler( BLEWritten, switchCharacteristicWritten );
}

void switchCharacteristicWritten( BLEDevice central, BLECharacteristic characteristic )
{
  // central wrote new value to characteristic, see if care, etc.
  Serial.print( "Characteristic event, written: " );
  Serial.println( characteristic.uuid() );
  // see if this is the Button Characteristic
  if ( characteristic.uuid() == (const char*)"2102" ) // added (const char*) see compiler warning before
  {
    characteristic.readValue( buttonValue );
    Serial.print( "new value " );
    Serial.println( buttonValue );
    if ( buttonValue == 1 )
    {
      digitalWrite( BUTTONSWITCHPIN, HIGH );
      //delay( 500 );  // do not use delay()
      commandIterations++;
      buttonCharacteristic.writeValue( 7 );		// <<<<<<< here is what i think should be sending the value 1 to the mobile??????
    }
    digitalWrite( BUTTONSWITCHPIN, LOW );
  }
}

void blePeripheralConnectHandler( BLEDevice central )
{
  // central connected event handler
  Serial.print( "Connected event, central: " );
  Serial.println( central.address() );
  digitalWrite( LED_BUILTIN, HIGH );  // indicate that we have a connection
  digitalWrite( BUTTONSWITCHPIN, LOW );       //  make sure our button is NOT pressed
}

void blePeripheralDisconnectHandler( BLEDevice central )
{
  // central disconnected event handler
  Serial.print( "Disconnected event, central: " );
  Serial.println( central.address() );
  digitalWrite( LED_BUILTIN, LOW );   // indicate that we no longer have a connection
  digitalWrite( BUTTONSWITCHPIN, LOW );       //  make sure our button is NOT pressed
}

void loop()
{
  bleTask();
}

void bleTask()
{
  #define BLE_UPDATE_INTERVAL 2
  static uint32_t previousMillis = 0;
  
  uint32_t currentMillis = millis();
  if ( currentMillis - previousMillis >= BLE_UPDATE_INTERVAL )
  {
    previousMillis = currentMillis;
    BLE.poll();
  }
}  

Now about sending data back, that is not how BLE works. From your applications point of view the data is only stored on the server/peripheral side. Your code does everything it can. I have modified it a little bit to show you what happens. Have a look at the following screenshots from my phone running the BLE Scanner app.

I wrote 01 to the characteristic once with Notify enabled and a second time without after reset.

  • Left image: Notify ON, after write the value is updated, and the app is notified that the value changed and 0x01 is read. Immediately after that the sketch writes 7 and the app is notified again and reads 7.
  • Middle image: Notify OFF, after write nothing happens, the app does not know whether the value was updated or not
  • Right image: After manual Read the app reads the value 7 because that is the current value on the server/peripheral. The value of 1 was missed because Notify was not enabled and the app did not read.

Let me know if that makes everything a bit clearer.

There are a few additional things you might want to look into:

  • 128-bit UUID
  • I have the feeling that BLE.setAppearance does not work.
  • BUTTONSWITCHPIN the name is confusing because one would think a button is a input. You probably have a good explanation. Maybe you can add a comment that explains it.
  • deviceName and localName are different, any reason?

Thanks, I think i misunderstood how the bluetooth worked.

I now see you need to write to the device first and then read it separately.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.