Creating Device Templates & Codec Editors for Custom Sensor Management

Introduction

The Internet of Things (IoT) is continuously evolving, driving the need for more adaptable and sophisticated sensor management systems. Recognizing this, myDevices has introduced an innovative feature in their platform: the Codec Editor and Device Template Editor. These tools offer unprecedented customization of sensor data handling, enabling device manufacturers and partners to fine-tune their IoT solutions for various applications.

Add device templates and codecs for various devices, such as sensors, actuators, gateways, tags, and more, as well as services for storing data, setting up alerts, visualizing data using custom dashboards, and transmitting data to other business intelligence (BI), artificial intelligence (AI), computerized maintenance management system (CMMS), or asset management software. The possibilities are limitless.

 

What is a Device Template?
A Device Template is a configuration blueprint that lets users define the representation, capabilities and management settings for an IoT device, sensor, or gateway.  This includes configuring device attributes, setting up data channels, and defining alert conditions. It provides a structured way to define and manage the characteristics and capabilities of that device within myDevices' application.

A Device Template is comprised of the following:

  1. General: Information about the device, such as name, description, and manufacturer, etc.

  2. Codec: used to decode or parse the payload of the device. It allows users to create and modify the logic (in JavaScript) that interprets sensor data.

  3. Capabilities: Sensors or Actuators the device supports.

  4. Attributes: UI settings conditions for specific use cases.

  5. Alert Types: Alerts are generated based on capabilities.

  6. Device Uses: used to define the use case of the device.


What is a Codec?
A codec for a device template is a script or set of instructions used to decode the raw data payload from IoT devices into a more meaningful and structured format. This can include encoding and decoding data packets, adapting to different communication protocols, and handling data in various formats.

 

Why do I need a Device Template and Codec?
Device templates and codecs are required to onboard devices into myDevices. They are used to define the capabilities of the device, how the data is decoded, and how the data is displayed in the UI. Device templates and codecs are also used to define the use case of the device, which is used to determine the appropriate alert types and attributes for the device.

 

Get Started Steps

  1. Log into console.mydevices.com

  2. Create a Device Template Go to the Device Templates Tab. Here, you can access all templates you've created for your applications and organization. You'll also find example templates that can serve as starting points. To begin, click on "Add Device Template" in the top-right corner.

Adding a Device Template: General Tab

 

  • Fill out all the fields such as Manufacturer, model, category, sub-category, codec, general device Icon, any certifications, IP rating, description and keywords. This information will be visible to end-users when they access device details or view the device on sensor maps.

  • When adding a device template, you will define the device category and subcategory.

    • If you're adding a Gateway, select "Gateway" as the Category, and do not choose a codec. Currently, we support LoRa Gateways for the subcategory.

    • For End Devices like sensors or actuators, a codec is required, and you should choose either LoRa or MQTT as the subcategory.

    • For End Devices like BLE tags or beacons, a codec is not necessary, and you should use the subcategory "BLE."

Adding a Device Template: Defining the Capabilities

Data capabilities represent the data transmitted by the device and are decoded by the codec. Add capabilities like temperature reading, motion detection, etc., ensuring each capability has a unique data channel. These capabilities determine how data appears in the management screen, gets stored in history, and enables alert creation. Click "Add Capability" to begin defining capabilities.

 

Fill out all fields including Template Type, Data Type, Name (Data Label in app), Channel ID, Chart, Icon and Widget.

  • Template Type supports different data representations, such as (e.g. 72.4 F), status (Open/Close), Tracking (GPS, BLE), Commands: Button (e.g. Stop Alert), Commands: Toggle On/Off (e.g. Water Valve), Commands: List (e.g. IR Blaster), and Image.

  • Data Type corresponds to the type of data capability you're adding, e.g., temperature.

  • Name is the label that appears in the user interface.

  • Channel ID must match between the device template and codec.

  • Chart defines the chart displayed in device details (e.g., line chart for value devices, status chart for status-based devices).

  • Icon represents the icon for this data capability in sensor maps.

  • Widget specifies the default widget added when this capability is included in a custom dashboard.

  • Depending on whether you choose a value or status data type, you'll have options for Units or Status Labels.

 

