Create a sensor extension for IoTool

This document provides general information on what you have to do to create a sensor extension for IoTool application. This does not go in to details on how to create extension using specific method of communication (wifi, bluetooth, etc.)

IoTool app and IoTool sensor extensions

IoTool app acquires the readings from any device (may include one or more sensors) only using IoTool sensor extension. For each device should be produced an IoTool sensor extension. Many IoTool sensor extensions are already available, e.g. IoToolSensorServiceDevice.apk for Android device internal sensors. If your sensor device with sensors is not yet supported an IoTool sensor extension should be produced.

Note: IoTool app should not be changed to support new devices. Only an IoTool sensor extension should be developed. IoTool sensor extension itself implements everything used by IoTool app and their communication.

Choosing a service ID

Many developers are producing IoTool sensor extensions and some of them may become public and used by many end users. So, it is preferred that all developed IoTool sensor extensions may run on the same device not interfering one with each other. As IoTool sensor extensions are actually apk’s they should be named differently for each sensor device. IoTool sensor extensions are distinct only by service ID which is then used in package name, class names, reading ids etc. throughout IoTool sensor extension. Service ID should consist only of alphanumeric characters without spaces and special chars. Service ID may consist of:

  • sensor device name,

  • sensor name,

  • sensor model name,

  • device manufacturer name,

  • any combination of above.

Note: service ID is case sensitive, except in the package name where lower case service ID should be used.

Where service ID should be used

Service ID should be used in package names and class names, readings ID names etc. to avoid all interference with other applications. For example we are using a package name "com.example" and we have would like pack Service class, Preference class and Provider class all in one package and the ID we have chosen is "DemoS". The first step is rename the package or add a sub package that contains the chosen ID (For example "com.example.servicedemos"). Then we have to rename classes, so that they contain service ID in their name (For example "IoToolSensorServiviceDemoS.java").

How to start developing a new IoTool sensor extension

To start developing IoTool sensor extension first download demo code that the method of communication of your choosing. Then a unique service ID should be chosen. After that a copy of a demo code package should be made. Chosen service ID should replace the service ID used in the demo code package. For example, if the demo code package for a Bluetooth LE sensor is used to develop a new IoTool sensor extension then all occurrences of "DemoBLE" in filenames and file contents should be replaced by chosen service ID.

How to proceed

When a copy of a demo code package with a unique service ID is ready the rest of this developer guide and developer guide of your chosen communication should be used.

Note: Any change to the code may be needed only at the sections which start with "//TODO".

Libraries

"IoToolLibraryBase.aar"

The only library to be used is "IoToolLibraryBase.aar" and it is also included in our demo code packages.

Classes

There are three main classes used our demo code packages. They all have follow certain format of naming. This will be described bellow. The information that follows is related to usage of classes implemented in the only library "IoToolLibraryBase.aar".

"IoToolSensorService" + service ID + ".java"

This class defines and implements all necessary setup and processing of data for readings that a sensor supports. In demo code packages this this class already implements all service functionality such as connecting to a sensor, responding to the application commands etc.

IoToolReading - this class takes care of storing data in database and broadcasting to IoTool app

  • setup: Setup(String readingid, File appDir, boolean usedb, String datatype, int sampleinterval, boolean broadcastdata, boolean broadcastimmediately, Context broadcastcontext)

  • readingid - consists of reading name and service ID separated by @ character: readingName@serviceID (reading Name should consist only of alphanumeric characters without spaces and special chars; like service ID)

  • appDir - directory on external storage where databases should be stored (provided by the application that starts the service)

  • usedb - store data in database (provided by the application that starts the service)

  • datatype - IoToolReading can use three different ways to store records in database: for readings that occur at approximately 1 second or longer interval uses dataTypeSingle, for readings that occur many times per second uses dataTypePeriodic if the interval is regular (for example exactly every 20ms) and dataTypeTimestamps when the interval is irregular

  • sampleinterval - if dataTypePeriodic datatype is used the interval in milliseconds should be provided, otherwise sampleinterval may be 0

  • broadcastdata - broadcasts data to application (provided by the application that starts the service)

  • broadcastimmediately - usualy data is broadcasted to application every 200ms, if readings occur at interval that is shorter than that, it’s best to set this to false

  • broadcastcontext - use "this" to select service as context for broadcasts

String serviceID = "DemoV"; //service ID that we have chosen
//In demo packages, sappDir, useDB and broadcastData are already defined in method onStartCommand.
//typeReading is one of the IoTool constants metioned above
reading1.Setup("Reading1@"+serviceID, appDir, useDB, typeReading, 0, IoToolReading.dataTypeTimestamps, true, this);

write and broadcast: writeData(long timestamp, double sample)

  • timestamp - current reading timestamp (unix time in milliseconds)

  • sample - current reading value (numeric)

"IoToolSensorService" + service ID + "Preferences.java"

