I just received a pair of Xiao BLE sensors in my mail to review! yess
Pros:
- The size of a 1€ coin.
- They are very afordable (i got the option without microphone).
- Seed wiki is amazing, eeverything works at the first try.
- They include a battery management/charger chip!, ( only for one cell lipos).
- BLE(bluetooth 5.0), Zigbee and NFC (external antenna needed)
Cons:
- NFC is not that well supported in arduino, no info about compatible external antennas, If NFC antenna is connected we lose the BLE capabilities.
In order to setup the Arduino IDE to compile and upload code to your Xiao BLE, follow this seed getting started guide, it worked for me at the first try!
My code is strongly based in the BLE example sketch found in the getting started guide.
First, the all the includes and gobal variables!I respected the same Service uuid used in Seeed BLE example, because why not...
I made up the characteristic's Uuid's, if you dont have any idea of what im talking about maybe you need to get smarter about how BLE works.
I am creating one LED service that contains 3 different byte characteristics that will turn on-off each colour.
#include <ArduinoBLE.h>
BLEService RGBledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // Bluetooth® Low Energy LED Service
// Bluetooth® Low Energy LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristicR("19B10001-E8F2-537E-4F6C-D104768A1215", BLERead | BLEWrite);
BLEByteCharacteristic switchCharacteristicG("19B10001-E8F2-537E-4F6C-D104768A1216", BLERead | BLEWrite);
BLEByteCharacteristic switchCharacteristicB("19B10001-E8F2-537E-4F6C-D104768A1217", BLERead | BLEWrite);
const int ledPinR = LEDR; // pin to use for the LEDR
const int ledPinG = LEDG; // pin to use for the LEDG
const int ledPinB = LEDB; // pin to use for the LEDB
The setup()
As usually, start the serial port to display debugging and system status messages.Then initialize each gpio connected to the rgb led.And the biggest chunk of the setup() is the BLE device construction, first we initialice the BLE class, we give it a name, and we attach a service containing characteristics.When the setup() is done the device should start advertising and we should be able to see it in any BLE scanner.
void setup() {
Serial.begin(9600);
delay(200);//some delay time for the serial device to start
// set LED pin to output mode
pinMode(ledPinR, OUTPUT); digitalWrite(ledPinR, HIGH);
pinMode(ledPinG, OUTPUT); digitalWrite(ledPinG, HIGH);
pinMode(ledPinB, OUTPUT); digitalWrite(ledPinB, HIGH);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy module failed!");
while (1);
}
// set advertised local name and service UUID:
BLE.setLocalName("LED");
BLE.setAdvertisedService(RGBledService);
// add the characteristic to the service
RGBledService.addCharacteristic (switchCharacteristicR);
RGBledService.addCharacteristic (switchCharacteristicG);
RGBledService.addCharacteristic (switchCharacteristicB);
// add service
BLE.addService(RGBledService);
// set the initial value for the characeristic:
switchCharacteristicR.writeValue(0);
switchCharacteristicG.writeValue(0);
switchCharacteristicB.writeValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral");
}
The infamous loop()
Its quite simple, our BLE device should be happily blinking its leds untill a central connects to it.When the central is connected, enter a while loop and check up if any of the characteristics was written, if it was, check the characteristic value and switch on/off the correspoding LED.
void loop() {
// listen for Bluetooth® Low Energy peripherals to connect:
BLEDevice central = BLE.central();
//the device is not connected to any central ... do a fun RGB carousel
digitalWrite(ledPinR, LOW);digitalWrite(ledPinB, HIGH);
delay(200);
digitalWrite(ledPinG, LOW);digitalWrite(ledPinR, HIGH);
delay(200);
digitalWrite(ledPinB, LOW);digitalWrite(ledPinG, HIGH);
delay(200);
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected()) {
digitalWrite(ledPinR, HIGH); //first turn OFF all leds.
digitalWrite(ledPinG, HIGH);
digitalWrite(ledPinB, HIGH);
while (central.connected()) {
if (switchCharacteristicR.written()) {//if the characteristic was just written
if (switchCharacteristicR.value()) {//if the characteristic contains a value other than 0
Serial.print("LED on ");
Serial.println(switchCharacteristicR.value());
digitalWrite(ledPinR, LOW); // changed from HIGH to LOW
} else {
Serial.println(F("LED off"));
digitalWrite(ledPinR, HIGH); // changed from LOW to HIGH
}
}
if (switchCharacteristicG.written()) {
if (switchCharacteristicG.value()) {
Serial.print("LED on ");
Serial.println(switchCharacteristicG.value());
digitalWrite(ledPinG, LOW); // changed from HIGH to LOW
} else {
Serial.println(F("LED off"));
digitalWrite(ledPinG, HIGH); // changed from LOW to HIGH
}
}
if (switchCharacteristicB.written()) {
if (switchCharacteristicB.value()) {
Serial.print("LED on ");
Serial.println(switchCharacteristicB.value());
digitalWrite(ledPinB, LOW); // changed from HIGH to LOW
} else {
Serial.println(F("LED off"));
digitalWrite(ledPinB, HIGH); // changed from LOW to HIGH
}
}
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
The JavaScript part: (disclaimer, I learned javascript 1h ago)The web is available here if you want to try it out (USE GOOGLE CHROME).
Viewing the javascipt console is very useful if youre lost press "F12"key.
The HTML part, just a header and 6 simple buttons, almost no style, for suer no css
<!DOCTYPE html>
<html>
<head>
<title>Web BLE research</title>
<meta name="webble" content="user-scalable=no">
<script type = "text/javascript" src="main.js"></script>
</head>
<body scroll="no" style="overflow: hidden;position: fixed;
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif ;
color:rgb(128, 128, 128);
font-size: xx-large;">
<h1 style="text-align:center">JavaScript BLE shenannigans</h1>
<p style="text-align:center">Turns on and off LED colours.</p>
<button onclick="onConnectBLEdevice()">Connect to BLE device</button>
<br><br><br>
<button onclick="onTurnOnRedLed()">onTurnOnRedLed</button>
<button onclick="onTurnOffRedLed()">onTurnOffRedLed</button><br>
<button onclick="onTurnOnBlueLed()">onTurnOnBlueLed</button>
<button onclick="onTurnOffBlueLed()">onTurnOffBlueLed</button><br>
<button onclick="onTurnOnGreenLed()">onTurnOnGreenLed</button>
<button onclick="onTurnOffGreenLed()">onTurnOffGreenLed</button>
<p id="demo"></p>
</body>
</html><br>
This are the resources I found helpful:
//https://web.dev/i18n/es/bluetooth/#connect
//https://googlechrome.github.io/samples/web-bluetooth/discover-services-and-characteristics.html?optionalServices=e
//https://developer.mozilla.org/en-US/docs/Web/API/Bluetooth/requestDevice
//https://googlechrome.github.io/samples/web-bluetooth/read-characteristic-value-changed.html
The javascript code:I just learned how to use the bluetooth web API, they use something called promises.
There are functions related to connect to BLE devices (it filters out the ones which name isnt "LED")
Once connected to the XIAO device, the LED blink should stop and we can control the LED with the buttons on the screen.
var bluetoothDevice;
var bluetoothDeviceCharacteristicRedLED;
var bluetoothDeviceCharacteristicGreenLED;
var bluetoothDeviceCharacteristicBlueLED;
var statusLED;
function onConnectBLEdevice() {
return (bluetoothDevice ? Promise.resolve() : requestDevice())
.then(connectDeviceAndCacheCharacteristics)
.catch(error => {
console.log('onConnectBLEdevice Argh! ' + error);
console.log(error);
});
}
function requestDevice() {
console.log('Requesting any Bluetooth Device with 19b10000-e8f2-537e-4f6c-d104768a1214 service...');
return navigator.bluetooth.requestDevice({
filters: [{name: 'LED'}],//<- Prefer filters to save energy & show relevant devices.
// acceptAllDevices: true,
optionalServices: ['19b10000-e8f2-537e-4f6c-d104768a1214']})
.then(device => {
bluetoothDevice = device;
bluetoothDevice.addEventListener('gattserverdisconnected', onDisconnected);
});
}
function connectDeviceAndCacheCharacteristics() {
if (bluetoothDevice.gatt.connected && bluetoothDeviceCharacteristic) {
return Promise.resolve();
}
console.log('Connecting to GATT Server...');
return bluetoothDevice.gatt.connect()
.then(server => {
console.log('Getting LED Service...');
return server.getPrimaryService('19b10000-e8f2-537e-4f6c-d104768a1214');
})
.then(service => {
console.log('Getting red LED Characteristic...');
// Get all characteristics.
return service.getCharacteristics();
})
.then(characteristics => {
console.log('> Characteristics: ' +
characteristics.map(c => c.uuid).join('\n' + ' '.repeat(19)));
console.log(characteristics)
console.log(characteristics[0])
//for (var i = 0; i < characteristics.length; i++) {
bluetoothDeviceCharacteristicRedLED = characteristics[0];
bluetoothDeviceCharacteristicGreenLED = characteristics[1];
bluetoothDeviceCharacteristicBlueLED = characteristics[2];
//}
})
.catch(error => {
console.log('Argh! ' + error);
});
}
/* This function will be called when `readValue` resolves and
* characteristic value changes since `characteristicvaluechanged` event
* listener has been added. */
function onDisconnected() {
console.log('> Bluetooth Device disconnected');
connectDeviceAndCacheCharacteristics()
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOnRedLed(){
aux=new Int8Array(1);
aux[0]=1;
return (bluetoothDeviceCharacteristicRedLED.writeValue(aux))
.then(_ => {
console.log('onTurnOnRedLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOnGreenLed(){
aux=new Int8Array(1);
aux[0]=1;
return (bluetoothDeviceCharacteristicGreenLED.writeValue(aux))
.then(_ => {
console.log('onTurnOnGreenLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOnBlueLed(){
aux=new Int8Array(1);
aux[0]=1;
return (bluetoothDeviceCharacteristicBlueLED.writeValue(aux))
.then(_ => {
console.log('onTurnOnBlueLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOffRedLed(){
aux=new Int8Array(1);
aux[0]=0;
return (bluetoothDeviceCharacteristicRedLED.writeValue(aux))
.then(_ => {
console.log('onTurnOffRedLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOffGreenLed(){
aux=new Int8Array(1);
aux[0]=0;
return (bluetoothDeviceCharacteristicGreenLED.writeValue(aux))
.then(_ => {
console.log('onTurnOffGreenLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
function onTurnOffBlueLed(){
aux=new Int8Array(1);
aux[0]=0;
return (bluetoothDeviceCharacteristicBlueLED.writeValue(aux))
.then(_ => {
console.log('onTurnOffBlueLed');
})
.catch(error => {
console.log('Argh! ' + error);
});
}
Comments
Please log in or sign up to comment.