Adding a Device Template: Adding Attributes: Attributes are used to set UI conditions for specific use cases (e.g., displaying device location on a map for tracking devices, adding resources or help links for the device, setting firmware configuration setting options for device, and providing sample payloads for sensor simulators).

  • Not all attributes are required, with only the Broadcast interval and Device Type being mandatory.

    • Broadcast interval should be set to match how often the device periodically checks in. If a device checks in only once a day, its broadcast interval should be set to 1440. By default we would recommend at least 60 minutes and no greater then 1440 minutes.

    • Device Type appears next to the device name in the UI.

    • Testing the Template: Use the simulator attribute to test how your template behaves with simulated sensor data.

 

Alert Types: Whenever you add a capability using either a Value or Status template type, the corresponding alert is generated. The alert notification text is editable, but the alert template is not editable currently.

  • For capabilities using Value template type, a Min/Max Threshold alert will automatically be created for that particular capability.

  • For capabilities using Status template type, distinct alert types are generated for each unique status. For instance, if you have a Status-based Door sensor that transmits 0 for "closed" and 1 for "open," an alert type is created for both "Open" and "Closed" states.

  • Personalizing Alert Notification Text: You have the ability to modify the text of alert notifications that will be transmitted for a specific alert type.

  • Enabling/Disabling Alert Type Settings: In certain scenarios, there may be data points where the end-user does not require an alert. In such cases, you can deactivate the display of the alert type (e.g., the "Panic Button Press" alert is visible in the user interface, while the "Not Pressed" alert can be toggled to a hidden status and will not be displayed).

Device Uses: This feature allows you to set up pre defined alerts that get added automatically during the device setup process. This is particularly valuable when you already have specific alert requirements in mind for a given use case.

  1. Import or create a Codec into Codec Editor

The Codec Editor provides a flexible environment to write and edit JavaScript for custom codec creation.
Key functions include setting up data interpretation rules, handling different data types, and integrating various sensor models. Example Use Case: Tailoring a codec for a specific temperature sensor to interpret data for a greenhouse environment, converting raw readings into actionable insights like temperature trends and anomaly detection.


Getting Started with the Codec Editor
Creating a New Codec: Click on 'Create New Codec'. Enter a name for your codec and it will automatically generate an ID.


Editing the Codec: Use the JavaScript-based interface to input or modify the code. This may include setting up data decoding functions for incoming data from sensors.


Testing Your Codec: Utilize the built-in debugger to test your codec. Input sample data payloads to see how your code interprets them.


Saving and Applying the Codec: Once satisfied, save your codec. It can now be linked to a device template for use.

 

Sample and Minimal Codec

Here is a minimal source code for the decoder.js file, with included comments explaining things.

Since it’s a JavaScript file running in a Node.JS sandbox, it allows us define a special context with dedicated data and functions.

In opposite to LoRaWAN type-of Codec, myDevices Engine doesn’t expect any specific function (although it could use a LoRaWAN type-of Codec), but provides tools to write Codec like any Node.JS script instead.

// Example Payload Decoder // Test with 00F000C8 // Temp = 24°C // Lum = 200lux const multiplier = 0.1; // Could use console.log to help debugging Codec console.log("multiplier = %d", multiplier); // Decoder.data.buffer contains a Node.JS Buffer object with the payload data // See https://nodejs.org/docs/latest-v18.x/api/buffer.html for more information console.log("Decoder.data.buffer = %s", Decoder.data.buffer.toString("hex")); const buffer = Decoder.data.buffer; // Decoder.data.fport contains LoRaWAN fPort // Could be used to filter uplink or adapt data decoding accordingly console.log("Decoder.data.fport = %d", Decoder.data.fport); // Decoder must send a Sensor Object or Sensor Object Array Decoder.sendSensors({ channel: 0, // Data Channel, must matches with Template Capability type: DataTypes.TYPE.TEMPERATURE, // Data Type unit: DataTypes.UNIT.CELSIUS, // Data Unit value: buffer.readInt16BE(0) * multiplier // Data Value }); Decoder.sendSensors({ channel: 2, type: DataTypes.TYPE.LUMINOSITY, unit: DataTypes.UNIT.LUX, value: buffer.readUInt16BE(2) }); // Complete Decoding process (optional, allows for faster response and prevent Codec timeout) Decoder.done();

 

