When I was working at Ubuntu, I worked on the Ubuntu Core iot operating system. In the future, the Internet of Things is a bigger web than the Internet. In the Internet of Things world, a lot of data will be collected, such as temperature, humidity, weather sensor data, car and elevator performance and so on. When a large amount of data is collected, we can analyze the data through the data platform and control it in real time. In today’s article, I will share a simple example of how to monitor Internet of Things devices using Canvas.
In our hypothetical case: we have some controllable lights at home, and we monitor the status of the lights through the Canvas in Kibana, and control the light switch through the Canvas interface.
Above is a simple diagram of the Internet of Things. Iot devices here could be devices like raspberry PI. Iot devices connect to the Elastic Stack via HTTP, and connect to the lights through wireless connections like Zigbee. In today’s article, we will introduce two aspects:
- Data is sent from the Internet of Things to the Elastic Stack, and status is displayed by Kibana
- Control signals are sent from Kibana to control the status of the lamp
Send status from iot devices to the Elastic Stack
In today’s experiment, we use a simple NodeJS application to send status. You can download my simulation app at the following address:
git clone https://github.com/liu-xiao-guo/elastic_iot
Copy the code
After downloading the application, I entered the root directory of the project in Terminal and entered the following command:
npm install
npm start
Copy the code
So our NodeJS server runs at http://localhost:3000. The application will continuously send data to Elasticsearch. I can take a look at one of the most important documents:
routes/index.js
var express = require('express'); const elasticsearch = require('elasticsearch'); var router = express.Router(); var light_status = 1; Const client = new ElasticSearch.client ({host: '127.0.0.1:9200', log: 'error'}); function sendLightStatus() { console.log("light_status: " + light_status); client.index({ index: 'lights', body: { "id": 1, "status": light_status, "@timestamp": new Date(new Date().toUTCString()) } },function( err,resp, status) { console.log(resp); }); } var mytimer = setInterval( function () { console.log("ticks for every 5 seconds"); sendLightStatus(); }, 5000); router.get('/toggle', function(req, res, next) { if(light_status == 1) { light_status = 0 } else { light_status = 1 } console.log("toggled: " + light_status); sendLightStatus(); var data = { message: 'OK' }; // res.status(200).send(data); // res.sendStatus(200); // res.end(); }); /* GET home page. */ router.get('/', function(req, res, next) { console.log("/ Home page") res.render('index', { title: 'Express' }); }); router.get('/hello', function(req, res, next) { console.log("/hello") res.render('index', { title: 'Hello' }); }); module.exports = router;Copy the code
In the above code, we used light_status to hold the status of the lamp. When the /toggle interface is called, it reverses the value of light_status: the on state changes to off; the off state changes to on. Of course, in practical use, we can call on a wireless software stack like Zigbee to control our lights. We use the following code:
var mytimer = setInterval( function () {
console.log("ticks for every 5 seconds");
sendLightStatus();
}, 5000);
Copy the code
Elasticsearch sends light_status to Elasticsearch every 5 seconds. The data is stored in an index called Lights:
The sent data has the following format:
"Id" : 1, "status" :0, "@timestamp" : "2020-11-16t11:27:04.000z"Copy the code
Id indicates the INDICATOR ID. Status indicates the indicator status: 1 indicates on, 0 indicates off. We use @timestamp to indicate the sent timestamp.
We can SUM the lights data over the last 5 seconds. If the sum is greater than 0, the light is on, and if it is 0, it is off.
Display lamp status in real time through Canvas
Next, we use Canvas to show the state of the lamp:
To be able to use our own images, we can upload our images via Manage Assets:
Let’s write down the ids of these two pictures. The two images above can be found in the images directory of my previous Elastic_iot project. Click the Close button:
The title
Let’s go back to the image where we inserted the image, click Asset, and select the light_off image:
Next we resize the image and click on the Expression Editor in the lower right corner:
Let’s copy the following code into the edit:
filters
| timefilter from="now-10s" to="now"
| essql query="SELECT SUM(status) FROM \"lights\" WHERE id = 1"
| getCell "SUM_status_"
| if {gt 0}
then={image dataurl={asset "asset-5df3b112-784b-4a59-a004-1bfc03b537de"} mode="contain"}
else={image dataurl={asset "asset-674cd68c-66af-4acd-ad78-47ce1ae3add9"} mode="contain"}
| render
Copy the code
Replace the asset ID with the asset ID generated in Kibana. The first ID above is the ID of light_on, and the following ID is the ID of light_off. The code above is simple enough to take the data from the lights index from the present to the past 10 seconds and add them. If the sum is greater than 0, then the light is on. Otherwise, the lights go out. We can also see how filter is written in the following data:
Click the Run button:
Let’s go ahead and click Auto Refresh Settings:
We set it to update every two seconds. So we can see that the lights are on. This is because our default value for Elastic_iot is 1.
Call the Toggle interface to change the state of etc
We then want to switch our lights on and off by calling the /toggle interface. This implementation is tricky, but we can do it via Markdown’s link, although it’s not perfect:
Click on the Expression Editor and paste the following code:
filters | demodata | markdown "[link](http://localhost:3000/toggle)" | render css=".canvasRenderEl a { display: block; position: absolute; top: 0; bottom: 0; right: 0; left: 0; border-radius: 90px; text-indent: -10000px; }. CanvasRenderEl a:hover {background: rgba(0,0,0,.2); }"Copy the code
Click the Run button:
We need to adjust the size of this markdown to be the same as that of the lamp.
So that when we click on the images such as this, it will be called http://localhost:3000/toggle interface changes, etc. We will then see the state of the lamp send change.
One downside of the current design is that you can see a constantly rotating icon in the title of the page, indicating that the page is waiting for a response. This is due to my previous nodeJS code:
router.get('/toggle', function(req, res, next) {
if(light_status == 1) {
light_status = 0
} else {
light_status = 1
}
console.log("toggled: " + light_status);
sendLightStatus();
var data = {
message: 'OK'
};
// res.status(200).send(data);
// res.sendStatus(200);
// res.end();
});
Copy the code
No value is returned. This is obviously not a good design. But if I add a response value, the page automatically jumps to another TAB to display the current return value. The user experience is worse. I have no good way to solve this problem at present.