A library containing all the relevant types and definitions shared between components of the Unified Prototyping Toolkit (UPT) for ease of maintainability. There shouldn't be a reason to use it directly, but it is being used to create libraries compatible with the rest of the UPT.
Goal of this library is to provide a uniform design language across all UPT modules when handling sensor data, for convenient flow of information and preserving metadata.
Fundamentally, a data point in the UPT ecosystem comes from one of two sources:
- Wired: signal readings retrieved via a wired communications bus, eg. i2c communication
- Bluetooth Low Energy (BLE): signal readings transimtted via BLE advertisement from a Sensirion demo device
Unfortunately, further classification of a data point's origin is tricky:
- The information about the sensor authoring a measurement is not transmitted via BLE,
it is thus in general not possible to assign a
SensorType
to eachDataPoint
received via BLE. - Not all wired sensors support exact sensor classification. For example,
while we know that a sensor responding to i2c commands on address
0x62
belongs in the SCD4X family of sensors, we have no way of knowing if it is a SCD40 or SCD41.
These two reasons motivate why we distinguish two sensor types, BLEGadgetType
and SensorType
, and the granularity of their definitions. To counter this
granularity, fields for storing the authoring sensor's serial number or MAC
address (depending on whether the data was received via i2c or BLE) are
provided, to ensure a unique identifier is made available.
To enable both total characterization and efficient storage of large quantities
of measurements, it was decided to encapsulate the actual values in different
layers. Let us go over each of the objects that make up a Measurement
:
At first, some measurement is either made via i2c, or received via interception
of a BLE advertisement. This allows us to populate the DataPoint
struct:
DataPoint(
t_offset = *Milliseconds since startup*
value = *Signal value*
);
We measure a relative time since startup because of its easy availability
anywhere in the code, through the built-in Arduino method millis()
. Conversion
to Epoch (or another time format) usually requires an internet connection,
making it less versatile. The underlying data type of the value
field depends on the sensor and the signal being measured. For ease of interoperability, all values (independently of their original type) are stored as float
in the DataPoint
.
Any kind of signal that can be measured by a Sensirion sensor is available as
a SignalType
. Both a description of the physical quantity being measured and the
SI units of the measurement can be queried through the provided methods unitOf()
and quantityOf()
. The SignalType
s of measurements by Sensirion's SCD4X series of CO2 sensors are for example
SignalType::CO2_PARTS_PER_MILLION
SignalType::TEMPERATURE_DEGREES_CELSIUS
SignalType::RELATIVE_HUMIDITY_PERCENT
The metadata encodes information regarding a measurement's origin:
MetaData(
devicePlatform = *WIRED or BLE*;
deviceID = *MAC address or sensor serial No.*;
DeviceType = *BLEGadgetType or SensorType*;
);
The first field, devicePlatform, enables us to interpret information contained
in the other two fields. A method to obtain a descriptive string of the device
type is available with deviceLabel()
. The DeviceType
is one of the
available BLEGadgetTypes
or SensorTypes
available in the Sensirion ecosystem.
To pick up on the SCD4X example above, assuming its signals are retrieved using UPT Sensor Autodetection, the MetaData
would look as such:
MetaData(
devicePlatform = DevicePlatform::WIRED;
deviceID = 151181767251340; // Some 48-bit int
DeviceType = SensorType::SCD4X;
);
Please refer to the BasicUsage.ino
script for a featured example on how to use the Measurement
struct.
Sensirion BLE Gadgets send their measurements encoded in their device advertisements,
one way to enable data transmission without needing to establish a connection to the device.
This encoding depends on the data being transmitted (to ensure the receiver knows how to interpret the data),
and can be queried in a dictionary (implemented as a std::map
) provided by this library.
These two identifiers (SampleType
is a uint8_t
and DataType
an enum
) serve as the main ways to
identify (1) the shape of the transmission message, and (2) the nature of the contents therein. The device sending the advertisement (such as an Arduino board running Sensirion's BLE DIY Gadget software) typically knows what signals it wants to send (and therefore selects an appropriate DataType
), while the receiving device reads the SignalType
field in the ManufacturerData
part of the BLE Advertisement message and maps it to the corresponding DataType
.
For example, a Sensirion MyCO2 Gadget sends an advertisement identified by DataType::T_RH_CO2_ALT
and SignalType = 8
, and containing the temperature, relative humidity and CO2 concentration measured by the device.
Please refer to the Sensirion BLE Communication Protocol for a list of available SignalType
s and for the structure of a Sensirion BLE Advertisement.
Once the DataType
of the message is determined, it can be used to query configuration information of the message, such as it size and signals it contains, using the provided sampleConfigSelector
dictionary provided:
SampleConfig sampleConfig = sampleConfigSelector[myDataType];
SampleConfig
contains the following fields, among others:
SampleConfig.sampleSizeBytes
: useful for determining the size of the Advertisement messageSampleConfig.sampleSlots
: a dictionary mapping the slots toSignalType
.
To pick up on the MyCO2 Gadget, the corresponding sampleSizeBytes
reads 6
(the 3 signal values transmitted get 2 bytes each), while the sampleSlots
informs us of the order of the signals, the aforementioned Temperature, Relative Humidity, and CO2 concentration.
The signals are transmitted as uint16_t
. To ensure no information is lost, encoding and decoding functions are provided. Since these are not uniform (being both signal and DataType
dependant), sampleSlots
also provides
pointers to the appropriate conversion functions.
Please refer to the BLE_example.ino
script for a featured example on how to encode/decode sensor data in a BLE Advertisement message.
Two example scripts are provided:
BasicUsage
: An example showing how to use theMeasurement
struct to handle sensor data in general;BLE_example
: An example showing how to encode/decode senor data for transmission via BLE Advertisement. Note that the example does not actually use Bluetooth, so it can be run on a board that does not have an antenna.
On PlatformIO, the examples can be run by by executing the following command from the library's root directory (containing this README):
- For example
BasicUsage
:$ pio run -t upload
or$ pio run -e basicUsage -t upload
(environment BasicUsage is default) - For example
BLE_example
:pio run -e ble_example -t upload
In both cases, the output can be monitored by using the PlatformIO device monitor:
pio device monitor
Arduino IDE users can navigate to File
-> Examples
-> Sensirion Gadget BLE Lib
-> BasicUsage
or BLE_example
, and click the upload button. The example outputs can be examined using the serial monitor (make sure to use 115200 baud
).
This library requires standard library compatibility. Some boards such as Arduino AVR Uno do not ship with this functionnality. This library was developed and tested on Espressif ESP32 boards.
- Download Arduino IDE and setup the environment for ESP32 platform
- Follow this guide
- Detailed Instructions for advanced users: Arduino-ESP32
- Start the Arduino IDE and open the Library Manager by selecting
Sketch
->Include Library
->Manage Libraries...
. Search for theSensirion UPT Core
library in theFilter your search...
field and install it by clicking theinstall
button. - Connect your ESP32 DevKit to your computer.
- In the Arduino IDE, make sure you have the
ESP32 Dev Module
and the correct Port selected. - Select
File
->Examples
->Sensirion Gadget BLE Lib
->BasicUsage
. - Connect your board and click the upload button.
- The Serial Monitor displays randomly generated mock Measurements.
For users interested in the BLE en/decoding features, example script BLE_example
is available.
- To install the PlatformIO Core, follow the steps detailed here.
- Open this project in PlatformIO.
- After you've conected your board, Compile, Upload and view Serial output or example script
BasicUsage
using the terminal:
pio run -t upload && pio device monitor
- The Serial Monitor displays randomly generated mock Measurements.
For users interested in the BLE en/decoding features, example script BLE_example
is available. It can be run with
pio run -e ble_example -t upload && pio device monitor
The example script will now display mock BLE advertisements in the console.
To use this library in your project, add Sensirion UPT Core
to your lib_deps
in the platformio.ini
file.
See LICENSE.