Monday, June 21, 2021

ArduinoBLE exercise on Nano RP2040 Connect: BLE Peripheral

ArduinoBLE exercise run on Nano RP2040 Connect, act as BLE Peripheral. Tested with nRF Connect app on Android.


nanoRP2040_BLE_Peripheral_20210622a.ino
/*
 * Arduino nano RP2040 Connect exercise:
 * as BLE Peripheral 
 * 
 * reference:
 * ArduinoBLE library-
 * https://www.arduino.cc/en/Reference/ArduinoBLE
 * 
 * In my implementation:
 * BLEByteCharacteristic written event checked by polling.
 * BLEStringCharacteristic/BLEIntCharacteristic using event haandler.
 * 
 */
 #include <ArduinoBLE.h>

/*  Visit Online GUID / UUID Generator
 *  (https://www.guidgenerator.com/)
 *  to generate your uuid
 */
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

const char* myLocalName = "MyBLE";
 
BLEService myBLEService(serviceUUID);
BLEByteCharacteristic myBLEByteCharacteristic(byteCharUUID, 
                              BLERead|BLEWrite);
BLEStringCharacteristic myBLEStringCharacteristic(stringCharUUID, 
                              BLERead|BLEWrite, 10);  //max length = 10
BLEIntCharacteristic myBLEIntCharacteristic(intCharUUID,
                              BLERead|BLEWrite);


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);
  delay(100);
  digitalWrite(LED_BUILTIN, HIGH);

  //Started, connect Serial to begin
  while(!Serial);
  Serial.println("\n---Start ---");
  digitalWrite(LED_BUILTIN, LOW);

  Serial.println("Initialize BLE...");
  if(!BLE.begin()){
    Serial.println("Starting BLE failed!");
    while(1);
  }
  Serial.println("BLE initialized.");
  Serial.print("MAC: ");
  Serial.println(BLE.address());
  Serial.println("Service UUIID: \t\t\t" + String(serviceUUID));
  Serial.println("Byte Characteristic UUIID: \t" + String(byteCharUUID));
  Serial.println("String Characteristic UUIID: \t" + String(stringCharUUID));
  Serial.println("Int Characteristic UUIID: \t" + String(intCharUUID));
  
  Serial.println();

  BLE.setLocalName(myLocalName);
  BLE.setAdvertisedService(myBLEService);
  myBLEService.addCharacteristic(myBLEByteCharacteristic);
  myBLEService.addCharacteristic(myBLEStringCharacteristic);
  myBLEService.addCharacteristic(myBLEIntCharacteristic);
  BLE.addService(myBLEService);

  myBLEStringCharacteristic.setEventHandler(BLEWritten, myBLEString_Written_Hndl);
  myBLEIntCharacteristic.setEventHandler(BLEWritten, myBLEInt_Written_Hndl);

  BLE.advertise();

}

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

  if(central){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print("Connected: ");
    Serial.println(central.address());

    while(central.connected()){

      if(myBLEByteCharacteristic.written()){
        byte valByte = myBLEByteCharacteristic.value();
        Serial.print("myBLEByteCharacteristic received: ");
        Serial.println(valByte, HEX);
      }
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Disconnected.");
  }
}

// Event Handler for myBLEStringCharacteristic Written
// Print received Sring, and write back in upper case.
void myBLEString_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEStringCharacteristic event, written: ");

  Serial.println("myBLEStringCharacteristic received: len=" + 
                  String(myBLEStringCharacteristic.valueLength()));
  String valString = myBLEStringCharacteristic.value();
  Serial.println(valString);
  valString.toUpperCase();
  Serial.println(valString);
  myBLEStringCharacteristic.setValue(valString);
}

// Event Handler for myBLEIntCharacteristic Written
void myBLEInt_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEIntCharacteristic event, written: ");
  
  int valInt = myBLEIntCharacteristic.value();
  Serial.println(valInt);
  
}



~ More exercises for Arduino Nano RP2040 Connect

Sunday, June 13, 2021

