BLE example with Environmental Sensing service.

Dependencies:   BSP_B-L475E-IOT01

Hello IoT BLE

This project uses Environmental Sensing Service and its characteristics:

Characteristic values can be read or they might be observed with notifications enabled.

Please note that this example uses slightly modified Environmental service.

Also there have been some opened issues regarding value types Issue 1 and Issue 2.

Note that this application was developed as a part of a larger project Hello IoT, but can be used as a standalone.

(Source files can be found at the end of this page.)

Running the application

The sample application can be seen on any BLE scanner on a smartphone. If you don't have a scanner on your phone, please install:

Hardware requirements are in the main readme.

Building instructions

Building with mbed CLI

If you'd like to use mbed CLI to build this, then you should refer to the main readme. The instructions here relate to using the Mbed Online Compiler.

Building with Mbed Online Compiler

In order to build this example in the Mbed Online Compiler, first import the example using the Import button on the right hand side.

Next, select a platform to build for. This must either be a platform that supports BLE, for example the NRF51-DK, or one of the following:

List of platforms supporting Bluetooth Low Energy.

Or you must also add a piece of hardware and the supporting library that includes a Bluetooth Low Energy driver for that hardware, for example the K64F or NUCLEO_F401RE with the X-NUCLEO-IDB05A1

List of components supporting Bluetooth Low Energy.

Once you have selected your platform, compile the example and drag and drop the resulting binary onto your board.

Note: This example was tested with DISCO_L475VG_IOT01A (ref B-L475E-IOT01A), so when using onboard sensors instead of simulated ones, make sure you select this board.

For general instructions on using the Mbed Online Compiler, please see the mbed Handbook.

Checking for success

Note: Screen captures depicted below show what is expected from this example if the scanner used is nRF Connect. If you encounter any difficulties consider trying another scanner or another version of nRF Connect. Alternative scanners may require reference to their manuals.

  • Build the application and install it on your board as explained in the building instructions.
  • Open the BLE scanner on your phone.
  • Start a scan and connect to a device named IoT_SENSOR.

nRF Scan

  • Discover the services and the characteristics on the device. The Environmental Sensing service has the UUID 0x181A with characteristics Temperature 0x2A6E, Humidity 0x2A6F and Pressure 0x2A6D.

nRF Service

  • At this point you can read or register for notifications. In figure below, all characteristics have been registered for notification and their values should change every second.

nRF Notif

