ucsd-creative-robotics

Bluetooth with the Dev Board

What is Bluetooth?

Talk through what Bluetooth Low Energy (BLE) is, and how it compares/differs from serial, WiFi, and other ways of connecting.

ESP32S3 Bluetooth

BLE Scanner App

nRF Connect is a good one for iOS, Anrdoid, and other OSes.

ESP32 BLE Scanner

!! DOES NOT WORK !! will revisit at a later date

Write a program to scan for nearby BLE devices and detect if a specific device (like your phone) is nearby.

1. Find your Phone’s BLE MAC Address

2. Compile and upload arduino code

/* 
Electronic Technologies for Art II
et4a.roberttwomey.com | rtwomey@ucsd.edu

ble-scanner

Scans for nearby BLE devices and detects a specific MAC address.
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

int scanTime = 5; //In seconds
BLEScan* pBLEScan;

// TARGET_DEVICE_MAC: Replace with your device's MAC address
// Format: "xx:xx:xx:xx:xx:xx" (lowercase)
String targetDeviceMac = "24:6f:28:ae:34:56"; 

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
    void onResult(BLEAdvertisedDevice advertisedDevice) {
      // Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
      
      // Convert found MAC to String for comparison
      String currentMac = advertisedDevice.getAddress().toString().c_str();
      
      // Check if the found device matches our target
      if (currentMac == targetDeviceMac) {
        Serial.println("***************************");
        Serial.println("Target Device Found!");
        Serial.printf("Device: %s \n", advertisedDevice.toString().c_str());
        Serial.printf("RSSI: %d \n", advertisedDevice.getRSSI());
        Serial.println("***************************");
      }
    }
};

void setup() {
  Serial.begin(115200);
  Serial.println("Scanning...");

  BLEDevice::init("");
  pBLEScan = BLEDevice::getScan(); //create new scan
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(99);  // less or equal setInterval value
}

void loop() {
  BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
  Serial.print("Devices found: ");
  Serial.println(foundDevices.getCount());
  Serial.println("Scan done!");
  pBLEScan->clearResults();   // delete results fromBLEScan buffer to release memory
  delay(2000);
}

3. Activity

BLE LED

Control the onboard LED1 or LED2 using a BLE characteristic.

1. Compile and upload arduino code

/* 
Electronic Technologies for Art II
et4a.roberttwomey.com | rtwomey@ucsd.edu

ble-led

Controls LED1 with BLE service. 
Use a BLE scanner (such as nRF Connect) or
this p5js sketch: https://editor.p5js.org/robert.twomey/sketches/aXwz43amQ

Adapted from ESP32 Examples -> BLE -> Write
And NYU ITP https://itpnyu.github.io/p5ble-website/docs/write-one-char-callback

*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

const int ledPin = 17;

class MyCallbacks : public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    String value = pCharacteristic->getValue();

    if (value.length() > 0) {
      Serial.println("*********");
      Serial.print("New value: ");
      for (int i = 0; i < value.length(); i++) {
        Serial.print(value[i]);
      }

        if (value != 0) {   // any value other than 0
          Serial.println("\nLED on\n");
          digitalWrite(ledPin, HIGH);         // will turn the LED on
        } else {                              // a 0 value
          Serial.println("\nLED off\n");
          digitalWrite(ledPin, LOW);          // will turn the LED off
        }

      Serial.println();
      Serial.println("*********");
    }
  }
};

void setup() {
  pinMode(ledPin, OUTPUT);

  Serial.begin(115200);

  Serial.println("1- Download and install an BLE scanner app in your phone (nRF)");
  Serial.println("2- Scan for BLE devices in the app");
  Serial.println("3- Connect to MyESP32");
  Serial.println("4- Go to CUSTOM CHARACTERISTIC in CUSTOM SERVICE and write something");
  Serial.println("5- See the magic =)");

  BLEDevice::init("MyESP32"); // change this name
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

  BLECharacteristic *pCharacteristic =
    pService->createCharacteristic(CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  pCharacteristic->setCallbacks(new MyCallbacks());

  pCharacteristic->setValue("Hello World");
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  pAdvertising->start();
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}

ble-led.zip

Instructions

  1. Be sure to change the device name (BLEDevice::init("MyESP32");)to be something special to you! (And so you don’t conflict with your classmates)

  2. Compile and upload the program.

  3. You can keep the serial port open to see what is happening from the dev board side. (Make sure Tools->USB CDC on Boot is set to Enabled)

1. Control with BLE scanner

2. Control with p5js

Use a p5js app to connect to and control the LED.

3. Activity

4. Extension

BLE Button

Use the onboard switch (SW1) to control an on-screen sketch.

1. Compile and upload arduino code

/* 
Electronic Technologies for Art II
et4a.roberttwomey.com | rtwomey@ucsd.edu

ble-button

Reads from builting SW1 (IO12) and publishes to service.
Use a BLE scanner (such as nRF Connect) or
this p5js sketch: https://editor.p5js.org/robert.twomey/sketches/8wQxLraNL

NOTE: change your BLEDevice name from "MyESP32" to something of your own.

Adapted from ESP32 Examples -> BLE -> Server
And NYU ITP https://itpnyu.github.io/p5ble-website/docs/read-one-char-callback

*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define BUTTON_CHARACTERISTIC_UUID "19B10012-E8F2-537E-4F6C-D104768A1214"

const int ledPin = 18; // set ledPin to on-board LED2
const int buttonPin = 12; // set buttonPin to BTN1
int sensorPin = A0;    // select the input pin for the potentiometer

// 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
// BLEIntCharacteristic buttonCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);

BLECharacteristic *pCharacteristic;

void setup() {
  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(buttonPin, INPUT); // use button pin as an input

  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  BLEDevice::init("MyESP32"); // change this name to a custom name
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic =
    pService->createCharacteristic(BUTTON_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY);
    // pService->createCharacteristic(CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE);

  char txString[8];
  dtostrf(0, 1, 2, txString);

  pCharacteristic->setValue(txString); // set value to 0
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);

  // read the value from an analog sensor:
  // int sensorValue = analogRead(sensorPin);
  // char txString[8];
  // dtostrf(sensorValue/4, 1, 2, txString);

  // read value from digital button
  // char txString[8];
  // dtostrf(digitalRead(buttonPin), 1, 2, txString);
  // Serial.println(txString);
  // publish to characteristic
  // pCharacteristic->setValue(txString);

  int btn = digitalRead(buttonPin);

  Serial.println(btn);
  pCharacteristic->setValue(btn);

}

ble-button.zip

You can keep the serial port open to see what is happening.

Be sure to change the device name to be something special to you! (And so you don’t conflict with your classmates)

1. Debug with BLE scanner

2. Control with p5js

Use a p5js app to connect and read the unboard switch.

3. Activity

4. Extension

References