Creating a Unified Sensor Driver

How do you create a new driver based around the unified sensor driver system, or port an existing driver over?

Thankfully it's not that complicated. You still have to create a basic driver the same way ... mapping out the correct registers, setting up some plumbing to send and receive the commands, etc. The only really different with a 'Unified Sensor Driver' is that there is an additional layer that sits on top of that underlying code that converts the sensor's native units into what Adafruit_Sensor is expecting.

Unified Driver Template

Since a simple code example usually makes the best documentation if you just want to get started quickly, we've put together a very simple template project that shows the minimum functionality that needs to be added to your driver to make it compliant with the unified sensor driver system.

You can get browse the code online or download it on github at https://github.com/adafruit/Adafruit_SensorTester.

They key elements are that your driver must inherit from the Adafruit_Sensor base class, which is handled in the class declaration in your header file:

Driver Header

Download: file
#ifndef _ADAFRUIT_SENSOR_TESTOR_
#define _ADAFRUIT_SENSOR_TESTOR_

#if ARDUINO >= 100
 #include "Arduino.h"
 #include "Print.h"
#else
 #include "WProgram.h"
#endif

#include <Adafruit_Sensor.h>
#include <Adafruit_SensorTester.h>

class Adafruit_SensorTester : public Adafruit_Sensor {

 public: 
  /* Constructor */
  Adafruit_SensorTester(int32_t);

  void getEvent(sensors_event_t*);
  void getSensor(sensor_t*);
  
 private:
   int32_t _sensorID;
};

#endif
The other two main requirements here:
  • You need to implement getEvent and getSensor, as defined in the base class, so the function prototypes are declared here in the header
  • Every instance of a sensor has a unique ID that's passed in to the constructor. Notice the int32_t in Adafruit_SensorTester(int32_t)? This is what we'll use to store this ID and it needs to have some sort of local placeholder so we also add a private '_sensorID' variables.

Driver Class Implementation

Once you've updated the header, you need to add a couple things to your actual driver to implement the required functions and support the constructor that accepts a sensor ID.

You can see some sample code for this below (or download it directly from github if you want):
Download: file
#include "Adafruit_SensorTester.h"

#include <avr/pgmspace.h>
#include <limits.h>
#include "pins_arduino.h"
#include "wiring_private.h"

Adafruit_SensorTester::Adafruit_SensorTester(int32_t sensorID) {
  _sensorID = sensorID;
}

void Adafruit_SensorTester::getEvent(sensors_event_t *event) {
  /* Clear the event */
  memset(event, 0, sizeof(sensors_event_t));

  event->version   = sizeof(sensors_event_t);
  event->sensor_id = _sensorID;
  event->type      = SENSOR_TYPE_PRESSURE;
  event->timestamp = 0;
  event->pressure = 123.0F;
}

void Adafruit_SensorTester::getSensor(sensor_t *sensor) {
  /* Clear the sensor_t object */
  memset(sensor, 0, sizeof(sensor_t));

  /* Insert the sensor name in the fixed length char array */
  strncpy (sensor->name, "TESTER", sizeof(sensor->name) - 1);
  sensor->name[sizeof(sensor->name)- 1] = 0;
  sensor->version     = 1;
  sensor->sensor_id   = _sensorID;
  sensor->type        = SENSOR_TYPE_PRESSURE;
  sensor->min_delay   = 0;
  sensor->max_value   = 300.0F;               // 300..1100 hPa
  sensor->min_value   = 1100.0F;
  sensor->resolution  = 0.01F;                // 0.01 hPa resolution

  /* Clear the reserved section */
  memset(sensor->reserved, 0, sizeof(sensor->reserved));
}
You can see here that we accept the sensor ID in the constructor and assign it to _sendorID. This value is then used in both getEvent and getSensor so that we always know which sensor data or sensor details are coming from (important if you're logging 30 different TSL2561 sensors!).

The key lines you'll need to changed are things like event->type and sensor->type to point to the correct sensor type (SENSOR_TYPE_PRESSURE is used here as an example).

You can also assign a small name to this sensor type ("BMP085", etc.).
Values assigned to sensor->name must be 12 characters or less. Anything longer than this will be truncated!
The third important point to noticed is 'event->pressure'. This is where you need to assign the correct value for the latest sensor reading, but it first needs to be converted to the expected SI units (hPa in the case of pressure sensors). The exact field that you assign your value to will depend on the sensor->type.

  • Acceleration sensors use: event->acceleration.x, event->acceleration.y, event->acceleration.z
  • magnetic sensors use: event->magnetic.x, event->magnetic.y, event->magnetic.z
  • Pressure sensors use: event->pressure
  • etc.
You can see the supported sensors by looking at the sensors_event_t typedef in Adafruit_Sensor.h.

Existing Drivers

The easiest way to learn how to use the system, though, is to look at some complete examples. We've linked to some existing drivers on the next page of this tutorial ...
This guide was first published on Feb 28, 2013. It was last updated on Feb 28, 2013. This page (Creating a Unified Sensor Driver) was last updated on Sep 15, 2019.