# Wio Terminal Bluetooth Tutorial ## Wio Terminal RTL8720DN Bluetooth Getting Started This wiki introduce how to update the Bluetooth firmware for the Wireless Core Realtek RTL8720 on Wio Terminal, as well as installing all the dependent libraries for Wio Terminal to enable BLE functionality. !!!Note Please note for the current framework, **the BLE firmware and Wi-Fi firmware are different** (BLE: eRPC and Wi-Fi: AT Commands) and therefore they **cannot be used together** for a period of time. The Wi-Fi will be able to use with BLE very shortly after the BLE release. ### Update the Wireless Core Firmware(BLE) In order to use the Bluetooth functionality, you must **update the Bluetooth firmware** to the Wireless Core to Wio Terminal. #### Tools and Set-ups Same configuration as updating network firmware, Please follow [**this guide**](https://wiki.seeedstudio.com/Wio-Terminal-Network-Overview/#update-the-wireless-core-firmware) for **tools and procedures**, but use the Bluetooth Firmware files below. #### Bluetooth Firmware Files Download the Bluetooth Firmware Files from **[here](https://files.seeedstudio.com/wiki/Wio-Terminal-BLE/20200925-seeed-ambd-firmware-rpc-v1.1.0.zip)** ### Libraries Installations - Update your **ArduinoSAMD Core** for Seeed's board to the latest verison: **≥1.8.0**. #### Installing the Seeed_Arduino_rpcBLE 1. Visit the [Seeed_Arduino_rpcBLE](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE) repositories and download the entire repo to your local drive. 2. Now, the library can be installed to the Arduino IDE. Open the Arduino IDE, and click `sketch` -> `Include Library` -> `Add .ZIP Library`, and choose the `Seeed_Arduino_rpcBLE` file that you've have just downloaded. ![InstallLibrary](https://files.seeedstudio.com/wiki/Wio-Terminal/img/Xnip2019-11-21_15-50-13.jpg) #### Installing the Seeed_Arduino_rpcUnified 1. Visit the [Seeed_Arduino_rpcUnified](https://github.com/Seeed-Studio/Seeed_Arduino_rpcUnified) repositories and download the entire repo to your local drive. 2. Now, the library can be installed to the Arduino IDE. Open the Arduino IDE, and click `sketch` -> `Include Library` -> `Add .ZIP Library`, and choose the `Seeed_Arduino_rpcUnified` file that you've have just downloaded. ## Client and Server Introduction This wiki introduces Client and server communicate function via BLE using the Wio terminal. <div align=center><img width = 400 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/Wio-connect.png"/></div> ### **Hardware required** - [**Wio terminal**](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) !!!Note If you have the Wio terminal, Please visit the [**Bluetooth Overview**](https://wiki.seeedstudio.com/Wio-Terminal-Bluetooth-Overview/) to updated the latest BLE firmware on RTL8720 and downloaded the dependant Arduino libraries. ### **Overview** #### **what is client and server** - The client made a request to the Server for data communication which allows a device to wirelessly exchange data with other Bluetooth devices. - The server provides data services to the Client, it encapsulates data through characteristic. Multiple characteristics form a Service, therefore service is a basic BLE application. - Client and Server are communication relations, They can both as master or slave. #### **What is UUID** - UUID is generally used for identifying information that needs to be unique within a system or network thereof. - All the BLE device has Service UUID, characteristic UUID and descriptor UUID, All the UUID of products should be uniqueness and low probability being repeated makes them useful for being associative keys in databases and identifiers for physical hardware within an organization. #### **BLE Server on Wio terminal** The Wio terminal with Bluetooth Low Energy can act as either server and client. The server advertises its existence. And it can be found by other devices and it contains the data that the client can read. The BLE supports two types of modes such as Broadcast mode and Mesh network mode. In broadcast mode, the server transmits data to many clients that are connected and in a mesh network mode, all the devices are connected. Both server and client have a “SERVICE UUID” to make a connection between server and client. Inside this service, there can be several “characteristics” which are defined by characteristic UUID’s. We use two characteristics TX and RX to send data to and receive data from the client. The Wio terminal (acting as the server) “notifies” the client via the TX characteristic UUID and data is sent to the Wio terminal and received via the RX characteristic UUID. However, since there is sending and receiving, TX on the Wio terminal is actually RX on the Android app. #### **nRF Connect APP usage** The nRF connect APP is used to search the BLE device of UUID and MAC address when you have not idea what the UUID and MAC address of the device is, also it is able to communicate with BLE device. - Download the [**nRF Connect APP**](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en) on your smartphone. - Scan the BLE device. - Find out the BLE device and connect it, then you will see the UUID and MAC address. - You can sent or revice the data on the Characteristic. There are BLE devices scanned by the nRF Connect APP. <div align=center><img width = 400 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/nRF-device-scan.png"/></div> On the characteristic, that has up arrow which is mean sent to data to the server, and down arrow means to receive the data from the server. <div align=center><img width = 400 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/interface.png"/></div> The interface option is according to the devices function, for example, i was connected to a Wio terminal(server) with a simple function, so there are only have one Service UUID with difference function characteristic, it depends on the complicacy of the equipment. ### **BLE Client usage** This example the Wio terminal as Client to search around all the BLE devices, and then display the BLE devices name and MAC address via BLE. - You need a Wio terminal with [**latest BLE firmware**](https://files.seeedstudio.com/wiki/Wio-Terminal-BLE/20200914-seeed-ambd-firmware-rpc-v1.0.0.zip). - Setup the Server UUID and MAC address on the code. - Upload the [**Client code**](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/blob/master/examples/BLE_client/BLE_client.ino) on the Wio terminal. #### Client code snippet In the code, we need to put the UUID and characteristic UUID service of the server which you want to connect that device. !!!note If you do not konw the MAC address and UUID of device, please go to the **nRF Connect APP** page. ```cpp // The remote service we wish to connect to. static BLEUUID serviceUUID(0x180F); // The characteristic of the remote service we are interested in. static BLEUUID charUUID(0x2A19); ``` !!!Note The UUID of code was defined by us and it just for the test, Normally The UUID format for commercial products is different to present, for example, xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. Update the MAC address of the device you want to connect that device on the code. ```cpp uint8_t bd_addr[6] = {0x7d, 0x18, 0x1b, 0xf1, 0xf7, 0x2c}; // MAC address: 2c:f7:f1:1b:18:7d ``` !!!Note A Bluetooth MAC address is designed to be unique and is traceable to the chip manufacturer, in addition, you need put the MAC address in reverse order. Connect to the remove BLE Server. ```cpp pClient->connect(myDevice); ``` Obtain a reference to the service we are after in the remote BLE server. ```cpp BLERemoteService* pRemoteService = pClient->getService(serviceUUID); ``` Obtain a reference to the characteristic in the service of the remote BLE server. ```cpp pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); ``` #### **Client code** ```cpp #include "BLEDevice.h" #include "Seeed_erpcUnified.h" #include <BLEScan.h> #include <BLEAdvertisedDevice.h> // The remote service we wish to connect to. static BLEUUID serviceUUID(0x180F); // The characteristic of the remote service we are interested in. static BLEUUID charUUID(0x2A19); static boolean doConnect = false; static boolean connected = false; static boolean doScan = false; static BLERemoteCharacteristic* pRemoteCharacteristic; static BLEAdvertisedDevice* myDevice; uint8_t bd_addr[6] = {0x7d, 0x18, 0x1b, 0xf1, 0xf7, 0x2c}; BLEAddress BattServer(bd_addr); static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { Serial.print("Notify callback for characteristic "); Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str()); Serial.print(" of data length "); Serial.println(length); Serial.print("data: "); Serial.print(*(uint8_t *)pData); } class MyClientCallback : public BLEClientCallbacks { void onConnect(BLEClient* pclient) { } void onDisconnect(BLEClient* pclient) { connected = false; Serial.println("onDisconnect"); } }; bool connectToServer() { Serial.print("Forming a connection to "); Serial.println(myDevice->getAddress().toString().c_str()); BLEClient* pClient = BLEDevice::createClient(); Serial.println(" - Created client"); pClient->setClientCallbacks(new MyClientCallback()); pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private) Serial.println(" - Connected to server"); BLERemoteService* pRemoteService = pClient->getService(serviceUUID); Serial.println(serviceUUID.toString().c_str()); if (pRemoteService == nullptr) { Serial.print("Failed to find our service UUID: "); Serial.println(serviceUUID.toString().c_str()); pClient->disconnect(); return false; } Serial.println(" - Found our service"); // Obtain a reference to the characteristic in the service of the remote BLE server. pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); if (pRemoteCharacteristic == nullptr) { Serial.print("Failed to find our characteristic UUID: "); Serial.println(charUUID.toString().c_str()); pClient->disconnect(); return false; } Serial.println(" - Found our characteristic"); // Read the value of the characteristic. if(pRemoteCharacteristic->canRead()) { Serial.println(" - can read start"); std::string value = pRemoteCharacteristic->readValue(); Serial.print("The characteristic value was: "); Serial.println(value.c_str()); } if(pRemoteCharacteristic->canNotify()) pRemoteCharacteristic->registerForNotify(notifyCallback); connected = true; return true; } //Scan for BLE servers and find the first one that advertises the service we are looking for. class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { Serial.print("BLE Advertised Device found: "); Serial.println(advertisedDevice.toString().c_str()); if (memcmp(advertisedDevice.getAddress().getNative(),BattServer.getNative(), 6) == 0) { Serial.print("BATT Device found: "); Serial.println(advertisedDevice.toString().c_str()); BLEDevice::getScan()->stop(); Serial.println("new BLEAdvertisedDevice"); myDevice = new BLEAdvertisedDevice(advertisedDevice); Serial.println("new BLEAdvertisedDevice done"); doConnect = true; doScan = true; } // onResult } }; // MyAdvertisedDeviceCallbacks void setup() { Serial.begin(115200); while(!Serial){}; delay(2000); Serial.println("Starting Arduino BLE Client application..."); BLEDevice::init(""); BLEScan* pBLEScan = BLEDevice::getScan(); pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setInterval(1349); pBLEScan->setWindow(449); pBLEScan->setActiveScan(true); pBLEScan->start(5, false); } // End of setup. void loop() { if (doConnect == true) { if (connectToServer()) { Serial.println("We are now connected to the BLE Server."); } else { Serial.println("We have failed to connect to the server; there is nothin more we will do."); } doConnect = false; } Serial.printf("."); delay(1000); } // End of loop ``` #### **Code running result** This is a simple Client code demonstration without connecting any devices, the Wio terminal scan around BLE devices and displays the devices. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/BLE-device-print.png"/></div> ### **BLE Server Usage** This example the Wio terminal as Server to connect the other Wio terminal(Client), and then receive the Client require via BLE. #### **Server code Snippet** You can define the BLE device name as below: ```cpp BLEDevice::init("UART Service"); ``` You need to define the UUID for the server device on the Wio terminal. ```cpp #define SERVICE_UUID "180f" #define CHARACTERISTIC_UUID "2a19" #define DESCRIPTOR_UUID "4545" ``` Create BLE server ```cpp BLEServer *pServer = BLEDevice::createServer(); ``` Create BLE service using the server UUID. ```cpp BLEService *pService = pServer->createService(SERVICE_UUID); ``` Add a characteristics. ```cpp BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE ); pCharacteristic->setValue("Hello World says Neil"); ``` Read and write function. ```cpp 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 ); ``` Start BLE service ```cpp pService->start(); ``` Advertising allows devices to broadcast information defining their intentions. Which means that when a mobile device has received a Bluetooth message, the recipient has the choice to either accept or decline the message. The recipient needs to positively indicate that they wish to receive marketing messages. ```cpp BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); ``` #### **Client and server commnication** We made a simple test in this example, the Wio terminal Client connects with the Wio terminal Server, when Client found the server then they will connect meanwhile server will text Client a message. - You need two Wio terminals. - You need to create the UUID to provide Client to connect it. - Please download the [**Client**](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/tree/master/examples/BLE_client) and [**Server**](https://github.com/Seeed-Studio/Seeed_Arduino_rpcBLE/tree/master/examples/BLE_server) code in this **github**. - Upload the Client code in the Wio terminal. - Upload the Server code in the other Wio terminal. When upload and running **The server code**, you will see it keep printing "unpaired" on the Arduino IDE monitor before connect the Client. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/Server_side3.png"/></div> After connected to the Client, it will stop print message and the Client will print message from server. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/Client_side7.png"/></div> #### Server code ```cpp #include <BLEDevice.h> #include <BLEServer.h> #include "Seeed_erpcUnified.h" // See the following for generating UUIDs: #define SERVICE_UUID "180f" #define CHARACTERISTIC_UUID "2a19" #define DESCRIPTOR_UUID "4545" 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){}; Serial.println("Starting BLE work!"); BLEDevice::init("UART servicess"); BLEServer *pServer = BLEDevice::createServer(); BLEService *pService = pServer->createService(SERVICE_UUID); BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, 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->setValue("Hello World says Neil"); pCharacteristic->setCallbacks(new MyCallbacks()); 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: Serial.println("unpaired"); delay(2000); } ``` ### Server connect to Client of Smartphone <div align=center><img src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/vidoeh-GIF.gif"/></div> This example is using a smartphone as a Client to connect the Wio terminal(server), and the Wio terminal is able to receive the message from the Client. - Download the nRF connect APP on the Phone. - Upload the code on the Wio terminal. - Open the nRF connect APP to search the Wio terminal and then connect it. !!!note Check the device name on the code, that will help you search it. #### **Code** ```cpp #include <BLEDevice.h> #include <BLEServer.h> #include <BLE2902.h> #include <TFT_eSPI.h> // Hardware-specific library #include <SPI.h> TFT_eSPI tft = TFT_eSPI(); // Invoke custom library TFT_eSprite spr = TFT_eSprite(&tft); // Sprite BLEServer *pServer = NULL; BLECharacteristic * pTxCharacteristic; bool deviceConnected = false; bool oldDeviceConnected = false; String Value11; #define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" #define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { deviceConnected = true; spr.fillSprite(TFT_BLACK); spr.createSprite(240, 100); spr.setTextColor(TFT_WHITE, TFT_BLACK); spr.setFreeFont(&FreeSansBoldOblique12pt7b); spr.drawString("Message: ", 20, 70); spr.setTextColor(TFT_GREEN, TFT_BLACK); spr.drawString("status: connected",10 ,5); spr.pushSprite(0, 0); }; void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.print("123123"); spr.fillSprite(TFT_BLACK); spr.createSprite(240, 100); spr.setTextColor(TFT_WHITE, TFT_BLACK); spr.setFreeFont(&FreeSansBoldOblique12pt7b); spr.drawString("Message: ", 20, 70); spr.setTextColor(TFT_RED, TFT_BLACK); spr.drawString("status: disconnect",10 ,5); spr.pushSprite(0, 0); } }; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); if (rxValue.length() > 0) { spr.fillSprite(TFT_BLACK); spr.setTextColor(TFT_WHITE, TFT_BLACK); spr.setFreeFont(&FreeSansBoldOblique9pt7b); for (int i = 0; i < rxValue.length(); i++){ // Serial.print(rxValue[i]); spr.drawString((String)rxValue[i],10 + i*15,0); spr.pushSprite(10, 100); } } } }; void setup() { tft.begin(); tft.init(); tft.setRotation(3); tft.fillScreen(TFT_BLACK); BLEDevice::init("UART Servicess"); //device name define // Create the BLE Server pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // Create the BLE Service BLEService *pService = pServer->createService(SERVICE_UUID); // Create a BLE Characteristic pTxCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_READ ); pTxCharacteristic->setAccessPermissions(GATT_PERM_READ); pTxCharacteristic->addDescriptor(new BLE2902()); BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE ); pRxCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); pRxCharacteristic->setCallbacks(new MyCallbacks()); // Start the service pService->start(); // Start advertising pServer->getAdvertising()->start(); spr.fillSprite(TFT_BLACK); spr.createSprite(240, 100); spr.setTextColor(TFT_WHITE, TFT_BLACK); spr.setFreeFont(&FreeSansBoldOblique12pt7b); spr.drawString("status: disconnect",10 ,5); spr.drawString("Message: ", 20, 70); spr.pushSprite(0, 0); } void loop() { // disconnecting if (!deviceConnected && oldDeviceConnected) { delay(500); // give the bluetooth stack the chance to get things ready pServer->startAdvertising(); // restart advertising oldDeviceConnected = deviceConnected; } // connecting if (deviceConnected && !oldDeviceConnected) { // do stuff here on connecting oldDeviceConnected = deviceConnected; } } ``` ## Using Web Bluetooth APIs with Wio Terminal This is the wiki of interacting Wio Terminal's Bluetooth Feature with the [**Web Bluetooth APIs**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API). The Web Bluetooth APIs provides you the ability of interacting Bluetooth devices on web browsers. <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/exmaple.gif"/></div> ### What is Web Bluetooth API Until now, the ability to interact with bluetooth devices has been possible only for native apps. The [**Web Bluetooth API**](https://developers.google.com/web/updates/2015/07/interact-with-ble-devices-on-the-web) aims to change this and brings it to web browsers as well. Alongside efforts like [Physical Web](https://google.github.io/physical-web/), people can walk up to and interact with devices straight from the web. Check out [this drone controlled from a web app](https://www.youtube.com/watch?v=yILD_ZdXJW4) video to get a sense of how that would work. ### Web Bluetooth Simple Example The following example demonstrate how to set up Wio Terminal and use a simple HTML site to interact the Web Bluetooth API with Wio Terminal's Bluetooth. <div align=center><video width="560" height="315" controls> <source src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/simple.mp4" type="video/mp4"> </video></div> #### Arduino Set-Up - Please follow the [**Wio Terminal Bluetooth Overview**](https://wiki.seeedstudio.com/Wio-Terminal-Bluetooth-Overview/) to flash Bluetooth firmware to Wio Terminal and download dependent libraries before the followings. - Copy the following code and upload to Wio Terminal: ```cpp #include <rpcBLEDevice.h> #include <BLEServer.h> #include <BLE2902.h> bool _BLEClientConnected = false; uint8_t level = 10; #define BatteryService BLEUUID((uint16_t)0x180F) BLECharacteristic BatteryLevelCharacteristic(BLEUUID((uint16_t)0x2A19), BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY); class MyServerCallbacks : public BLEServerCallbacks { void onConnect(BLEServer* pServer) { _BLEClientConnected = true; }; void onDisconnect(BLEServer* pServer) { _BLEClientConnected = false; } }; /* ############################################################### CALL back to receive data from Phone */ #define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string rxValue = pCharacteristic->getValue(); Serial.println(rxValue[0]); 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 initBLE() { BLEDevice::init("BLE Battery"); // Create the BLE Server BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // Create the BLE Service BLEService *pBattery = pServer->createService(BatteryService); pBattery->addCharacteristic(&BatteryLevelCharacteristic); BatteryLevelCharacteristic.addDescriptor(new BLE2902()); /* ############################################################### define callback */ BLECharacteristic *pWriteCharacteristic = pBattery->createCharacteristic( CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE ); pWriteCharacteristic->setAccessPermissions(GATT_PERM_READ | GATT_PERM_WRITE); pWriteCharacteristic->setCallbacks(new MyCallbacks()); /* ############################################################### */ pServer->getAdvertising()->addServiceUUID(BatteryService); pBattery->start(); // Start advertising pServer->getAdvertising()->start(); } void setup() { Serial.begin(115200); // while(!Serial); Serial.println("--- Wio Terminal BLE Battery Level Indicator ---"); initBLE(); } void loop() { BatteryLevelCharacteristic.setValue(&level, 1); BatteryLevelCharacteristic.notify(); delay(3000); level++; Serial.print("Battery Level: "); Serial.println(int(level)); if (int(level)==100) level=0; } ``` The above code configures Wio Terminal with the Bluetooth discoverable name **`BLE Battery`** and as Bluetooth Server and establish a Battery BLE Service. This is important and needs to match with Web Bluetooth APIs HTML Site later. #### Web Bluetooth API HTML Website Now Wio Terminal is all set-up, we need to write a HTML site with the Web Bluetooth APIs so that they can interact. Check the following for reference: - Download the [**`webbluetooth.html`**](https://github.com/ansonhe97/WioTerminal-WebBluetooth/blob/main/webbluetooth.html) from here. - Open the `webbluetooth.html` using the **Latest Google Chrome or Microsoft Edge**(which supports Web Bluetooth APIs). - **Right click** on the site and select **Inspect** (CMD+OPT+I for macOS and Ctrl+Shift+I for Windows), select **Control Console**: <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/1.png"/></div> - Click on the **Connect with BLE device** button on the site. You should see that the `BLE Battery`(Wio Terminal) appeared in the connecting window. Click on **Connect**. >Note: The Web Bluetooth APIs actually will discover all the BLE devices nearby, but here used filter to only limited to the BLE device named BLE Battery. <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/2.png"/></div> - Click on **Start** button on the site and it will start receiving data battery information transmitted from Wio Terminal! Web Bluetooth API Site Console: <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/3.png"/></div> Arduino Serial Monitor Control Console: <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/4.png"/></div> - Now the Wio Terminal is interacting with the site using Web Bluetooth APIs! This makes the BLE feature more much interesting that you can have information transmitted though Web Browsers! ### Visualizing Accelerator Data on Web Site using Web Bluetooth APIs The following is a good example of using Web Bluetooth APIs on a Site. This example site connects the Wio Terminal using Web Bluetooth and visualize the onboard accelerator data. <div align=center><video width="560" height="315" controls> <source src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/example.mp4" type="video/mp4"> </video></div> #### Arduino Set-up - Please make sure you have followed the [**Wio Terminal's Accelerator Overview**](https://wiki.seeedstudio.com/Wio-Terminal-IMU-Overview/) before the followings. - Download the **[`WebBluetooth-Accelerator.ino`](https://github.com/Seeed-Studio/Seeed_Arduino_Sketchbook/blob/master/examples/WioTerminal_WebBluetooth/WioTerminal_WebBluetooth.ino) Example** or Copy the following code in Arduino IDE. ```cpp #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("Accelerater 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); } ``` - Upload the example to Wio Terminal. #### Web Bluetooth API HTML Website - Open the **[Web Bluetooth Accelerometer Plotter For Wio Terminal](https://seeed-studio.github.io/Seeed_Arduino_Sketchbook/)** Website. > You can also read the [**HTML source code**](https://github.com/Seeed-Studio/Seeed_Arduino_Sketchbook/blob/web-bluetooth/docs/index.html) here, for more reference. - Connect your device named `Accelerator` (Wio Terminal), and you should be able to see the Accelerator data on the Web Site! <div align=center><img src="https://files.seeedstudio.com/wiki/Wio-Terminal-Web-Bluetooth/web-acc.gif"/></div> This means you can write a Web Bluetooth Interact Website with Wio Terminal! ### Resources - [**Web Bluetooth APIs Specs**](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API) - [**Web Bluetooth APIs Examples**](https://googlechrome.github.io/samples/web-bluetooth/index.html) - [**Implementation Bugs**](https://crbug.com/?q=component:Blink>Bluetooth) - [**Web Bluetooth Spec**](https://webbluetoothcg.github.io/web-bluetooth) ## Wio terminal basic on BLE ibeacon <div align=center><img width = 400 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/PIC-ibeacon.png"/></div> ### Overview Wio terminal is a powerful IoT device having inbuilt support for classic Bluetooth and Bluetooth LOW Energy (BLE), the classic Bluetooth is used to in the Bluetooth audio module, file, or large code stream data transmission, the BLE is used for battery optimized applications, such as Bluetooth beacons, fitness bands, proximity advertisements, etc. So we are able to according to users required to connecting with some specific function module, then as a beacon on the specific occasion. The previous Wio terminal tutorials we has to introduce the Client mode and Server mode to using on the wio terminal, if there is any doubt please review [**Client and Server introduction**](https://wiki.seeedstudio.com/Wio-terminal-BLE-introduction/) In this tutorial we are going to build a BLE Ibeacon using Wio terminal, in addition, we will use a smartphone to present the iBeacon information. I assume that you are already know on how to use the Wio terminal with Arduino IDE, if not fall back to [**the Wio terminal get start**](https://wiki.seeedstudio.com/Wio-Terminal-Getting-Started/). ### hardware required - [**Wio terminal**](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) - **Type-C cable** - [**Wio terminal chassis battery**](https://www.seeedstudio.com/Wio-Terminal-Chassis-Battery-p-4516.html) ### Software required - Downlord the [**Arduino IDE**](https://www.arduino.cc/en/main/software) on PC - Download the [**nRF Connect APP**](https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en_US) on the smartphone !!!note If you are unfamiliar on how to use nRF connect APP, please view this [**tutorial**](https://wiki.seeedstudio.com/Wio-terminal-BLE-introduction/#nrf-connect-app-usage). ### Instruction #### **Wio terminal iBeacon test** This is a simple test for scan the Wio terminal iBeacon device and presents the information, make sure the Wio terminal Ibeacon device can be detected, you will see the Ibeacon specific icon. #### **the nRF connect APP** 1. Download the **nRF Connect APP** then open the the APP, find the **SCAN** option on the upper right, you will see the Wio terminal iBeacon devices on the list, there are MAC address, RSSI(dBm) and connection delay time. <div align=center><img width = 400 src="https://files.seeedstudio.com/wiki/wio%20terminal%20bluetooth/nRF_interface.jpg"/></div> !!!Note In this test the device did not named, so it will display N/A. **Test code** ```CPP #include "sys/time.h" #include "BLEDevice.h" #include "BLEBeacon.h" BLEAdvertising *pAdvertising; //struct timeval now; #define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) void setBeacon() { BLEBeacon oBeacon = BLEBeacon(); oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); oBeacon.setMajor(0x007B); oBeacon.setMinor(0x01C8); BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 std::string strServiceData = ""; strServiceData += (char)26; // Len strServiceData += (char)0xFF; // Type strServiceData += oBeacon.getData(); oAdvertisementData.addData(strServiceData); pAdvertising->setAdvertisementData(oAdvertisementData); pAdvertising->setScanResponseData(oScanResponseData); pAdvertising->setAdvertisementType(GAP_ADTYPE_ADV_NONCONN_IND); } void setup() { Serial.begin(115200); while(!Serial){}; // Create the BLE Device BLEDevice::init(""); pAdvertising = BLEDevice::getAdvertising(); setBeacon(); // Start advertising pAdvertising->start(); Serial.println("Advertizing started..."); delay(100); Serial.printf("in deep sleep\n"); } void loop() { delay(1000); } ``` #### Ibeacon simple exhibition This demo is introduced how to use Wio terminal on some specific occasion, for example, the Wio terminal Ibeacon can advertising the gateway information to guide the people, as below picture, there are door-1, door-2...etc, and door-1 inside have product A and the instruction. We can install the Wio terminal in each door to advertising information and display the introduction information on the screen. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/Ibeacon_demo_pic.png"/></div> Open the nRF connect APP we will see the "Wio" Ibeacon device on the list, then click the device, there will display the device UUID, RSSI, and manufacturer data. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/ibecon_formatttttt.png"/></div> Click manufacturer data, there will display 3 options which are Manufacturer data(Bluetooth Core 4.1), Manufacturer data, and Text(UTF-8). Then click the text(UTF-8), the manufacturer data will transfer to normal data. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/ibeacon_data_format.png"/></div> The Text(UTF-8) displays the gateway information, A in door-1, B in door-2, thus people will know A and B where they are. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/Ibeacon_device_info.png"/></div> we can see, after people enter the door, they will see about A or B more detail, such as history or other text introduction that depends on the usage occasion. <div align=center><img width = 500 src="https://files.seeedstudio.com/wiki/Wio-terminal-BLE-Ibeacon/Ibeacon_product_new.png"/></div> ### Code ```CPP #include "sys/time.h" #include "BLEDevice.h" #include "BLEBeacon.h" #include <TFT_eSPI.h> // Hardware-specific library #include <SPI.h> TFT_eSPI tft = TFT_eSPI(); // Invoke custom library TFT_eSprite spr = TFT_eSprite(&tft); // Sprite LIS3DHTR<TwoWire> lis; BLEAdvertising *pAdvertising; #define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit #define SERVICE_UUID 0x1801 #define SERVICE_UUID1 0x1802 #define SERVICE_UUID2 0x1803 void setBeacon() { BLEBeacon oBeacon = BLEBeacon(); oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); oBeacon.setMajor(0x007B); oBeacon.setMinor(0x01C8); BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 std::string strServiceData = ""; strServiceData += (char)26; // Len strServiceData += (char)0xFF; // Type strServiceData += oBeacon.getData(); oAdvertisementData.addData(strServiceData); union cracked_float_t { float f; uint32_t l; word w[sizeof(float) / sizeof(word)]; byte b[sizeof(float)]; }; oScanResponseData.setName("wio"); oScanResponseData.setManufacturerData("oxA-door-1"); // Ibeacon information(MAX:31 byte) oScanResponseData.setManufacturerData("oxB-door-2"); pAdvertising->setAdvertisementData(oAdvertisementData); pAdvertising->setScanResponseData(oScanResponseData); pAdvertising->setAdvertisementType(GAP_ADTYPE_ADV_SCAN_IND); spr.fillSprite(TFT_BLACK); spr.createSprite(240, 160); spr.fillSprite(TFT_BLACK); spr.setTextColor(TFT_WHITE, TFT_BLACK); spr.setFreeFont(&FreeSansBoldOblique12pt7b); spr.drawString("what is A", 20 , 10); // product introduction spr.drawString("The A history: .....", 20 , 35); spr.drawString("what is B", 20 , 110); spr.drawString("The B history: .....", 20 , 135); spr.pushSprite(0, 0); } void setup() { tft.begin(); tft.init(); tft.setRotation(3); tft.fillScreen(TFT_BLACK); Serial.begin(115200); // Create the BLE Device BLEDevice::init(""); lis.begin(Wire1); if (!lis) { Serial.println("ERROR"); while (1); } lis.setOutputDataRate(LIS3DHTR_DATARATE_25HZ); //Data output rate lis.setFullScaleRange(LIS3DHTR_RANGE_2G); //Scale range set to 2g pAdvertising = BLEDevice::getAdvertising(); Serial.println("Advertizing started..."); delay(100); } void loop() { setBeacon(); // Start advertising pAdvertising->start(); delay(5000); pAdvertising->stop(); delay(1000); } ``` Here is the link for [**<font color=red>Wio Terminal Getting Started</font>**](https://hackmd.io/@amebaiot/SyeByHzYD). Here is the link for [**<font color=red>Wio Terminal Wifi Tutorial</font>**](https://hackmd.io/@amebaiot/BkD_V_MKD).