Enter Your Electronics & Design Project for a chance to win a $200 shopping cart! Back to homepage | Project14 Home | |
Monthly Themes | ||
Monthly Theme Poll |
This is a continuation from a previous post about using the Wio Terminal with Blynk.
Previously, I had demonstrated that the Wio Terminal communicated via WiFi to Blynk running on my Android tablet to display data from the MS8607 sensor. I ran into problems demonstrating BLE communication from the Blynk to the Wio Terminal to control the NeoPixel strip. The problem was fairly simple, I could not locate an include file so I was not able compile the example program. Seeed is continually updating their device libraries and recommended that I update to the latest WiFi and BLE firmware and libraries. I had updated the firmware when I first received the Wio Terminal but apparently it has been updated in the last month.
The firmware update is for the RTL8720DN WiFi/BLE chip so the process is interesting. You can't communicate directly with the RTL8720 so you need to do it through the main ATSAMD51 processor. The RTL8720DN has two MCUs so there are binary files included for both of them. There is an Arduino program that is uploaded to the Wio Terminal to establish communication from the PC to the ATSAMD51 and then via UART to the RTL8720DN. Then you need to run another program on the PC to erase/program the firmware over that communication channel. A little clunky but it works well.
After the firmware update I updated the 4 associated software libraries:
- Seeed_Arduino_rpcWiFi library
- Seeed_Arduino_rpcUnified library
- Seeed_Arduino_FreeRTOS library
- Seeed_Arduino_rpcBLE library
Then I ran a WiFi/Bluetooth scanning program WiFi_BLE_Scan/WiFi_BLE_Scan.ino and that detected the devices/networks that are nearby.
However, now both the Blynk WiFi and BLE examples would not compile. It turns out the library updates are not compatible with some of the prior examples depending on what WiFi/BLE features were used. I noticed today that they removed a Blynk project on Hackster that had some of the include file issues and I also see that they just added an eRPC project that describes the updated firmware https://www.hackster.io/Salmanfarisvp/the-new-wio-terminal-erpc-firmware-bfd8bd .
My compile problems were easy to fix. The orphan Seeed_erpcUnified.h file has been incorporated into the new library and is no longer required so I deleted it (since it no longer exists) - that fixed the Blynk BLE NeoPixel example. To fix the WiFi example I needed to incude rpcWiFi.h instead of aTWiFi.h.
My Wio_Terminal_Blynk_Temperature program was then working properly. Unfortunately, my BLE program was still having problems. It would connect to the Android tablet and then immediately disconnect.
I ran some other non-Blynk BLE programs that use the nRF Connect app (iBeacon and BLE_UART) and those were working so the BLE connection was okay. I tried new authorization tokens but just couldn't figure it out. In desperation I tried running Blynk on my iPad - and voila - it worked! No idea what's not working on the Android tablet (running Android 8.1) but for now I'll just demo the NeoPixel program using the iPad.
Blynk NeoPixel Control over BLE
This example program uses the zeRGBa widget in Blynk which is a multi-colored zebra to send RGB values to the Wio Terminal based on where the selector is positioned on the zebra. In the output merge mode of the widget the RGB values are sent to a single virtual pin as a 3 parameter array over BLE.
On the project screen select the Bluetooth icon to connect
Select the Blynk device which is the Wio Terminal
On the Wio Terminal the parameter array is used to program both the NeoPixel strip and the LCD color using the following program:
Wio_Terminal_Blynk_NeoPixel.ino
#define BLYNK_PRINT Serial #define BLYNK_USE_DIRECT_CONNECT #include <BlynkSimpleWioTerminal_BLE.h> #include <rpcBLEDevice.h> //bluetooth library #include <BLEServer.h> #include <Adafruit_NeoPixel.h> #include <TFT_eSPI.h> // Hardware-specific library TFT_eSPI tft = TFT_eSPI(); // Invoke custom library #define PIN D2 #define NUMPIXELS 8 #define BLYNK_PRINT Serial Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); // You should get Auth Token in the Blynk App. // Go to the Project Settings (nut icon). char auth[] = "aaaaaaaaaaaaaaa"; BLYNK_WRITE(V2) { int R = param[0].asInt(); int G = param[1].asInt(); int B = param[2].asInt(); tft.fillScreen(tft.color565(R, G, B)); for (int i = 0; i < NUMPIXELS; i++) { pixels.setPixelColor(i, pixels.Color(R, G, B)); pixels.setBrightness(32); pixels.show(); } } void setup() { // Debug console Serial.begin(115200); // while(!Serial){}; Serial.println("Waiting for connections..."); Blynk.setDeviceName("Blynk"); Blynk.begin(auth); tft.begin(); tft.fillScreen(TFT_BLACK); pixels.begin(); } void loop() { Blynk.run(); }
Once the program is uploaded press the run button in the app and a selection circle appears on the zebra.
Here is a short video showing the color changing as the selection circle is moved.
Web Bluetooth Accelerometer Plot over BLE
I've used the Web Bluetooth API before DMM Logging with Web Bluetooth and TS-04 DMM Data Plotting so it was nice to see a Web Bluetooth example using the accelerometers on the Wio Terminal. The beauty of Web Bluetooth is that you can run HTML code in a local browser window that uses your computer's Bluetooth interface to connect to other Bluetooth/BLE devices. I'm running the following example using the Chrome browser on my Win10 PC (not all browsers support the Web Bluetooth API). I'll probably modify the HTML code later to work with the MS8607 sensor but for demonstration I think 3 axis accelerometer data is more interesting.
Here is the HTML code running on the Chrome browser:
index.html
<html> <head> <title>Web Bluetooth Accelerometer Plotter</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.js"></script> <script src="https://unpkg.com/p5ble@0.0.5/dist/p5.ble.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.js"></script> <!-- <script src="smooth-plotter.js"></script> --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.1.0/dygraph.min.css" /> <meta name="viewport" content="width=device-width,height=device-height,initial-scale=1.0" /> <link href="https://fonts.googleapis.com/css?family=Ubuntu&display=swap" rel="stylesheet" /> </head> <style> h2, h3, p { font-family: 'Ubuntu', sans-serif; } </style> <body> <h2 style="text-align: center">Web Bluetooth Accelerometer Plotter For Wio Terminal</h2> <div> <ol> <li>The original work is done by <a href="https://github.com/armsp">Shantam Raj</a> and all credits goes to him. This is a modification for using Wio Terminal.</li> <li>Upload the WebBluetooth-Accelerator.ino sketch to your Wio Terminal</li> <li>Open Serial Monitor (it's is important otherwise the data transfer won't take place)</li> <li>Click the "Connect" button and follow the prompt</li> </ol> </div> <h3 style="text-align: center; color: red;" id="compatiblity"></h3> <script> if ("bluetooth" in navigator) { console.log("Supports Web Bluetooth"); // else the browser doesn't support bluetooth } else { console.log("Browser doesn't support Web Bluetooth"); alert("WARNING: This browser doesn't support Web Bluetooth. Try using Chrome."); document.getElementById("compatiblity").innerHTML = "Your browser doesn't support Web Bluetooth. Try using Chrome."; } </script> <div id="div_g" style="width:150vh; height:40vh; margin: auto;"></div> <script> const serviceUuid = "19b10000-e8f2-537e-4f6c-d104768a1214"; //const serviceUuid = "180f0000-0000-0000-0000-000000000000"; let myCharacteristic; let myValue = 0; let myBLE; var data = []; var g; var dataPoints = 100; //var plotFlag = true; //Graphing $(document).ready(function () { //var data = []; var t = new Date(); for (var i = dataPoints; i >= 0; i--) { var x = new Date(t.getTime() - i * 1000); data.push([x, NaN, NaN, NaN]); } g = new Dygraph(document.getElementById("div_g"), data, { //color: 'red', strokeWidth: 2, //rollPeriod: 10, drawPoints: true, //showRoller: true, valueRange: [-6, 6], labels: ['Time', 'X', 'Y', 'Z'], colors: ['#3B3B98', '#ff5e57', '#1dd1a1'], fillGraph: true, pointSize: 3, stepPlot: false, ylabel: "X, Y, Z" //pixelsPerLabel: 10, }); }); function plot(ax, ay, az) { // if (plotFlag === true){ // g.updateOptions({'file': []}); // var t = new Date(); // for (var i = dataPoints; i >= 0; i--) { // var x = new Date(t.getTime() - i * 1000); // data.push([x, NaN, NaN, NaN]); // } // g.updateOptions({'file': data}); // plotFlag = false; // } //My test var d = new Date(); // current time var x = ax; var y = ay; var z = az; data.shift(); // if (dataPoints>0){ // dataPoints-=1; // data.shift(); // data.push([d, x, y, z]); // } // else{ // data.push([d, x, y, z]); // } data.push([d, x, y, z]); g.updateOptions({ 'file': data }); } // Bluetooth function setup() { // Create a p5ble class myBLE = new p5ble(); createCanvas(300, 200); textSize(20); textAlign(CENTER, CENTER); // Create a 'Connect' button const connectButton = createButton('Connect') connectButton.mousePressed(connectToBle); } function connectToBle() { // Connect to a device by passing the service UUID myBLE.connect(serviceUuid, gotCharacteristics); } // A function that will be called once got characteristics function gotCharacteristics(error, characteristics) { if (error) console.log('error: ', error); console.log('characteristics: ', characteristics); myCharacteristic = characteristics[0]; // Read the value of the first characteristic myBLE.read(myCharacteristic, 'string', gotValue); //plot(myCharacteristic); } // A function that will be called once got values function gotValue(error, value) { if (error) console.log('error: ', error); console.log('value: ', value); myValue = value; var acceleration = myValue.split('|'); console.log('Acceleration: ', acceleration); plot(parseFloat(acceleration[0]), parseFloat(acceleration[1]), parseFloat(acceleration[2])); // After getting a value, call p5ble.read() again to get the value again myBLE.read(myCharacteristic, 'string', gotValue); } function draw() { background(250); text(myValue, 150, 100); } </script> </body> </html>
Here is the Arduino code running on the Wio Terminal:
WebBluetooth-Accelerator.ino
#include <rpcBLEDevice.h> #include <BLEServer.h> #include <LIS3DHTR.h> #define accelerometerService "19b10000-e8f2-537e-4f6c-d104768a1214" #define firstCharacteristic "19b10010-e8f2-537e-4f6c-d104768a1214" #define DESCRIPTOR_UUID "19b10010" LIS3DHTR<TwoWire> lis; bool deviceConnected = false; bool oldDeviceConnected = false; BLEServer *pServer = NULL; BLECharacteristic * pCharacteristic; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { Serial.println("MyServerCallbacks onConnect "); deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { Serial.println("*********"); Serial.print("Received Value: "); for (int i = 0; i < rxValue.length(); i++) Serial.print(rxValue[i]); Serial.println(); Serial.println("*********"); } } }; void setup() { Serial.begin(115200); while(!Serial){}; lis.begin(Wire1); if (!lis) { Serial.println("Accelerator Error!"); while(1); } lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g Serial.println("Accelerater Initialised!"); Serial.println("Starting BLE work!"); BLEDevice::init("Accelerometer"); pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(accelerometerService); pCharacteristic = pService->createCharacteristic( firstCharacteristic, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); BLEDescriptor *pDescriptor = pCharacteristic->createDescriptor( DESCRIPTOR_UUID, ATTRIB_FLAG_VOID | ATTRIB_FLAG_ASCII_Z, GATT_PERM_READ | GATT_PERM_WRITE, 2 ); pCharacteristic->setCallbacks(new MyCallbacks()); pService->start(); BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(accelerometerService); 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() { if (deviceConnected) { updateAcceleration(); } // disconnecting if (!deviceConnected && oldDeviceConnected) { delay(500); // give the bluetooth 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; } } void updateAcceleration() { float x_values, y_values, z_values; x_values = lis.getAccelerationX(); y_values = lis.getAccelerationY(); z_values = lis.getAccelerationZ(); String accelerometerData = String(x_values)+"|"+String(y_values)+"|"+String(z_values); Serial.println(accelerometerData); pCharacteristic->setValue(accelerometerData.c_str()); pCharacteristic->notify(); delay(20); }
Here is a short video of the output in the browser window. I'm having a little issue with my capture program so the the connection pop-up window didn't get captured.
There is lag in the data being updated in browser display.
Links to related posts
Wio Terminal Sensor Fusion - Introduction
Wio Terminal Sensor Fusion - Sensor Integration
Wio Terminal Sensor Fusion - Remote Data Display and Control using Blynk