Displaying Metrics from IoT Devices with Kendo UI Builder

Using a custom component and the model property, we'll explore how you can easily interact with IoT devices using Kendo UI Builder.

In this next blog in my Kendo UI Builder how-to series, we are going to study a sample custom component that interacts with another component on the page via the model property. Specifically, the component will display a metric from an IoT device in a room. The data from the various rooms and devices is obtained via a REST data provider.

We will use two instances of this component on a blank view to show the temperature and the humidity in the room. The room is selected from a combobox component on the same view.

The view containing the combobox and the two custom components looks like this:

This sample component builds up from the basic component sample that I introduced earlier in the series. If you are not familiar with it, you can read more about it here.

To follow along, download the template samples zip from github or clone the repository; then open the folder components/custom-device-metrics-comp and follow the same steps outlined in this post to install this template in your target application.

Pre- Requisites

We need to set up a couple of items:

A test REST server that serves device metrics for several rooms

A Data Provider to the REST service

A blank view containing a combobox to select which room we want information from

We will leverage the REST server and data provider in several other samples in this series, so please do take the two minutes it takes setting it up. It will be time well invested.

Setting Up the REST Server (2 Minutes)

The device metrics will be provided by a test REST server. Setting it up is straightforward thanks to json-server, a zero coding REST server:

This will save you from having to configure the REST data provider to the Devices REST service installed in previous step.

Restart Kendo UI Builder and verify the IoT data provider is listed. When you edit the Devices data source, you should see this:

Setting Up the Blank View

The blank view is setup with a data source to our Devices REST service and with a drop-down list showing the list of rooms. Follow these steps:

In your application, create a blank view

In the right panel, click on the Edit button of the View’s Data Source property and create a data source like this:

On the blank view, in one column of your choice, add a combobox component with the following properties:

Once that’s done, we are ready to create instances of our device metric component and bind these instances to a specific field from the REST record (a room with device metrics) via the model “DevicesModel.”

How do we define a component that can be bound to a field in this model? Let’s look how we do that by programming the component definition file.

Component Definition

Open the file components/custom-device-metrics-comp/custom-device-metrics-comp.json

It contains the same properties as the basic component sample, so these should be familiar to you. If not please refer to this blog post.

There are two new properties:

01."valuePrimitive": {

02."type": "boolean",

03."default": true,

04."hidden": true,

05."order": 3

06.},

07."model": {

08."type": "string",

09."title": "Model",

10."default": "",

11."editorType": "modelName",

12."order": 4

13.}

In this post, we're focusing on the model. We will go into the details of valuePrimitive in the next blog when we write a multi-values component.

The model property, and more specifically the modelName editor (property editorType), provides a way to select the data source and the field to bind to the EJS model variable.

Here is how the model property renders at design-time, in the property panel:

For the first instance of my device metric custom component, I selected the model corresponding to my IoT Devices data source (DevicesModel). Then, I selected, the field currentTemp to indicate that I want the Metric component to display the current temperature from the selected room.

For the second instance, I simply selected the “hum” field (Humidity):

Now would be an appropriate time to try this for yourself: go to the blank view you created earlier and drag two instances of the custom component in two separate columns. For each one, select the model and any of the metric you like (like VOC, CO2, ect…).

The generated code base component typescript file, for example, devices.view.base.component.ts, has an object literal $dataModels with a reference to an object containing the field values we want to render in component instances

1.public $dataModels: any = {

2.DevicesModel: newIoTDevice()

3.};

And here is the definition for IoTDevice:

01.export class IoTDevice

02.{

03.public id: number;

04.public room: string;

05.public setTemp: number;

06.public currentTemp: number;

07.public hum: number;

08.public co2: number;

09.public voc: number;

10.}

The expression {{$dataModels.<%- model %>}} will be translated by the EJS compiler to {{$dataModels.DevicesModel.currentTemp>}} for the first instance of the custom component and to {{$dataModels.DevicesModel.hum>}} for the second instance, thus providing access to the values for the currently selected device (room).

Note: The code generator uses the data provider and data source names to generate the IoTDevice class name. If you used a different data provider than the one provided in the github repository the names will be different.

How is the model updated?

The model is updated each time the combobox is changed. This is happening because of this change handler registered within the combobox component (See file: generators/angular/generators/shared-module/templates/components/combo-box/combo-box.component.html in your generated project):

The generated code (controller.js) defines $viewModels as an array of data source models. The expression {{vm.$viewModels.<%-model%>}} will be translated by EJS compiler to {{ vm.$viewModels.DevicesModel.currentTemp>}} for the first instance of the custom component and to {{ vm.$viewModels.DevicesModel.hum>}} for the second instance, thus providing access to the values for the currently selected device(room).

CSS Classes

Notice that for both the Angular and AngularJS frameworks we provide a set of CSS classes to further customize the appearance and content. Here are example CSS definitions to put in view styles:

01..deviceMetric{

02.font-size: 120%;

03.margin: 1rem;

04.}

05.

06..deviceMetricLabel {

07.font-weight: normal;

08.}

09.

10..deviceMetricSeparator:before {

11.content: ":";

12.margin-right: 0.6rem;

13.}

14.

15..deviceMetricValue {

16.font-weight: bold;

17.}

Conclusion

A component typically needs to interact with data source items. This blog and its associated sample shows how:

You can define a custom component that interacts with the data source model (a property with an editor of type modelEditor)

You can leverage the model property in the component template

The component we studied is rendering a single value. In the next post, we will study a component that renders multiple values, so be sure to check it out.

Catch Up on Kendo UI Builder

If you jumped into this series in the middle and want to start from the beginning, you can find the previous blog posts here:

Thierry Ciot is a Software Architect and Product Owner on Progress Rollbase. Ciot has gained a broad experience in the development of products ranging from development tools to production monitoring systems. He is using his expertise to create a low code/rapid application development platform that provides a “Yes!” user experience. He is now focusing on responsive and adaptive modern web applications for public and private clouds. He holds two patents in the memory management space.

Choosing the Right Digital Experience Platform to Improve Business Outcomes

The Fastest Way to Build Mobile Apps With Cloud Data

Progress, Telerik, and certain product names used herein are trademarks or registered trademarks of Progress Software Corporation and/or one of its subsidiaries or affiliates in the U.S. and/or other countries. See Trademarks for appropriate markings.