Control IoT device with EdgeX Kuiper rules engine
Overview
This document describes how to use Kuiper rule engine to control devices with anlysis result. To make the tutorial simple, the doc uses device-virtual sample, it analyzes the data sent from device-virtual services, and then control the device according to the analysis result produced by Kuiper rule engine.
Scenarios
In this document, following 2 rules will be created and run.
- A rule that monitoring
Random-UnsignedInteger-Device
device, and ifuint8
value is larger than20
, then send a command toRandom-Boolean-Device
device, and turn on random generation of bool value. - A rule that monitoring
Random-Integer-Device
device, and if the average value forint8
with every 20 seconds is larger than 0, then send a command toRandom-Boolean-Device
device service to turn off random generation of bool value.
The scenario does not have any real business logics, but simply to demonstrate the feature of EdgeX Kuiper rule engine. You can make a reasonable business rules based on our demo.
Prerequisite knowledge
This document will not cover basic operations for EdgeX & EMQX Kuiper, so readers should have basic knowledge for them:
- Refer to this link for learning basic knowledge of EdgeX, and it would be better to finish Quick Start.
- Refer to EdgeX Kuiper Rule Engine Tutorial: You'd better go through this quick tutorial, and get to start trying out the rules engine in the EdgeX.
- Go template: EMQX Kuiper uses Go template for extracting data from analysis result. Knowledge of Go template could help you to extract expected data from analysis result.
Start to use
Make sure you have followed document EdgeX Kuiper Rule Engine Tutorial, and successfully run the tutorial.
Create EdgeX stream
You should create a stream that can consume streaming data from EdgeX application service before creating rule. This step is not required if you already finished EdgeX Kuiper Rule Engine Tutorial.
curl -X POST \
http://$kuiper_docker:48075/streams \
-H 'Content-Type: application/json' \
-d '{
"sql": "create stream demo() WITH (FORMAT=\"JSON\", TYPE=\"edgex\")"
}'
Since both of rules will send control command to device Random-UnsignedInteger-Device
, let's get a list of available commands for this device by running below command,
curl http://localhost:48082/api/v1/device/name/Random-Boolean-Device | jq
, and it prints similar outputs as below.
{
"id": "9b051411-ca20-4556-bd3e-7f52475764ff",
"name": "Random-Boolean-Device",
"adminState": "UNLOCKED",
"operatingState": "ENABLED",
"labels": [
"device-virtual-example"
],
"commands": [
{
"created": 1589052044139,
"modified": 1589052044139,
"id": "28d88bb3-e280-46f7-949f-37cc411757f5",
"name": "Bool",
"get": {
"path": "/api/v1/device/{deviceId}/Bool",
"responses": [
{
"code": "200",
"expectedValues": [
"Bool"
]
},
{
"code": "503",
"description": "service unavailable"
}
],
"url": "http://edgex-core-command:48082/api/v1/device/bcd18c02-b187-4f29-8265-8312dc5d794d/command/d6d3007d-c4ce-472f-a117-820b5410e498"
},
"put": {
"path": "/api/v1/device/{deviceId}/Bool",
"responses": [
{
"code": "200"
},
{
"code": "503",
"description": "service unavailable"
}
],
"url": "http://edgex-core-command:48082/api/v1/device/bcd18c02-b187-4f29-8265-8312dc5d794d/command/d6d3007d-c4ce-472f-a117-820b5410e498",
"parameterNames": [
"Bool",
"EnableRandomization_Bool"
]
}
}
]
}
From the output, you can know that there are two commands, and the 2nd command is used for update configurations for the device. There are two parameters for this device,
Bool
: Set the returned value when other services want to get device data. The parameter will be used only whenEnableRandomization_Bool
is set to false.EnableRandomization_Bool
: Enable randomization generation of bool value or not. If this value is set to true, then the 1st parameter will be ignored.
So a sample control command would be similar as following.
curl -X PUT \
http://edgex-core-command:48082/api/v1/device/c1459444-79bd-46c8-8b37-d6e1418f2a3a/command/fe202437-236d-41c5-845e-3e6013b928cd \
-H 'Content-Type: application/json' \
-d '{"Bool":"true", "EnableRandomization_Bool": "true"}'
Create rules
The first rule
The 1st is a rule that monitoring Random-UnsignedInteger-Device
device, and if uint8
value is larger than 20
, then send a command to Random-Boolean-Device
device, and turn on random generation of bool value. Below is the rule definition, please notice that,
- The action will be triggered when uint8 value is larger than 20. Since the uint8 value is not used for sending control command to
Random-Boolean-Device
, theuint8
value is not used in thedataTemplate
property ofrest
action.
curl -X POST \
http://$kuiper_server:48075/rules \
-H 'Content-Type: application/json' \
-d '{
"id": "rule1",
"sql": "SELECT uint8 FROM demo WHERE uint8 > 20",
"actions": [
{
"rest": {
"url": "http://edgex-core-command:48082/api/v1/device/bcd18c02-b187-4f29-8265-8312dc5d794d/command/d6d3007d-c4ce-472f-a117-820b5410e498",
"method": "put",
"dataTemplate": "{\"Bool\":\"true\", \"EnableRandomization_Bool\": \"true\"}",
"sendSingle": true
}
},
{
"log":{}
}
]
}'
The 2nd rule
The 2nd rule is monitoring Random-Integer-Device
device, and if the average value for int8
with every 20 seconds is larger than 0, then send a command to Random-Boolean-Device
device service to turn off random generation of bool value.
- The average value for uint8 is caculated every 20 seconds, and if the average value is larger than 0, then send a control command to
Random-Boolean-Device
service.
curl -X POST \
http://$kuiper_server:48075/rules \
-H 'Content-Type: application/json' \
-d '{
"id": "rule2",
"sql": "SELECT avg(int8) AS avg_int8 FROM demo WHERE int8 != nil GROUP BY TUMBLINGWINDOW(ss, 20) HAVING avg(int8) > 0",
"actions": [
{
"rest": {
"url": "http://edgex-core-command:48082/api/v1/device/bcd18c02-b187-4f29-8265-8312dc5d794d/command/d6d3007d-c4ce-472f-a117-820b5410e498",
"method": "put",
"dataTemplate": "{\"Bool\":\"false\", \"EnableRandomization_Bool\": \"false\"}",
"sendSingle": true
}
},
{
"log":{}
}
]
}'
Now both of rules are created, and you can take a look at logs of edgex-kuiper for the rule execution result.
# docker logs edgex-kuiper
Extract data from analysis result?
It is probably that the analysis result need to be sent to command rest service as well, how to extract the data from analysis result? For example, below SQL is used for filtering data.
SELECT int8, "true" AS randomization FROM demo WHERE uint8 > 20
The output of the SQL is probably similar as below,
[{"int8":-75, "randomization":"true"}]
Let's suppose a service need following data format, while value
field is read from field int8
, and EnableRandomization_Bool
is read from field randomization
.
curl -X PUT \
http://edgex-core-command:48082/api/v1/device/${deviceId}/command/xyz \
-H 'Content-Type: application/json' \
-d '{"value":-75, "EnableRandomization_Bool": "true"}'
Kuiper uses Go template to extract data from analysis result, and the dataTemplate
should be similar as following.
"dataTemplate": "{\"value\": {{.int8}}, \"EnableRandomization_Bool\": \"{{.randomization}}\"}"
In some cases, you probably need to iterate over returned array values, or set different values with if conditions, then refer to this link for writing more complex data template expressions.
Extended readings
If you want to explore more features of EMQX Kuiper, please refer to below resources.