Dependancies
Pre-requisites
Buy the components
web-ble-gatt.ino
#include <bluefruit.h>
uint8_t uvindexvalue = 0x0;
#define UUID16_SVC_ENVIRONMENTAL_SENSING 0x181A
#define UUID16_CHR_UV_INDEX 0x2A76
BLEService environmental_sensing_service = BLEService(UUID16_SVC_ENVIRONMENTAL_SENSING);
BLECharacteristic uv_index_characteristic = BLECharacteristic(UUID16_CHR_UV_INDEX);
void setup() {
Serial.begin(115200);
delay(500);
Serial.println("Start!");
Bluefruit.begin();
Bluefruit.setName("Palm");
setupESService();
startAdv();
}
void loop() {
uvindexvalue = random(0, 11);
Serial.print("UV Index: ");
Serial.println(uvindexvalue);
if (uv_index_characteristic.indicate(&uvindexvalue, sizeof(uvindexvalue))) {
Serial.print("Updated UV Index: ");
Serial.println(uvindexvalue);
} else {
Serial.println("UV Index Indicate not set");
}
delay(1000);
}
void startAdv(void) {
Bluefruit.Advertising.addService(environmental_sensing_service);
Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
Bluefruit.Advertising.addTxPower();
Bluefruit.Advertising.addName();
Bluefruit.Advertising.restartOnDisconnect(true);
Bluefruit.Advertising.setInterval(32, 244);
Bluefruit.Advertising.setFastTimeout(30);
Bluefruit.Advertising.start(0);
}
void setupESService(void) {
environmental_sensing_service.begin();
uv_index_characteristic.setProperties(CHR_PROPS_INDICATE);
uv_index_characteristic.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
uv_index_characteristic.setFixedLen(1);
uv_index_characteristic.begin();
uv_index_characteristic.write(&uvindexvalue, sizeof(uvindexvalue));
}
BOARD?=adafruit:nrf52:feather52832
PORT?=/dev/tty.SLAB_USBtoUART
.PHONY: default lint all flash clean
default: lint all flash clean
lint:
cpplint --extensions=ino --filter=-legal/copyright,-whitespace/line_length *.ino
all:
arduino-cli compile --fqbn $(BOARD) ./
flash:
adafruit-nrfutil dfu genpkg --dev-type 0x0052 --application ./.*.hex dfu-package.zip
adafruit-nrfutil dfu serial --package dfu-package.zip -p $(PORT) -b 115200
clean:
rm -f .*.elf
rm -f .*.hex
rm -f *.zip
serve:
echo "Open Chrome browser at http://localhost:8000/web-ble-read.html"
python -m SimpleHTTPServer 8000
Connect to a BLE device with BLE GATT Service of Environmental Sensing and BLE GATT Characteristic of UV Index and read the values from the Chrome browser console when the readings are updated.
Ensure the browser side of the code is also implemented with web-ble-gatt.html
.
<button id="read">Connect with BLE device</button>
<button id="start" disabled>Start</button>
<button id="stop" disabled>Stop</button>
<script>
var deviceName = 'Palm'
var bleService = 'environmental_sensing'
var bleCharacteristic = 'uv_index'
var bluetoothDeviceDetected
var gattCharacteristic
document.querySelector('#read').addEventListener('click', function() {
if (isWebBluetoothEnabled()) { read() }
})
document.querySelector('#start').addEventListener('click', function(event) {
if (isWebBluetoothEnabled()) { start() }
})
document.querySelector('#stop').addEventListener('click', function(event) {
if (isWebBluetoothEnabled()) { stop() }
})
function isWebBluetoothEnabled() {
if (!navigator.bluetooth) {
console.log('Web Bluetooth API is not available in this browser!')
return false
}
return true
}
function getDeviceInfo() {
let options = {
optionalServices: [bleService],
filters: [
{ "name": deviceName }
]
}
console.log('Requesting any Bluetooth Device...')
return navigator.bluetooth.requestDevice(options).then(device => {
bluetoothDeviceDetected = device
}).catch(error => {
console.log('Argh! ' + error)
})
}
function read() {
return (bluetoothDeviceDetected ? Promise.resolve() : getDeviceInfo())
.then(connectGATT)
.then(_ => {
console.log('Reading UV Index...')
return gattCharacteristic.readValue()
})
.catch(error => {
console.log('Waiting to start reading: ' + error)
})
}
function connectGATT() {
if (bluetoothDeviceDetected.gatt.connected && gattCharacteristic) {
return Promise.resolve()
}
return bluetoothDeviceDetected.gatt.connect()
.then(server => {
console.log('Getting GATT Service...')
return server.getPrimaryService(bleService)
})
.then(service => {
console.log('Getting GATT Characteristic...')
return service.getCharacteristic(bleCharacteristic)
})
.then(characteristic => {
gattCharacteristic = characteristic
gattCharacteristic.addEventListener('characteristicvaluechanged',
handleChangedValue)
document.querySelector('#start').disabled = false
document.querySelector('#stop').disabled = true
})
}
function handleChangedValue(event) {
let value = event.target.value.getUint8(0)
var now = new Date()
console.log('> ' + now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds() + ' UV Index is ' + value)
}
function start() {
gattCharacteristic.startNotifications()
.then(_ => {
console.log('Start reading...')
document.querySelector('#start').disabled = true
document.querySelector('#stop').disabled = false
})
.catch(error => {
console.log('[ERROR] Start: ' + error)
})
}
function stop() {
gattCharacteristic.stopNotifications()
.then(_ => {
console.log('Stop reading...')
document.querySelector('#start').disabled = false
document.querySelector('#stop').disabled = true
})
.catch(error => {
console.log('[ERROR] Stop: ' + error)
})
}
</script>