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.
In this document, following 2 rules will be created and run.
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.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 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.
This document will not cover basic operations for EdgeX & EMQ X Kuiper, so readers should have basic knowledge for them:
Make sure you have followed document EdgeX Kuiper Rule Engine Tutorial, and successfully run the tutorial.
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 when EnableRandomization_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"}'
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,
Random-Boolean-Device
, the uint8
value is not used in the dataTemplate
property of rest
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 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.
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
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.
If you want to explore more features of EMQ X Kuiper, please refer to below resources.