Committer:
jernej_vrscaj
Date:
Sat Dec 29 13:33:02 2018 +0000
Revision:
0:0681ebb27b3c
Initial commit.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jernej_vrscaj 0:0681ebb27b3c 1 /* mbed Microcontroller Library
jernej_vrscaj 0:0681ebb27b3c 2 * Copyright (c) 2006-2013 ARM Limited
jernej_vrscaj 0:0681ebb27b3c 3 *
jernej_vrscaj 0:0681ebb27b3c 4 * Licensed under the Apache License, Version 2.0 (the "License");
jernej_vrscaj 0:0681ebb27b3c 5 * you may not use this file except in compliance with the License.
jernej_vrscaj 0:0681ebb27b3c 6 * You may obtain a copy of the License at
jernej_vrscaj 0:0681ebb27b3c 7 *
jernej_vrscaj 0:0681ebb27b3c 8 * http://www.apache.org/licenses/LICENSE-2.0
jernej_vrscaj 0:0681ebb27b3c 9 *
jernej_vrscaj 0:0681ebb27b3c 10 * Unless required by applicable law or agreed to in writing, software
jernej_vrscaj 0:0681ebb27b3c 11 * distributed under the License is distributed on an "AS IS" BASIS,
jernej_vrscaj 0:0681ebb27b3c 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
jernej_vrscaj 0:0681ebb27b3c 13 * See the License for the specific language governing permissions and
jernej_vrscaj 0:0681ebb27b3c 14 * limitations under the License.
jernej_vrscaj 0:0681ebb27b3c 15 */
jernej_vrscaj 0:0681ebb27b3c 16
jernej_vrscaj 0:0681ebb27b3c 17 #include <events/mbed_events.h>
jernej_vrscaj 0:0681ebb27b3c 18 #include "mbed.h"
jernej_vrscaj 0:0681ebb27b3c 19 #include "ble/BLE.h"
jernej_vrscaj 0:0681ebb27b3c 20 #include "EnvironmentalService_v2.h"
jernej_vrscaj 0:0681ebb27b3c 21 //#include "debug.h"
jernej_vrscaj 0:0681ebb27b3c 22
jernej_vrscaj 0:0681ebb27b3c 23 // Uncomment this line if you want to use the board temperature sensor instead of
jernej_vrscaj 0:0681ebb27b3c 24 // a simulated one.
jernej_vrscaj 0:0681ebb27b3c 25 #define USE_BOARD_SENSORS
jernej_vrscaj 0:0681ebb27b3c 26
jernej_vrscaj 0:0681ebb27b3c 27 #ifdef USE_BOARD_SENSORS
jernej_vrscaj 0:0681ebb27b3c 28 #include "stm32l475e_iot01_tsensor.h"
jernej_vrscaj 0:0681ebb27b3c 29 #include "stm32l475e_iot01_hsensor.h"
jernej_vrscaj 0:0681ebb27b3c 30 #include "stm32l475e_iot01_psensor.h"
jernej_vrscaj 0:0681ebb27b3c 31 #endif
jernej_vrscaj 0:0681ebb27b3c 32
jernej_vrscaj 0:0681ebb27b3c 33 #define ADVERTISING_INTERVAL 1000
jernej_vrscaj 0:0681ebb27b3c 34 #define UPDATE_VALUES_INTERVAL 1000
jernej_vrscaj 0:0681ebb27b3c 35
jernej_vrscaj 0:0681ebb27b3c 36 DigitalOut led1(LED1, 0);
jernej_vrscaj 0:0681ebb27b3c 37 DigitalOut led2(LED2, 0);
jernej_vrscaj 0:0681ebb27b3c 38
jernej_vrscaj 0:0681ebb27b3c 39 const static char DEVICE_NAME[] = "IoT_SENSOR";
jernej_vrscaj 0:0681ebb27b3c 40 static const uint16_t uuid16_list[] = {GattService::UUID_ENVIRONMENTAL_SERVICE};
jernej_vrscaj 0:0681ebb27b3c 41 static EnvironmentalService *environmentServicePtr;
jernej_vrscaj 0:0681ebb27b3c 42
jernej_vrscaj 0:0681ebb27b3c 43 /* initial dummy values */
jernej_vrscaj 0:0681ebb27b3c 44 static float currentTemperature = -15.0;
jernej_vrscaj 0:0681ebb27b3c 45 static float currentHumidity = 0.0;
jernej_vrscaj 0:0681ebb27b3c 46 static float currentPressure = 260.0 * 100; // hPa -> Pascal
jernej_vrscaj 0:0681ebb27b3c 47
jernej_vrscaj 0:0681ebb27b3c 48 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
jernej_vrscaj 0:0681ebb27b3c 49 static int id_adv;
jernej_vrscaj 0:0681ebb27b3c 50 static int id_conn;
jernej_vrscaj 0:0681ebb27b3c 51
jernej_vrscaj 0:0681ebb27b3c 52 void updateSensorValue(void) {
jernej_vrscaj 0:0681ebb27b3c 53
jernej_vrscaj 0:0681ebb27b3c 54 static int16_t lastTemperature;
jernej_vrscaj 0:0681ebb27b3c 55 static uint16_t lastHumidity;
jernej_vrscaj 0:0681ebb27b3c 56 static uint32_t lastPressure;
jernej_vrscaj 0:0681ebb27b3c 57
jernej_vrscaj 0:0681ebb27b3c 58 int16_t tempTemperature = 0;
jernej_vrscaj 0:0681ebb27b3c 59 uint16_t tempHumidity = 0;
jernej_vrscaj 0:0681ebb27b3c 60 uint32_t tempPressure = 0;
jernej_vrscaj 0:0681ebb27b3c 61
jernej_vrscaj 0:0681ebb27b3c 62 #ifdef USE_BOARD_SENSORS
jernej_vrscaj 0:0681ebb27b3c 63 currentTemperature = BSP_TSENSOR_ReadTemp();
jernej_vrscaj 0:0681ebb27b3c 64 currentHumidity = BSP_HSENSOR_ReadHumidity();
jernej_vrscaj 0:0681ebb27b3c 65 currentPressure = BSP_PSENSOR_ReadPressure();
jernej_vrscaj 0:0681ebb27b3c 66 currentPressure = currentPressure*100; // hPa -> Pascal
jernej_vrscaj 0:0681ebb27b3c 67 #else
jernej_vrscaj 0:0681ebb27b3c 68 /* dummy values */
jernej_vrscaj 0:0681ebb27b3c 69 currentTemperature = (currentTemperature + 0.1f > 43.0f) ? -15.0f : currentTemperature + 0.1f;
jernej_vrscaj 0:0681ebb27b3c 70 currentHumidity = (currentHumidity + 0.1f > 100.0f) ? 0.0f : currentHumidity + 0.1f;
jernej_vrscaj 0:0681ebb27b3c 71 currentPressure = (currentPressure + 10 > 126000.0f) ? 26000.0f : currentPressure + 10;
jernej_vrscaj 0:0681ebb27b3c 72 #endif
jernej_vrscaj 0:0681ebb27b3c 73
jernej_vrscaj 0:0681ebb27b3c 74 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 75 pc.printf("\r\n");
jernej_vrscaj 0:0681ebb27b3c 76 pc.printf("T_sensor = %.2f C\r\n", ((int16_t)(currentTemperature*100))/100.0);
jernej_vrscaj 0:0681ebb27b3c 77 pc.printf("H_sensor = %.2f %%\r\n", ((uint16_t)(currentHumidity*100))/100.0);
jernej_vrscaj 0:0681ebb27b3c 78 pc.printf("P_sensor = %.1f Pa\r\n", ((uint32_t)(currentPressure*10))/10.0);
jernej_vrscaj 0:0681ebb27b3c 79 pc.printf("\r\n");
jernej_vrscaj 0:0681ebb27b3c 80 #endif
jernej_vrscaj 0:0681ebb27b3c 81
jernej_vrscaj 0:0681ebb27b3c 82 tempTemperature = (int16_t)(currentTemperature*100);
jernej_vrscaj 0:0681ebb27b3c 83 tempHumidity = (uint16_t)(currentHumidity*100);
jernej_vrscaj 0:0681ebb27b3c 84 tempPressure = (uint32_t)(currentPressure*10);
jernej_vrscaj 0:0681ebb27b3c 85
jernej_vrscaj 0:0681ebb27b3c 86 /* Update char values, but only if they differ from previous */
jernej_vrscaj 0:0681ebb27b3c 87 if(tempTemperature != lastTemperature)
jernej_vrscaj 0:0681ebb27b3c 88 {
jernej_vrscaj 0:0681ebb27b3c 89 environmentServicePtr->updateTemperature(tempTemperature);
jernej_vrscaj 0:0681ebb27b3c 90 lastTemperature = tempTemperature;
jernej_vrscaj 0:0681ebb27b3c 91 }
jernej_vrscaj 0:0681ebb27b3c 92 if(tempHumidity != lastHumidity)
jernej_vrscaj 0:0681ebb27b3c 93 {
jernej_vrscaj 0:0681ebb27b3c 94 environmentServicePtr->updateHumidity(tempHumidity);
jernej_vrscaj 0:0681ebb27b3c 95 lastHumidity = tempHumidity;
jernej_vrscaj 0:0681ebb27b3c 96 }
jernej_vrscaj 0:0681ebb27b3c 97 if(tempPressure != lastPressure)
jernej_vrscaj 0:0681ebb27b3c 98 {
jernej_vrscaj 0:0681ebb27b3c 99 environmentServicePtr->updatePressure(tempPressure);
jernej_vrscaj 0:0681ebb27b3c 100 lastPressure = tempPressure;
jernej_vrscaj 0:0681ebb27b3c 101 }
jernej_vrscaj 0:0681ebb27b3c 102 }
jernej_vrscaj 0:0681ebb27b3c 103
jernej_vrscaj 0:0681ebb27b3c 104 void periodicCallback(void)
jernej_vrscaj 0:0681ebb27b3c 105 {
jernej_vrscaj 0:0681ebb27b3c 106 /* Do blinky on LED1 while advertising */
jernej_vrscaj 0:0681ebb27b3c 107 led1 = !led1;
jernej_vrscaj 0:0681ebb27b3c 108 wait(0.25);
jernej_vrscaj 0:0681ebb27b3c 109 led1 = !led1;
jernej_vrscaj 0:0681ebb27b3c 110 }
jernej_vrscaj 0:0681ebb27b3c 111
jernej_vrscaj 0:0681ebb27b3c 112 /* On Connection event start updating sensor values */
jernej_vrscaj 0:0681ebb27b3c 113 void connectionCallback(const Gap::ConnectionCallbackParams_t *)
jernej_vrscaj 0:0681ebb27b3c 114 {
jernej_vrscaj 0:0681ebb27b3c 115 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 116 pc.printf("\r\n");
jernej_vrscaj 0:0681ebb27b3c 117 pc.printf("Connection Event.\r\n");
jernej_vrscaj 0:0681ebb27b3c 118 #endif
jernej_vrscaj 0:0681ebb27b3c 119 eventQueue.cancel(id_adv);
jernej_vrscaj 0:0681ebb27b3c 120 led1 = 0;
jernej_vrscaj 0:0681ebb27b3c 121 led2 = 1; // LED2 on when connected
jernej_vrscaj 0:0681ebb27b3c 122 updateSensorValue();
jernej_vrscaj 0:0681ebb27b3c 123 id_conn = eventQueue.call_every(UPDATE_VALUES_INTERVAL, updateSensorValue);
jernej_vrscaj 0:0681ebb27b3c 124 }
jernej_vrscaj 0:0681ebb27b3c 125
jernej_vrscaj 0:0681ebb27b3c 126 /* Restart Advertising on disconnection*/
jernej_vrscaj 0:0681ebb27b3c 127 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *)
jernej_vrscaj 0:0681ebb27b3c 128 {
jernej_vrscaj 0:0681ebb27b3c 129 eventQueue.cancel(id_conn);
jernej_vrscaj 0:0681ebb27b3c 130 led2 = 0; // LED2 off when disconnected
jernej_vrscaj 0:0681ebb27b3c 131 BLE::Instance().gap().startAdvertising();
jernej_vrscaj 0:0681ebb27b3c 132 id_adv = eventQueue.call_every(ADVERTISING_INTERVAL, periodicCallback);
jernej_vrscaj 0:0681ebb27b3c 133
jernej_vrscaj 0:0681ebb27b3c 134
jernej_vrscaj 0:0681ebb27b3c 135 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 136 pc.printf("\r\n");
jernej_vrscaj 0:0681ebb27b3c 137 pc.printf("Disconnection Event - Start Advertising...\r\n");
jernej_vrscaj 0:0681ebb27b3c 138 #endif
jernej_vrscaj 0:0681ebb27b3c 139 }
jernej_vrscaj 0:0681ebb27b3c 140
jernej_vrscaj 0:0681ebb27b3c 141 void onBleInitError(BLE &ble, ble_error_t error)
jernej_vrscaj 0:0681ebb27b3c 142 {
jernej_vrscaj 0:0681ebb27b3c 143 /* Initialization error handling should go here */
jernej_vrscaj 0:0681ebb27b3c 144 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 145 pc.printf("BLE Init Error: %u\r\n", error);
jernej_vrscaj 0:0681ebb27b3c 146 #endif
jernej_vrscaj 0:0681ebb27b3c 147
jernej_vrscaj 0:0681ebb27b3c 148 while(1)
jernej_vrscaj 0:0681ebb27b3c 149 { /* Do blinky on LED2 on Error */
jernej_vrscaj 0:0681ebb27b3c 150 led2 = !led2;
jernej_vrscaj 0:0681ebb27b3c 151 wait(0.25);
jernej_vrscaj 0:0681ebb27b3c 152 }
jernej_vrscaj 0:0681ebb27b3c 153 }
jernej_vrscaj 0:0681ebb27b3c 154
jernej_vrscaj 0:0681ebb27b3c 155 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
jernej_vrscaj 0:0681ebb27b3c 156 {
jernej_vrscaj 0:0681ebb27b3c 157 BLE& ble = params->ble;
jernej_vrscaj 0:0681ebb27b3c 158 ble_error_t error = params->error;
jernej_vrscaj 0:0681ebb27b3c 159
jernej_vrscaj 0:0681ebb27b3c 160 if (error != BLE_ERROR_NONE) {
jernej_vrscaj 0:0681ebb27b3c 161 onBleInitError(ble, error);
jernej_vrscaj 0:0681ebb27b3c 162 return;
jernej_vrscaj 0:0681ebb27b3c 163 }
jernej_vrscaj 0:0681ebb27b3c 164
jernej_vrscaj 0:0681ebb27b3c 165 /* Ensure that it is the default instance of BLE */
jernej_vrscaj 0:0681ebb27b3c 166 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
jernej_vrscaj 0:0681ebb27b3c 167 return;
jernej_vrscaj 0:0681ebb27b3c 168 }
jernej_vrscaj 0:0681ebb27b3c 169
jernej_vrscaj 0:0681ebb27b3c 170 /* Callback function when connected */
jernej_vrscaj 0:0681ebb27b3c 171 ble.gap().onConnection(connectionCallback);
jernej_vrscaj 0:0681ebb27b3c 172 /* Callback function when disconnected */
jernej_vrscaj 0:0681ebb27b3c 173 ble.gap().onDisconnection(disconnectionCallback);
jernej_vrscaj 0:0681ebb27b3c 174
jernej_vrscaj 0:0681ebb27b3c 175 /* Setup primary service. */
jernej_vrscaj 0:0681ebb27b3c 176 environmentServicePtr = new EnvironmentalService(ble);
jernej_vrscaj 0:0681ebb27b3c 177
jernej_vrscaj 0:0681ebb27b3c 178 /* setup advertising */
jernej_vrscaj 0:0681ebb27b3c 179 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
jernej_vrscaj 0:0681ebb27b3c 180 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
jernej_vrscaj 0:0681ebb27b3c 181 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
jernej_vrscaj 0:0681ebb27b3c 182 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
jernej_vrscaj 0:0681ebb27b3c 183 ble.gap().setAdvertisingInterval(ADVERTISING_INTERVAL);
jernej_vrscaj 0:0681ebb27b3c 184 ble.gap().startAdvertising();
jernej_vrscaj 0:0681ebb27b3c 185 }
jernej_vrscaj 0:0681ebb27b3c 186
jernej_vrscaj 0:0681ebb27b3c 187 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
jernej_vrscaj 0:0681ebb27b3c 188 BLE &ble = BLE::Instance();
jernej_vrscaj 0:0681ebb27b3c 189 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
jernej_vrscaj 0:0681ebb27b3c 190 }
jernej_vrscaj 0:0681ebb27b3c 191
jernej_vrscaj 0:0681ebb27b3c 192 int main()
jernej_vrscaj 0:0681ebb27b3c 193 {
jernej_vrscaj 0:0681ebb27b3c 194 #ifdef USE_BOARD_SENSORS
jernej_vrscaj 0:0681ebb27b3c 195 BSP_TSENSOR_Init();
jernej_vrscaj 0:0681ebb27b3c 196 BSP_HSENSOR_Init();
jernej_vrscaj 0:0681ebb27b3c 197 BSP_PSENSOR_Init();
jernej_vrscaj 0:0681ebb27b3c 198 #endif
jernej_vrscaj 0:0681ebb27b3c 199
jernej_vrscaj 0:0681ebb27b3c 200 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 201 pc.printf("== BLE - EnvironmentalService ==\r\n");
jernej_vrscaj 0:0681ebb27b3c 202 #endif
jernej_vrscaj 0:0681ebb27b3c 203
jernej_vrscaj 0:0681ebb27b3c 204 id_adv = eventQueue.call_every(ADVERTISING_INTERVAL, periodicCallback);
jernej_vrscaj 0:0681ebb27b3c 205
jernej_vrscaj 0:0681ebb27b3c 206 BLE &ble = BLE::Instance();
jernej_vrscaj 0:0681ebb27b3c 207 ble.onEventsToProcess(scheduleBleEventsProcessing);
jernej_vrscaj 0:0681ebb27b3c 208
jernej_vrscaj 0:0681ebb27b3c 209 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 210 pc.printf("Init BLE...\r\n");
jernej_vrscaj 0:0681ebb27b3c 211 #endif
jernej_vrscaj 0:0681ebb27b3c 212
jernej_vrscaj 0:0681ebb27b3c 213 ble.init(bleInitComplete);
jernej_vrscaj 0:0681ebb27b3c 214
jernej_vrscaj 0:0681ebb27b3c 215 #ifdef DEBUG
jernej_vrscaj 0:0681ebb27b3c 216 pc.printf("Init complete - Advertising...\r\n");
jernej_vrscaj 0:0681ebb27b3c 217 #endif
jernej_vrscaj 0:0681ebb27b3c 218
jernej_vrscaj 0:0681ebb27b3c 219 eventQueue.dispatch();
jernej_vrscaj 0:0681ebb27b3c 220
jernej_vrscaj 0:0681ebb27b3c 221 return 0;
jernej_vrscaj 0:0681ebb27b3c 222 }