Define a Device model #
We will now define a new Device model with the associated Decoder in order to receive raw payloads.
The device is a temperature and pressure sensor, we will use the standard temperature measurement but we need to define a custom co2 measurement.
Define a custom measurement #
To define a measure, it is necessary to declare an object indicating to the storage engine the names and types of the different values of the measure.
It is also advisable to create a type for this measure in order to take advantage of the strong typing in the rest of the project.
In this example, we will declare a CO2 measurement that will contain its value in a co2
property of type float
:
import { MeasureDefinition } from '@kuzzleio/iot-platform-backend';
export type CO2Measurement = {
co2: number;
};
export const co2MeasureDefinition: MeasureDefinition = {
valueMappings: {
co2: { type: 'float' },
},
};
[!NOTE] After 3.1.0-beta.58, a
MeasureModel
interface is provided by iot-platform to simplify the models definition
import { MeasureModel } from '@kuzzleio/iot-platform-backend';
export type CO2Measurement = {
co2: number;
};
export const co2Measurement: MeasureModel = {
modelName: 'co2',
definition: {
valuesMappings: { co2: { type: 'float' } },
},
};
Then the measure should be registered on the framework:
import { DeviceManagePlugin } from 'kuzzle-device-manager';
import { co2MeasureDefinition } from './CO2Measurement';
const deviceManager = app.plugin.get<DeviceManagerPlugin>('device-manager');
deviceManager.models.registerMeasure('co2', co2MeasureDefinition);
[!NOTE] After 3.1.0-beta.58, a
ModelsModule
abstract class is provided by iot-platform to simplify the models definition, with it all register methods are called in background for you.
You have only to provide models in appropriate properties (deviceModels
andmeasuresModels
)
import { DeviceModel, ModelsModule } from '@kuzzleio/iot-platform-backend';
import { co2Measurement } from './CO2Measurement';
export class MeasureModule extends ModelsModule {
protected measuresModels: MeasureModel[] = [co2Measurement];
}
Decoder #
First, you need to create a Decoder that will transform the raw payload into standardized measures.
For this, you need to extends the Decoder
class and
- define measure decoded by the Decoder
- implements the
decode
method
The decode
method take 2 parameters:
decodedPayload
utility class to extract the measurespayload
the raw payload as a JSONObject
Each measure should be extracted with the following information:
- device reference which acts as device unique identifier (e.g.
ABC123
) - measure type (e.g.
temperature
) - measure name (e.g.
temperature
) - measure timestamp of the measurement (e.g.
1675959435515
) - measure values (e.g.
21.2
)
An example of the complete implementation can be found in the apps/api/lib/modules/devices/
directory
In this example, we will implements a Decoder to decode the following raw payload:
{
"deviceEUI": "ABC123",
"temp": 21.2
}
Our Decoder will define two measures, temperature
and co2
.
import {
DecodedPayload,
Decoder,
HumidityMeasurement,
TemperatureMeasurement,
} from '@kuzzleio/iot-platform-backend';
import { JSONObject } from 'kuzzle';
import { has } from 'lodash';
import { CO2Measurement } from './CO2Measurement';
export class ExampleDecoder extends Decoder {
/**
* Declare the measure extracted by this Decoder
*/
public measures = [
{ name: 'temperature', type: 'temperature' },
{ name: 'co2', type: 'co2' },
] as const;
constructor() {
super();
/**
* Register a custom mappings for the "payloads" collection
*/
this.payloadsMappings = {
deviceId: { type: 'keyword' },
};
}
/**
* Ensure the payload contains the correct values
*/
async validate(payload: JSONObject): Promise<boolean> {
// This throw an exception if the property "deviceId" is not present
this.ensureProperties(payload, ['deviceId']);
const properties = ['temperature', 'co2'];
return properties.every((property) => has(payload, property));
}
async decode(
decodedPayload: DecodedPayload<ExampleDecoder>,
payload: JSONObject,
): Promise<DecodedPayload<Decoder>> {
const deviceId = payload.deviceId;
const measuredAt = payload.timestamp || Date.now();
decodedPayload.addMeasurement<TemperatureMeasurement>(
deviceId, // device reference
'temperature', // measure name
{
measuredAt, // timestamp of the measure
type: 'temperature', // measure type
values: {
temperature: payload.temperature,
},
},
);
decodedPayload.addMeasurement<CO2Measurement>(deviceId, 'co2', {
measuredAt,
type: 'co2',
values: {
co2: payload.co2,
},
});
return decodedPayload;
}
}
Device model #
Then we can define a new Device model associated with the Decoder we just wrote.
For this, we will use the Device Manager plugin:
import { DeviceManagePlugin } from 'kuzzle-device-manager';
import { ExampleDecoder } from './ExampleDecoder';
const deviceManager = app.plugin.get<DeviceManagerPlugin>('device-manager');
deviceManager.models.registerDevice('Example', {
decoder: new ExampleDecoder(),
});
[!NOTE] After 3.1.0-beta.58, a
DeviceModel
interface is provided by iot-platform to simplify the models definition
import { DeviceModel } from '@kuzzleio/iot-platform-backend';
import { ExampleDecoder } from './ExampleDecoder';
export const Example: DeviceModel = {
modelName: 'Example',
definition: {
decoder: new ExampleDecoder(),
},
};
After like measures you can use the abstract ModelsModule
to create a modules to register the device models
import { DeviceModel, ModelsModule } from '@kuzzleio/iot-platform-backend';
import { Example } from './Example';
export class DeviceModule extends ModelsModule {
protected readonly deviceModels: DeviceModel[] = [Example];
}
Once registered, the new device model automatically exposes a HTTP route to send raw payloads:
curl -X POST \
-H "Content-Type: application/json" \
"http://localhost:7512/_/devicemanager/payload/example"\
--data '{"deviceId": "ABC123", "co2": 123, "temperature": 21.2 }'
You can now open the Admin > Orphans
view of the IoT Console and see you newly created device.
By default, the IoT Platform automatically create new devices when a payload is received for the first time.