ARDUINOBLE ButtonLED example

Hi, I am trying to create a peripheral that sends updates for 2 separate buttons. I attempted duplicate the buttonCharacteristic as shown below but I am having a couple of issues.

  1. button3 works backwards. once I press it and let go the LED stays on. It only turns off when I hold down button 3 or press button2.

  2. when I press either button then both Characteristics are updated the Light Blue app. So for example if I press button2 I get a updated value for characteristic2 and characteristic3 in the app and vice versa.

Is the ledService a bad service to use for this application? Is there a better one to use without creating a custom service?

Should I be creating multiple instances of the ledService instead of creating multiple characteristics for the buttons?

Thanks so much!

/*
  Button LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED and another characteristic that
  represents the state of the button.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.
  - Button connected to pin 4

  You can use a generic BLE central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED
const int button2Pin = 2; // set buttonPin to digital pin 4
const int button3Pin = 3; // set buttonPin to digital pin 5

BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic ledCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
// create button characteristic and allow remote device to get notifications
BLEByteCharacteristic button2Characteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);

BLEByteCharacteristic button3Characteristic("19B10013-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);


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

  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(button2Pin, INPUT); // use button pin as an input
  pinMode(button3Pin, INPUT); // use button pin as an input

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

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("2ButtonLED");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(ledService);

  // add the characteristics to the service
  ledService.addCharacteristic(ledCharacteristic);
  ledService.addCharacteristic(button2Characteristic);
  ledService.addCharacteristic(button3Characteristic);
  
  // add the service
  BLE.addService(ledService);

  ledCharacteristic.writeValue(0);
  button2Characteristic.writeValue(0);
  button3Characteristic.writeValue(0);

  // start advertising
  BLE.advertise();

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

void loop() {
  // poll for BLE events
  BLE.poll();

  // read the current button pin state
  char button2Value = digitalRead(button2Pin);

  // has the value changed since the last read
  boolean button2Changed = (button2Characteristic.value() != button2Value);
 

  if (button2Changed) {
    // button state changed, update characteristics
    ledCharacteristic.writeValue(button2Value);
    button2Characteristic.writeValue(button2Value);
  }

  if (ledCharacteristic.written() || button2Changed) {
    // update LED, either central has written to characteristic or button state has changed
    if (ledCharacteristic.value()) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
  }
  
  char button3Value = digitalRead(button3Pin);
  boolean button3Changed = (button3Characteristic.value() != button3Value);

      if (button3Changed) {
    // button state changed, update characteristics
    ledCharacteristic.writeValue(button3Value);
    button3Characteristic.writeValue(button3Value);
  }
  
  if (ledCharacteristic.written() || button3Changed) {
    // update LED, either central has written to characteristic or button state has changed
    if (ledCharacteristic.value()) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
  }

}

How are your buttons wired up? You have them declared as INPUT which means they will require an external pull-down resistor. Are these resistors present?

blh64:
How are your buttons wired up? You have them declared as INPUT which means they will require an external pull-down resistor. Are these resistors present?

Great point! Yeah I think so, I tested each button individually using only one characteristic before adding the second characteristic. See attached photo of the remote I'm building. I started with 10k but was having issues so I moved down to a 1k and it worked!

osy:

  1. button3 works backwards. once I press it and let go the LED stays on. It only turns off when I hold down button 3 or press button2.

  2. when I press either button then both Characteristics are updated the Light Blue app. So for example if I press button2 I get a updated value for characteristic2 and characteristic3 in the app and vice versa.

Is the ledService a bad service to use for this application? Is there a better one to use without creating a custom service?

Should I be creating multiple instances of the ledService instead of creating multiple characteristics for the buttons?

Ok so I was able to fix problem 1 by replacing the two separate LED update sections with one double-OR statement as follows.

if (ledCharacteristic.written() || button3Changed || button2Changed) {
    // update LED, either central has written to characteristic or button state has changed
   if (ledCharacteristic.value()) {
   Serial.println("LED on");
   digitalWrite(ledPin, HIGH);
    } else {
   Serial.println("LED off");
   digitalWrite(ledPin, LOW);
   }
  }

I am still having the issue with the characteristic updates in Light Blue. Both buttons update both characteristics at the same time!?!?! Please help.

All I have to test on is an Arduino 101, so I had to use the CurieBLE library instead of the one you used. Since I don't have the Light Blue app I used nRF Connect by Nordic Semiconductor.

I wired up two buttons with 1K pull-downs and the program works flawlessly, each button controls the characteristics individually on the app.

You might try adding some print statements where the characteristics are being written so you can see what's going on.