Our Engine main global object is Decoder one, which hold:

  • data Object

    • buffer Object with payload using Node.JS Buffer interface

    • fport numerical value

    • format string value (set to "buffer" with LoRaWAN payload)

  • sendSensors function

    • Used to send sensor data, either atomically, or grouped in an array.
      Each sensor data must be an object with a few attributes:

      • channel sensor data channel (eg. unique identifier)

      • type sensor data type

      • unit sensor data unit

      • value actual sensor data value

      • timestamp (optional) used for historical data, should be provided as UTC timestamp in milliseconds

  • done function

    • Although it’s optional, it’s recommend to end your decoding process by calling Decoder.done().
      This allows to complete Decoding process before context timeout, speeding up processing.
      By default codecs are granted a maximum execution time of 100ms, which should be enough for most of use cases. It could be increased by opening a ticket in our support portal.

The second important global object is DataTypes, which have definition for all TYPE and UNIT available.
You can use editor completion to find out existing types and unit available (shortcut CTRL-SPACE).

 

Since it’s running in a sandbox, you can also use usual console.log and console.error JavaScript function, and see the result directly in the editor. However those functions will be ignored when decoding real data (from real device) in order to speed up execution time.

Using LoRaWAN Codec API

In order to use LoRaWAN type-of Codec, you just have to include the function in your myDevices codec, call it with proper arguments, and then map and send the result into sensor objects (with channel/type/unit/value).

// Past your decodeUplink function function decodeUplink(input) { // ... do something with input return output; } // Call it const result = decodeUplink({ bytes: Decoder.data.buffer, fPort: Decoder.data.fport, recvTime: new Date(Decoder.data.timestamp) }); // Map and send sensor data Decoder.sendSensors({ channel: 1, type: DataTypes.TYPE.TEMPERATURE, unit: DataTypes.UNIT.CELSIUS, value: result.temperature }); Decoder.done();

 

  1. Registry Device IDs: After creating a Device Template & Codec, you’ll next want to register device ID(s) to the new Device Template. Go to Registry Tab, click Upload Devices to begin.

  • Template Catalog

    • If you’re adding device IDs to a public template, choose Public.

    • If you’re adding device IDs to a template you created, choose Application.

  • Device Template

    • Select the appropriate template

  • Registry Type

    • You can choose to register the IDs to a specific application or make it globally available

  • Upload with Text input or CSV File

 

  1. Add the device to your app and visualize the data

 

6. Best Practices and Tips

  • Gain a fundamental understanding of JavaScript and familiarize yourself with basic IoT communication protocols for effective use of the Codec Editor.

  • Regularly review and update device templates to stay aligned with evolving sensor technologies and varying data requirements.

  • Addressing Common Concerns: Prioritize data security and privacy when customizing codecs and templates, ensuring that the data handling complies with industry standards and regulations.

  • Iterative Development: Start with a basic setup and gradually add complexity as you become more familiar with the tools.

  • Regular Updates: Continuously revisit and update your codecs and templates to cater to new sensor models and evolving requirements.

  • Documentation and Support: Leverage the myDevices documentation and community forums for troubleshooting and best practices.

 

By following these steps and tips, users can fully utilize the Codec and Device Template Editors to create customized, efficient IoT solutions tailored to their specific needs.Conclusion

The introduction of the Codec and Device Template Editors in the myDevices platform marks a significant advancement in custom sensor management. By harnessing these features, users can significantly enhance their IoT deployments, ensuring they are robust, adaptable, and tailored to their specific needs.

 

 

