This shows you the differences between two versions of the page.
iothings:laboratoare:2022:lab7 [2023/11/20 21:28] dan.tudose [Project Overview] |
iothings:laboratoare:2022:lab7 [2023/11/20 22:15] (current) dan.tudose [Web BLE Application] |
||
---|---|---|---|
Line 94: | Line 94: | ||
* humidity: **0x246F** | * humidity: **0x246F** | ||
+ | ==== Mobile App ==== | ||
+ | {{ :iothings:laboratoare:2022:nrf_connect.png?150|}} | ||
+ | To verify the proper creation of the BLE Server and to receive notifications for temperature, humidity, and pressure, we'll utilize a smartphone application. | ||
+ | |||
+ | Most contemporary smartphones come equipped with BLE capabilities. You can check your smartphone's specifications to confirm its BLE compatibility. | ||
+ | |||
+ | Note: The smartphone can function as either a client or a server. In this context, it will act as the client, establishing a connection with the Sparrow BLE server. | ||
+ | |||
+ | For our testing purposes, we'll employ a free application named nRF Connect for Mobile, developed by Nordic Semi. This app is available on both Android ([[https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp&hl=en_US| Google Play Store]]) and iOS. To install the app, simply go to the Google Play Store or App Store, search for "nRF Connect for Mobile," and proceed with the installation. | ||
+ | |||
+ | ==== Sparrow BLE Service ==== | ||
+ | |||
+ | Here are the steps to create an BLE peripheral with an Environmental Sensing BLE service with temperature, humidity, and pressure, characteristics: | ||
+ | |||
+ | - Create a BLE device (server) with a name of your choice (we’ll call it ESP32_BME680, but you can call it any other name). | ||
+ | - Create an Environmental Sensing service (UUID: 0x181A). | ||
+ | - Add characteristics to that service: pressure (0x2A6D), temperature (0x2A6E) and humidity (0x246F) | ||
+ | - Add descriptors to the characteristics. | ||
+ | - Start the BLE server. | ||
+ | - Start advertising so BLE clients can connect and read the characteristics. | ||
+ | - Once a connection is established with a client, it will write new values on the characteristics and will notify the client, every time there’s a change. | ||
+ | |||
+ | |||
+ | Copy the following code to the Arduino IDE, modify it and upload it to your board. | ||
+ | |||
+ | <code C> | ||
+ | #include <BLEDevice.h> | ||
+ | #include <BLEServer.h> | ||
+ | #include <BLEUtils.h> | ||
+ | #include <BLE2902.h> | ||
+ | #include "Zanshin_BME680.h" | ||
+ | |||
+ | //BLE server name | ||
+ | #define bleServerName "Sparrow_BME680" | ||
+ | |||
+ | // Default UUID for Environmental Sensing Service | ||
+ | // https://www.bluetooth.com/specifications/assigned-numbers/ | ||
+ | #define SERVICE_UUID (BLEUUID((uint16_t)0x181A)) | ||
+ | |||
+ | // Temperature Characteristic and Descriptor (default UUID) | ||
+ | // Check the default UUIDs here: https://www.bluetooth.com/specifications/assigned-numbers/ | ||
+ | BLECharacteristic temperatureCharacteristic(BLEUUID((uint16_t)0x2A6E), BLECharacteristic::PROPERTY_NOTIFY); | ||
+ | BLEDescriptor temperatureDescriptor(BLEUUID((uint16_t)0x2902)); | ||
+ | |||
+ | // Humidity Characteristic and Descriptor (default UUID) | ||
+ | BLECharacteristic humidityCharacteristic(BLEUUID((uint16_t)0x2A6F), BLECharacteristic::PROPERTY_NOTIFY); | ||
+ | BLEDescriptor humidityDescriptor(BLEUUID((uint16_t)0x2902)); | ||
+ | |||
+ | // Pressure Characteristic and Descriptor (default UUID) | ||
+ | BLECharacteristic pressureCharacteristic(BLEUUID((uint16_t)0x2A6D), BLECharacteristic::PROPERTY_NOTIFY); | ||
+ | BLEDescriptor pressureDescriptor(BLEUUID((uint16_t)0x2902)); | ||
+ | |||
+ | // Create a sensor object | ||
+ | BME680_Class BME680; | ||
+ | |||
+ | bool deviceConnected = false; | ||
+ | |||
+ | //Setup callbacks onConnect and onDisconnect | ||
+ | class MyServerCallbacks: public BLEServerCallbacks { | ||
+ | void onConnect(BLEServer* pServer) { | ||
+ | deviceConnected = true; | ||
+ | Serial.println("Device Connected"); | ||
+ | }; | ||
+ | void onDisconnect(BLEServer* pServer) { | ||
+ | deviceConnected = false; | ||
+ | Serial.println("Device Disconnected"); | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | void setup() { | ||
+ | // Start serial communication | ||
+ | Serial.begin(115200); | ||
+ | |||
+ | // Start BME sensor | ||
+ | while (!BME680.begin(I2C_STANDARD_MODE)) { // Start BME680 using I2C, use first device found | ||
+ | Serial.print(F("- Unable to find BME680. Trying again in 5 seconds.\n")); | ||
+ | delay(5000); | ||
+ | } // of loop until device is located | ||
+ | Serial.print(F("- Setting 16x oversampling for all sensors\n")); | ||
+ | BME680.setOversampling(TemperatureSensor, Oversample16); // Use enumerated type values | ||
+ | BME680.setOversampling(HumiditySensor, Oversample16); // Use enumerated type values | ||
+ | BME680.setOversampling(PressureSensor, Oversample16); // Use enumerated type values | ||
+ | Serial.print(F("- Setting IIR filter to a value of 4 samples\n")); | ||
+ | BME680.setIIRFilter(IIR4); // Use enumerated type values | ||
+ | Serial.print(F("- Setting gas measurement to 320\xC2\xB0\x43 for 150ms\n")); // "degC" symbols | ||
+ | BME680.setGas(320, 150); // 320 deg.C for 150 milliseconds | ||
+ | |||
+ | // Create the BLE Device | ||
+ | BLEDevice::init(bleServerName); | ||
+ | |||
+ | // Create the BLE Server | ||
+ | BLEServer *pServer = BLEDevice::createServer(); | ||
+ | pServer->setCallbacks(new MyServerCallbacks()); | ||
+ | |||
+ | // Create the BLE Service | ||
+ | BLEService *bmeService = pServer->createService(SERVICE_UUID); | ||
+ | |||
+ | // Create BLE Characteristics and corresponding Descriptors | ||
+ | bmeService->addCharacteristic(&temperatureCharacteristic); | ||
+ | temperatureCharacteristic.addDescriptor(&temperatureDescriptor); | ||
+ | | ||
+ | bmeService->addCharacteristic(&humidityCharacteristic); | ||
+ | humidityCharacteristic.addDescriptor(&humidityDescriptor); | ||
+ | |||
+ | bmeService->addCharacteristic(&pressureCharacteristic); | ||
+ | pressureCharacteristic.addDescriptor(&pressureDescriptor); | ||
+ | | ||
+ | // Start the service | ||
+ | bmeService->start(); | ||
+ | |||
+ | // Start advertising | ||
+ | pServer->getAdvertising()->start(); | ||
+ | Serial.println("Waiting a client connection to notify..."); | ||
+ | } | ||
+ | |||
+ | void loop() { | ||
+ | if (deviceConnected) { | ||
+ | | ||
+ | static int32_t temp, hum, pres, gas; // BME readings | ||
+ | | ||
+ | BME680.getSensorData(temp, hum, pres, gas); // Get readings | ||
+ | | ||
+ | float t = (float)((int8_t)(temp / 100)); | ||
+ | t += (float)((uint8_t)(temp % 100))/100.0; | ||
+ | |||
+ | float h = (float)((int8_t)(hum / 1000)); | ||
+ | h += (float)((uint16_t)(hum % 1000)))/1000.0; | ||
+ | |||
+ | float p = (float)((int16_t)(pres / 100)); | ||
+ | p += (float)((uint8_t)(pres % 100))/100.0; | ||
+ | | ||
+ | //Notify temperature reading | ||
+ | uint16_t temperature = (uint16_t)t; | ||
+ | //Set temperature Characteristic value and notify connected client | ||
+ | temperatureCharacteristic.setValue(temperature); | ||
+ | temperatureCharacteristic.notify(); | ||
+ | Serial.print("Temperature Celsius: "); | ||
+ | Serial.print(t); | ||
+ | Serial.println(" ºC"); | ||
+ | |||
+ | //Notify humidity reading | ||
+ | uint16_t humidity = (uint16_t)h; | ||
+ | //Set humidity Characteristic value and notify connected client | ||
+ | humidityCharacteristic.setValue(humidity); | ||
+ | humidityCharacteristic.notify(); | ||
+ | Serial.print("Humidity: "); | ||
+ | Serial.print(h); | ||
+ | Serial.println(" %"); | ||
+ | |||
+ | //Notify pressure reading | ||
+ | uint16_t pressure = (uint16_t)p; | ||
+ | //Set humidity Characteristic value and notify connected client | ||
+ | pressureCharacteristic.setValue(pressure); | ||
+ | pressureCharacteristic.notify(); | ||
+ | Serial.print("Pressure: "); | ||
+ | Serial.print(p); | ||
+ | Serial.println(" hPa"); | ||
+ | | ||
+ | delay(10000); | ||
+ | } | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Upload the code to your board. After uploading, open the Serial Monitor, and restart the Sparrow by pressing the RST/EN button. | ||
+ | |||
+ | You should get a //"Waiting a client connection to notify..."// message in the Serial Monitor. | ||
+ | |||
+ | Then, go to your smartphone, open the nRF Connect app from Nordic, and start scanning for new devices. You should find a device called **Sparrow_BME680**, this is the BLE server name you defined earlier. | ||
+ | |||
+ | Connect to it. You’ll see that it displays the Environmental Sensing service with the temperature, humidity, and pressure characteristics. Click on the down arrows to activate the notifications. | ||
+ | |||
+ | Then, click on the second icon (the one that looks like a " mark) at the left to change the format. You can change to unsigned int for all characteristics. You’ll start seeing the temperature, humidity, and pressure values being reported every 10 seconds. | ||
+ | |||
+ | ===== Web BLE Application ===== | ||
+ | |||
+ | Follow the tutorial [[https://randomnerdtutorials.com/esp32-web-bluetooth/| here]] to learn how to create a Web application that connects directly to your Sparrow ESP32 board. You can use the web app just like a normal phone application to send and receive information over BLE from your device. | ||
+ | |||
+ | <note important>Web BLE is not currently supported by iOS phones </note> | ||
+ | |||
+ | Build the application in the tutorial and deploy the web page in your GitHub account. | ||
+ | |||
+ | === Assignment === | ||
+ | <note> Modify the web page and the BLE app to display the BME680 sensor data (temperature, pressure and humidity). </note> |