Raspberry Pi/Python BLE Central + Arduino Nano RP2040 Connect BLE Peripheral

This exercise implement Python 3 code run on Raspberry Pi act as BLE Central, connect to Arduino Nano RP2040 Connect act as BLE Peripheral. And send data (0x01/0x00) to turn the Nano RP2040 Connect's onboard LED ON/OFF.


Arduino Nano RP2040 Connect act as BLE Peripheral side:

- Make sure ArduinoBLE library is installed.

- The Arduino code is modified from ArduinoBLE Examples > Peripheral > CallbackLED. With MAC, Service UUID, Characteristic UUID, and BLE written data displayed. Such that we can program Central side accordingly.

nanoRP2040_BLE_CallbackLED.ino
/*
  Callback LED

  This example creates a BLE peripheral with service that contains a
  characteristic to control an LED. The callback features of the
  library are used.

  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.

  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>

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

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = LED_BUILTIN; // pin to use for the LED

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(1000);
  Serial.println("\n--- Start---");
  
  pinMode(ledPin, OUTPUT); // use the LED pin as an output

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

    while (1);
  }

  Serial.print("My BLE MAC:\t\t ");
  Serial.println(BLE.address());
  Serial.print("Service UUID:\t\t ");
  Serial.println(ledService.uuid());
  Serial.print("Characteristic UUID:\t ");
  Serial.println(switchCharacteristic.uuid());
  Serial.println();

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

  // add the characteristic to the service
  ledService.addCharacteristic(switchCharacteristic);

  // add service
  BLE.addService(ledService);

  // assign event handlers for connected, disconnected to peripheral
  BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
  BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler);

  // assign event handlers for characteristic
  switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten);
  // set an initial value for the characteristic
  switchCharacteristic.setValue(0);

  // start advertising
  BLE.advertise();

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

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

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.print("Connected event, central: ");
  Serial.println(central.address());
}

void blePeripheralDisconnectHandler(BLEDevice central) {
  // central disconnected event handler
  Serial.print("Disconnected event, central: ");
  Serial.println(central.address());
}

void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) {
  // central wrote new value to characteristic, update LED
  Serial.println("Characteristic event, written: ");

  byte charValue = switchCharacteristic.value();
  Serial.println(charValue);

  if (charValue) {
    Serial.println("LED on");
    digitalWrite(ledPin, HIGH);
  } else {
    Serial.println("LED off");
    digitalWrite(ledPin, LOW);
  }
}

Raspberry Pi/Python BLE Central Side:
- bluepy library is used to control Bluetooth BLE.

To install bluepy for Python3, enter the command:
$ sudo pip3 install bluepy

- tkinter is used for GUI.

py_BLE_Central_LedControl.py connect to Peripheral with matched MAC, and search for service/characteristic with match UUID. Then send 0x01/0x00 to turn ON/OFF the Nano RP2040 Connect's onboard LED.

"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found: send bytes 0x01 and 0x00 for three time
to turn Nano RP2040 Connect onboard LED ON/OFF.
"""

from bluepy import btle
import time

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    for i in range(3):
        nanoRP2040_Char.write(bytes_ON, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
        nanoRP2040_Char.write(bytes_OFF, True)
        print(nanoRP2040_Char.read())
        time.sleep(1.0)
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")
pyTk_BLE_Central_LedControl.py implement GUI with tkinter, user click on button to turn ON/OFF LED.
"""
Python/Raspberry Pi BluetoothLE exercise:
using bluepy library

Work with Arduino Nano RP2040 Connect example:
ArduinoBLE > Peripheral > CallbackLED

Connect to Peripheral with matched MAC.
Check for service uuid and characteristic uuid,
if matched found:
    Start GUI to control Nano RP2040 Connect onboard LED
"""

from bluepy import btle
import time
import tkinter as tk

#Have to match with Peripheral
MAC = "84:cc:a8:2e:8d:76"
SERVICE_UUID = "19b10000-e8f2-537e-4f6c-d104768a1214"
CHARACTERISTIC_UUID = "19b10001-e8f2-537e-4f6c-d104768a1214"

nanoRP2040_Char = None

def toggle():
    if toggle_btn.config('relief')[-1] == 'sunken':
        toggle_btn.config(relief="raised")
        nanoRP2040_Char.write(bytes_OFF, True)
        toggle_btn['text'] = 'Turn LED ON'
    else:
        toggle_btn.config(relief="sunken")
        nanoRP2040_Char.write(bytes_ON, True)
        toggle_btn['text'] = 'Turn LED OFF'

print("Hello")

print("Connect to:" + MAC)
dev = btle.Peripheral(MAC)
print("\n--- dev ----------------------------")
print(type(dev))
print(dev)

print("\n--- dev.services -------------------")
for svc in dev.services:
    print(str(svc))
    
print("\n------------------------------------")
print("Get Serice By UUID: " + SERVICE_UUID)
service_uuid = btle.UUID(SERVICE_UUID)
service = dev.getServiceByUUID(service_uuid)

print(service)
print("\n--- service.getCharacteristics() ---")
print(type(service.getCharacteristics()))
print(service.getCharacteristics())

#----------------------------------------------
characteristics = dev.getCharacteristics()
print("\n--- dev.getCharacteristics() -------")
print(type(characteristics))
print(characteristics)
    
for char in characteristics:
    print("----------")
    print(type(char))
    print(char)
    print(char.uuid)
    if(char.uuid == CHARACTERISTIC_UUID ):
        print("=== !CHARACTERISTIC_UUID matched! ==")
        nanoRP2040_Char = char
        print(char)
        print(dir(char))
        #print(char.getDescriptors)
        #print(char.propNames)
        #print(char.properties)
        #print(type(char.read()))
        print(char.read())
        
bytes_ON = b'\x01'
bytes_OFF = b'\x00'

if nanoRP2040_Char != None:
    print("\nnanoRP2040_Char found")
    print(nanoRP2040_Char)
    
    root = tk.Tk()
    label = tk.Label( root, text="Toggle button to Turn ON/OFF the nano RP040 Connect LED")
    label.pack(pady=10)
    toggle_btn = tk.Button(text="Turn LED ON", width=12, relief="raised", command=toggle)

    toggle_btn.pack(pady=10)
    root.geometry("500x200")

    #Place tkinter window center
    root.eval('tk::PlaceWindow %s center' % root.winfo_pathname(root.winfo_id()))
    root.title("arduino-er.blogspot.com")
    root.mainloop()
else:
    print("\nnanoRP2040_Char NOT found!")
#=============================================
dev.disconnect()
print("\n--- bye ---\n")


~ More exercises of Arduino Nano RP2040 Connect.

Friday, June 11, 2021

Arduino Nano RP2040 Connect exercise: control onboard RGB LED

The Nano RP2040 Connect onboard RGB LED is connected through the W-102 module, so the WiFiNINA library needs to be installed and included in sketch.

Exercise to control onboard RGB LED.

#include <WiFiNINA.h>

void setup() {

  delay(2000);

  Serial.begin(9600);
  Serial.println(LEDR);
  Serial.println(LEDG);
  Serial.println(LEDB);
  
  pinMode(LEDR, OUTPUT);
  pinMode(LEDG, OUTPUT);
  pinMode(LEDB, OUTPUT);

  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE

}

void loop() {
  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, HIGH); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, LOW); //BLUE


  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, HIGH); //GREEN
  digitalWrite(LEDB, LOW); //BLUE

  delay(1000);
  digitalWrite(LEDR, LOW); //RED
  digitalWrite(LEDG, LOW); //GREEN
  digitalWrite(LEDB, HIGH); //BLUE
}


update@20211-06-28:

After WiFiNINA library updated, the code Serial.println(LEDR) (also LEDG and LEDB) throw error of :

error: call to 'NinaPin::operator int' declared with attribute error: Change me to a #define Serial.println(LEDR);

Just comment the codes to make it work.