Real Codec Examples

Dragino LHT65 Temp & Humidity Sensor 2.0 Codec Used

//Sample data, external DS18B20 sensor: 0B4501050248010105 //Sample data, external soil moisture sensor: 0B49FF3F024802 //Sample data, external tilting sensor: 0B450105024803 "use strict"; const DS18B20_SENSOR = 0x01; const SOIL_MOISTURE_SENSOR = 0x01; const TILTING_SENSOR = 0x01; var buffer = Decoder.data.buffer; var temperature = 23; const {probe_offset = 0, internal_offset = 0, offset_unit = 'c', humidity_offset = 0} = Decoder.data.options; function getTemperatureOffset(offset) { const offset_number = Number(offset); if (offset_unit == 'c') { return offset_number; } else if (offset_unit == 'f') { // we want to solve CtoF(temp) + OFFSET_F = CtoF(temp + OFFSET_C) // and compute OFFSET_C based on OFFSET_F provided by setting ... // CtoF(x) = x * 1.8 + 32 // temp * 1.8 + 32 + OFFSET_F = (temp + OFFSET_C) * 1.8 + 32 // temp * 1.8 + 32 + OFFSET_F = temp * 1.8 + 32 + OFFSET_C * 1.8 // OFFSET_F = OFFSET_C * 1.8 // OFFSET_C = OFFSET_F / 1.8 return offset_number / 1.8; } } function decodeTemperature(offset, channel, name, temperature_offset = 0) { let value = buffer.readInt16BE(offset); let tempValue = Number((value / 100).toFixed(2)); /** * @author: Adrian * @comment: Do not send probe reading if value is equal to 327 * @date: 09/04/2019 */ if (Math.floor(tempValue) != 327) { Decoder.send({ channel: channel, type: DataTypes.TYPE.TEMPERATURE, unit: DataTypes.UNIT.CELSIUS, value: Number((value / 100).toFixed(2)) + temperature_offset, name: name }); //Save the internal temperature if (channel == 3) { temperature = tempValue; } } } decodeTemperature(2, 3, 'Internal Temp', getTemperatureOffset(internal_offset)); Decoder.send({ channel: 4, type: DataTypes.TYPE.RELATIVE_HUMIDITY, unit: DataTypes.UNIT.PERCENT, value: Number((buffer.readUInt16BE(4) / 10).toFixed(1)) + humidity_offset, name: 'Humidity' }); var external_sensor = buffer.readUInt8(6); switch(external_sensor){ case DS18B20_SENSOR: decodeTemperature(7, 7, 'Probe Temp', getTemperatureOffset(probe_offset)); break case SOIL_MOISTURE_SENSOR: //Format not yet defined break case TILTING_SENSOR: //Format not yet defined break } //Calculate battery percent using trendline from real world temperature/voltage data let maxValue = 2914 + 6.25 * temperature + -0.0793 * Math.pow(temperature, 2); if (temperature > 39) { maxValue = 3040; } if (temperature < -40) { maxValue = 2540; } console.log(maxValue) let minValue = 2400; let range = maxValue - minValue; let battery = (buffer.readUInt16BE(0) & 0x3FFF) - minValue; let batteryPercent = Number((Math.min(Math.max(battery, 0), range) / range * 100).toFixed(2)); Decoder.send({ channel: 5, type: DataTypes.TYPE.BATTERY, unit: DataTypes.UNIT.PERCENT, value: batteryPercent, name: 'Battery' }); console.log("Voltage: " + (buffer.readUInt16BE(0) & 0x3FFF) / 1000); Decoder.send({ channel: 500, type: DataTypes.TYPE.VOLTAGE, unit: DataTypes.UNIT.MILLIVOLTS, value: buffer.readUInt16BE(0) & 0x3FFF, name: 'Battery Voltage' }); Decoder.done();

 

 

Dragino LDS03 Door Sensor 2.0 Codec Used

 

 

Dragino LDDS45 Distance Detection (Rolling Average) Codec Used