This class implements preferences for a sensor which are accessible from IoTool app. Each implementation can be different from demo package to demo package.

"IoToolSensorService" + service ID + "Provider.java"

It must provide info for sensor properties, any dashboard profiles, sensor readings properties. For each of those, info is stored in two arrays, one for headers and one for actual data.

PROPERTIES - sensor properties, 1 row only, columns:

  • IoToolConstants.PROVIDER_ROWID - unique row id (integer)

  • IoToolConstants.PROVIDER_PROPERTIES_ID - service ID

  • IoToolConstants.PROVIDER_PROPERTIES_NAME - full sensor Name, may include manufacturer

  • IoToolConstants.PROVIDER_PROPERTIES_DEVELOPER - extension developer name (company)

  • (optional) IoToolConstants.PROVIDER_PROPERTIES_BLUETOOTHMODE - default is IoToolConstants.BLUETOOTH_MODE_NORMAL, for BT Low Energy devices it should be set to IoToolConstants.BLUETOOTH_MODE_BLE (optional) IoToolConstants.PROVIDER_PROPERTIES_PREFIX - when choosing a device (sensor) from a list of all found bluetooth devices in preferences, filtering can be applied to shorten the list (if prefix is set the name of device has to start with it)

Example:

static final String[] properties_header = new String[] {IoToolConstants.PROVIDER_ROWID, IoToolConstants.PROVIDER_PROPERTIES_ID, IoToolConstants.PROVIDER_PROPERTIES_NAME, IoToolConstants.PROVIDER_PROPERTIES_DEVELOPER};
static final Object[] properties = new Object[] {1, "DemoS", "Demo Sensor", "example.com"};

PROFILES - provide at least one for easy dashboard setting, with some typical readings, columns:

  • IoToolConstants.PROVIDER_ROWID - unique row id (integer)

  • IoToolConstants.PROVIDER_PROFILES_NAME - profile name

  • IoToolConstants.PROVIDER_PROFILES_READINGS - array of reading IDs

Example:

static final String[] profiles_header = new String[] {IoToolConstants.PROVIDER_ROWID, IoToolConstants.PROVIDER_PROFILES_NAME, IoToolConstants.PROVIDER_PROFILES_READINGS};
static final Object[][] profiles = new Object[][] {
	{1, "Demo S", new String[] {"Reading1@DemoS", "Reading2@DemoS"}}
};

READINGS - reading properties - one for each reading that service implements (if data for column is set to null, default value is used), columns:

  • IoToolConstants.PROVIDER_ROWID - unique row id (integer)

  • IoToolConstants.PROVIDER_READINGS_ID - reading id

  • IoToolConstants.PROVIDER_READINGS_NAME - reading full name

  • IoToolConstants.PROVIDER_READINGS_SHORTNAME - reading short name (max ~8 characters), for dashboard buttons

  • (optional) IoToolConstants.PROVIDER_READINGS_UNIT - reading unit

  • (optional) IoToolConstants.PROVIDER_READINGS_INTERVAL - approx. reading interval (default 1000ms)

  • (optional) IoToolConstants.PROVIDER_READINGS_DECIMALS - only for display on dashboard buttons (default 0)

  • (optional) IoToolConstants.PROVIDER_READINGS_DISPLAYNUMBER - display value on dashboard button (set to false to hide, e.g. for reading which varies a lot in less than one second)

  • (optional) IoToolConstants.PROVIDER_READINGS_CHARTTYPE - chart display type, default is IoToolConstants.CHART_TYPE_DEFAULT which equals IoToolConstants.CHART_TYPE_LINE, other available options: IoToolConstants.CHART_TYPE_SPLINE, IoToolConstants.CHART_TYPE_COLUMN, IoToolConstants.CHART_TYPE_POINT

  • (optional) IoToolConstants.PROVIDER_READINGS_SETYRANGE - fixed y range on chart (default false)

  • (optional) IoToolConstants.PROVIDER_READINGS_MINYRANGE - chart y range starts with (min value to be displayed)

  • (optional) IoToolConstants.PROVIDER_READINGS_MAXYRANGE - chart y range end with (max value to be displayed)

Example:

static final String[] readings_header = new String[] {IoToolConstants.PROVIDER_ROWID, IoToolConstants.PROVIDER_READINGS_ID, IoToolConstants.PROVIDER_READINGS_NAME, IoToolConstants.PROVIDER_READINGS_SHORTNAME, IoToolConstants.PROVIDER_READINGS_UNIT, IoToolConstants.PROVIDER_READINGS_INTERVAL, IoToolConstants.PROVIDER_READINGS_DECIMALS};
static final Object[][] readings = new Object[][] {
	{1, "Reading1@DemoS", "Reading 1", "Read.1", "unit1", null, 1},
	{2, "Reading2@DemoS", "Reading 2", "Read.2", "unit2", null, 1}
};