Report parsing documentation

Report parser

External systems and individual IoT devices (hereafter collectively called "devices") can communicate with our application. The payload they send in can vary from device type to device type. We therefore offer full flexibility on how to parse it into condition reports, using a custom Typescript parser function.

The parser function gets called every time the device type event handler calls exec.parseReport({ reportTypeHashId, payload }) with the reportTypeHashId of the report type to which this parser function belongs. The payload parameter is a string (often the device type event handler applied JSON.stringify() on some object to convert it to a string).

The parser should then convert the payload string (probably applying JSON.parse first) into an actual report with measurements and or fields. Note that the fields have to adhere to the field configuration of the report type this parser belongs to.

Measurements are registered using scientific notation, so you provide integer significand and an orderOfMagnitude. The value can then be calculated as significand * 10 ** orderOfMagnitude.

This advantage of scientific notation is we know what the precision of the measurement is. Say we have the following two measurements for a quantity "Voltage":

  1. significand = 50, orderOfMagnitude = 0
  2. significand = 5, orderOfMagnitude = 1 both are around 50 volt, but the first one is larger than 49 and smaller than 51, but for the second we only know that it is larger than 40 and smaller than 60. This distinction is relevant when applying thresholds on them and to avoid false accuracy when presenting these measurements.

The identifier function should:

  • be written in Typescript,
  • be named handle
  • have the following signature: handle(args: Arguments): Result

Example

const quantityHashIds = {
temperature: 'aaaaa1', // fake hashId
pressure: 'bbbbb1', // fake hashId
};


function handle(args: Arguments, exec: Exec): Result {
const data = JSON.parse(args.payload);

// We expect that data is of type { generatedAt: string; payload: [number, number] }
// and validate that below
if (typeof data !== 'object' || data === null) {
throw new Error('Data is not a JSON-object');
}

const generatedAtMs = Date.parse(data.generatedAt);
if (Number.isNaN(generatedAtMs)) {
throw new Error('generatedAt cannot be parsed into a valid Date');
}
const generatedAt = new Date(generatedAtMs);
const payload = data.payload;
if (!Array.isArray(payload) || payload.length !== 2) {
throw new Error('Payload is not an array of length 2');
}
const temperature = payload[0];
if (typeof temperature !== 'number' && temperature !== null) {
throw new Error('Temperature is not as number or null');
}
const pressure = payload[1];
if (typeof pressure !== 'number' && temperature !== null) {
throw new Error('Pressure is not as number or null');
}

const measurements: Result['measurements'] = [];

if (temperature !== null) {
measurements.push({
channelIndex: 0,
quantityHashId: quantityHashIds.temperature,
generatedAt,
significand: temperature,
orderOfMagnitude: 0, // temperature is in degrees celcius
});
}

let pressureOverload: boolean;
if (pressure !== null) {
measurements.push({
channelIndex: 0,
quantityHashId: quantityHashIds.pressure,
generatedAt,
significand: pressure,
orderOfMagnitude: -3, // pressure is in millibar, while quantity is in bar
});
pressureOverload = false;
} else {
pressureOverload = true;
}

return {
generatedAt,
measurements,
fields: {
pressureOverload,
},
};
}
}

Inspecting activity

You can inspect activity on this report parser by going to "Activity" in the connectivity environment and filtering "Report Type" on the name chosen for this report type.