Skip to content

Instantly share code, notes, and snippets.

@Palantir555

Palantir555/BLE_server.ino

Last active Nov 11, 2019
Embed
What would you like to do?
/*
* This sketch is the BLE GATT server for a halloween costume.
* For more information on the project, check this post:
* https://jcjc-dev.com/2019/11/11/esp32-arduino-bluetooth-halloween-costume/
*
* Create a BLE server that, once we receive a connection, will poll a button and
* an accelerometer. If the button is pressed or the device is moved abruptly,
* the device will send a notification to the BLE clients.
*
* The service advertises itself as $BLE_STORM_SERVICE_UUID
* And has a characteristic of $BLE_PROP_CHARACTERISTIC_UUID
*
* The design of creating the BLE server is:
* 1. Create a BLE Server
* 2. Create a BLE Service
* 3. Create a BLE Characteristic on the Service
* 4. Create a BLE Descriptor on the characteristic
* 5. Start the service.
* 6. Start advertising.
*
* A connect hander associated with the server starts a background task that
* performs notification every couple of seconds.
*
* Author: Juan Carlos Jimenez Caballero
*
* License: Fully Open Source. Use at your own peril
* This firmware uses code found in Aruino's ESP32 BLE GATT example, and some
* snippets from other unlicensed open source projects
*/
#include <BLE2902.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
/* Modify these UUIDs for your project. Generate your own using uuidgenerator.net
* or any other UUID generator */
#define BLE_STORM_SERVICE_UUID "ca626879-77c5-4f6d-922c-e8fa1a6cb83c"
#define BLE_PROP_CHARACTERISTIC_UUID "08ea4673-8b2b-4394-8390-d6e6e96b4974"
#define GPIO_BUTTON_PIN 14 /* wire-connected button */
#define ACCEL_SCL_PIN 22
#define ACCEL_SDA_PIN 21
#define USE_ACCEL_INPUT 1
#if USE_ACCEL_INPUT
#define ACCL_THRESHOLD 50
#include <Adafruit_ADXL345_U.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
/* Assign a unique ID to this sensor at the same time */
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
#endif
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
bool button_read = LOW;
bool last_button_read = LOW;
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer* pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer)
{
deviceConnected = false;
}
};
void notify_uint32(uint32_t value)
{
uint32_t bt_characteristic_value = value;
pCharacteristic->setValue((uint8_t*)&bt_characteristic_value,
sizeof(uint32_t));
pCharacteristic->notify();
}
void setup()
{
Serial.begin(115200);
/* GPIO Init */
pinMode(GPIO_BUTTON_PIN, INPUT_PULLUP);
#if USE_ACCEL_INPUT
/* The I2C data pins must be INPUT_PULLUP for accel.begin() to succeed */
pinMode(ACCEL_SDA_PIN, INPUT_PULLUP);
pinMode(ACCEL_SCL_PIN, INPUT_PULLUP);
/* Initialise the sensor */
while(!accel.begin()) {
/* Unable to detect the ADXL345. check your connections */
Serial.println("ERROR! Unable to detect ADXL345. Check your wiring!");
delay(1000);
}
/* Set the range to whatever is appropriate for your project */
accel.setRange(ADXL345_RANGE_16_G); /* _8_G, _4_G, _2_G */
#endif
/* Create the BLE Device */
BLEDevice::init("ESP32");
/* Create the BLE Server */
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
/* Create the BLE Service */
BLEService* pService = pServer->createService(BLE_STORM_SERVICE_UUID);
/* Create a BLE Characteristic */
pCharacteristic = pService->createCharacteristic(
BLE_PROP_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE);
/* Create a BLE Descriptor */
pCharacteristic->addDescriptor(new BLE2902());
/* Start the service */
pService->start();
/* Start advertising */
BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(BLE_STORM_SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0); /* set bt_characteristic_value to 0x00
* to not advertise this parameter */
BLEDevice::startAdvertising();
Serial.println("Waiting for a client connection to notify...");
}
void loop()
{
if(deviceConnected) {
uint32_t virtual_switch = 0;
button_read = digitalRead(GPIO_BUTTON_PIN);
if((button_read == LOW) && (last_button_read == HIGH)) {
/* button pressed */
(virtual_switch == 1) ? (virtual_switch = 0) : (virtual_switch = 1);
notify_uint32(virtual_switch);
delay(300); /* Debounce */
}
last_button_read = button_read;
#if USE_ACCEL_INPUT
/* Get a new sensor event (acceleration is measured in m/s^2) */
sensors_event_t event;
accel.getEvent(&event);
if((event.acceleration.x > ACCL_THRESHOLD) ||
(event.acceleration.x < -1 * ACCL_THRESHOLD) ||
(event.acceleration.y > ACCL_THRESHOLD) ||
(event.acceleration.y < -1 * ACCL_THRESHOLD) ||
(event.acceleration.z > ACCL_THRESHOLD) ||
(event.acceleration.z < -1 * ACCL_THRESHOLD)) {
/* These debug messages are useful to calibrate ACCL_THRESHOLD */
/*
Serial.print("x: "); Serial.print(event.acceleration.x);
Serial.print(" | y: "); Serial.print(event.acceleration.y);
Serial.print(" | z: "); Serial.println(event.acceleration.z);
*/
notify_uint32(1);
delay(400);
}
#endif
}
/* disconnecting */
if(!deviceConnected && oldDeviceConnected) {
delay(500); /* give the BT stack the chance to get things ready */
pServer->startAdvertising(); /* restart advertising */
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
/* connecting */
if(deviceConnected && !oldDeviceConnected) {
/* do stuff here on connecting */
oldDeviceConnected = deviceConnected;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment