Skip to content

Command device with EdgeX eKuiper rules engine

Overview

This document describes how to actuate a device with rules trigger by the eKuiper rules engine. To make the example simple, the virtual device device-virtual is used as the actuated device. The eKuiper rules engine analyzes the data sent from device-virtual services, and then sends a command to virtual device based a rule firing in eKuiper based on that analysis. It should be noted that an application service is used to route core data through the rules engine.

Use Case Scenarios

Rules will be created in eKuiper to watch for two circumstances:

  1. monitor for events coming from the Random-UnsignedInteger-Device device (one of the default virtual device managed devices), and if a uint8 reading value is found larger than 20 in the event, then send a command to Random-Boolean-Device device to start generating random numbers (specifically - set random generation bool to true).
  2. monitor for events coming from the Random-Integer-Device device (another of the default virtual device managed devices), and if the average for int8 reading values (within 20 seconds) is larger than 0, then send a command to Random-Boolean-Device device to stop generating random numbers (specifically - set random generation bool to false).

These use case scenarios do not have any real business meaning, but easily demonstrate the features of EdgeX automatic actuation accomplished via the eKuiper rule engine.

Prerequisite Knowledge

This document will not cover basic operations of EdgeX or LF Edge eKuiper. Readers should have basic knowledge of:

  • Get and start EdgeX. Refer to Quick Start for how to get and start EdgeX with the virtual device service.
  • Run the eKuiper Rules Engine. Refer to EdgeX eKuiper Rule Engine Tutorial to understand the basics of eKuiper and EdgeX.

Start eKuiper and Create an EdgeX Stream

Make sure you read the EdgeX eKuiper Rule Engine Tutorial and successfully run eKuiper with EdgeX.

First create a stream that can consume streaming data from the EdgeX application service (rules engine profile). This step is not required if you already finished the EdgeX eKuiper Rule Engine Tutorial .

bash
curl -X POST \
  http://$ekuiper_docker:59720/streams \
  -H 'Content-Type: application/json' \
  -d '{"sql": "create stream demo() WITH (FORMAT=\"JSON\", TYPE=\"edgex\")"}'

Get and Test the Command URL

Since both use case scenario rules will send commands to the Random-Boolean-Device virtual device, use the curl request below to get a list of available commands for this device.

bash
curl http://127.0.0.1:59882/api/v2/device/name/Random-Boolean-Device | jq

It should print results like those below.

json
{
  "apiVersion": "v2",
  "statusCode": 200,
  "deviceCoreCommand": {
    "deviceName": "Random-Boolean-Device",
    "profileName": "Random-Boolean-Device",
    "coreCommands": [
      {
        "name": "WriteBoolValue",
        "set": true,
        "path": "/api/v2/device/name/Random-Boolean-Device/WriteBoolValue",
        "url": "http://edgex-core-command:59882",
        "parameters": [
          {
            "resourceName": "Bool",
            "valueType": "Bool"
          },
          {
            "resourceName": "EnableRandomization_Bool",
            "valueType": "Bool"
          }
        ]
      },
      {
        "name": "WriteBoolArrayValue",
        "set": true,
        "path": "/api/v2/device/name/Random-Boolean-Device/WriteBoolArrayValue",
        "url": "http://edgex-core-command:59882",
        "parameters": [
          {
            "resourceName": "BoolArray",
            "valueType": "BoolArray"
          },
          {
            "resourceName": "EnableRandomization_BoolArray",
            "valueType": "Bool"
          }
        ]
      },
      {
        "name": "Bool",
        "get": true,
        "set": true,
        "path": "/api/v2/device/name/Random-Boolean-Device/Bool",
        "url": "http://edgex-core-command:59882",
        "parameters": [
          {
            "resourceName": "Bool",
            "valueType": "Bool"
          }
        ]
      },
      {
        "name": "BoolArray",
        "get": true,
        "set": true,
        "path": "/api/v2/device/name/Random-Boolean-Device/BoolArray",
        "url": "http://edgex-core-command:59882",
        "parameters": [
          {
            "resourceName": "BoolArray",
            "valueType": "BoolArray"
          }
        ]
      }
    ]
  }
}

From this output, look for the URL associated to the PUT command (the first URL listed). This is the command eKuiper will use to call on the device. There are two parameters for this command:

  • 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/disable the randomization generation of bool values. If this value is set to true, then the 1st parameter will be ignored.

You can test calling this command with its parameters using curl as shown below.

bash
curl -X PUT \
  http://edgex-core-command:59882/api/v2/device/name/Random-Boolean-Device/WriteBoolValue \
  -H 'Content-Type: application/json' \
  -d '{"Bool":"true", "EnableRandomization_Bool": "true"}'

Create rules

Now that you have EdgeX and eKuiper running, the EdgeX stream defined, and you know the command to actuate Random-Boolean-Device, it is time to build the eKuiper rules.

The first rule

Again, the 1st rule is to monitor for events coming from the Random-UnsignedInteger-Device device (one of the default virtual device managed devices), and if a uint8 reading value is found larger than 20 in the event, then send the command to Random-Boolean-Device device to start generating random numbers (specifically - set random generation bool to true).

Option 1: Use Rest API

Given the URL and parameters to the command, below is the curl command to declare the first rule in eKuiper.

bash
curl -X POST \
  http://$ekuiper_server:59720/rules \
  -H 'Content-Type: application/json' \
  -d '{
  "id": "rule1",
  "sql": "SELECT uint8 FROM demo WHERE uint8 > 20",
  "actions": [
    {
      "rest": {
        "url": "http://edgex-core-command:59882/api/v2/device/name/Random-Boolean-Device/WriteBoolValue",
        "method": "put",
        "dataTemplate": "{\"Bool\":\"true\", \"EnableRandomization_Bool\": \"true\"}",
        "sendSingle": true
      }
    },
    {
      "log":{}
    }
  ]
}'

Option 2: Use Messaging

See core-command for details. Take the first rule as an example to describe how to configure it:

  1. Set the MESSAGEQUEUE_EXTERNAL_ENABLED environment variable to true to enable the external messagebus of core-command. Set the MESSAGEQUEUE_EXTERNAL_URL environment variable to the address and port number of the external messagebus.

  2. Create the rule using the following configuration:

    shell
    {
      "sql": "SELECT uint8 FROM demo WHERE uint8 > 20",
      "actions": [
        {
          "mqtt": {
            "server": "tcp://mqtt-server:1883",
            "topic": "edgex/command/request/Random-Boolean-Device/WriteBoolValue/set",
            "dataTemplate": "{\"ApiVersion\": \"v2\", \"contentType\": \"application/json\", \"CorrelationID\": \"14a42ea6-c394-41c3-8bcd-a29b9f5e6840\", \"RequestId\": \"e6e8a2f4-eb14-4649-9e2b-175247911380\", \"Payload\": \"eyJCb29sIjogInRydWUiLCAiRW5hYmxlUmFuZG9taXphdGlvbl9Cb29sIjogInRydWUifQ==\"}"
          }
        },
        {
          "log":{}
        }
      ]
    }

    The payload is the base64-encoding json struct:

    shell
    {"Bool":"true", "EnableRandomization_Bool": "true"}
  3. Receive command response message from external MQTT broker on topic edgex/command/response/#

    shell
    {
      "ReceivedTopic": "edgex/device/command/response/device-virtual/Random-Boolean-Device/WriteBoolValue/set",
      "CorrelationID": "14a42ea6-c394-41c3-8bcd-a29b9f5e6840",
      "ApiVersion": "v2",
      "RequestID": "e6e8a2f4-eb14-4649-9e2b-175247911380",
      "ErrorCode": 0,
      "Payload": null,
      "ContentType": "application/json",
      "QueryParams": {}
    }

The second rule

The 2nd rule is to monitor for events coming from the Random-Integer-Device device (another of the default virtual device managed devices), and if the average for int8 reading values (within 20 seconds) is larger than 0, then send a command to Random-Boolean-Device device to stop generating random numbers (specifically - set random generation bool to false).

Option 1: Use Rest API

Here is the curl request to setup the second rule in eKuiper. The same command URL is used as the same device action (Random-Boolean-Device's PUT bool command) is being actuated, but with different parameters.

bash
curl -X POST \
  http://$ekuiper_server:59720/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:59882/api/v2/device/name/Random-Boolean-Device/WriteBoolValue",
        "method": "put",
        "dataTemplate": "{\"Bool\":\"false\", \"EnableRandomization_Bool\": \"false\"}",
        "sendSingle": true
      }
    },
    {
      "log":{}
    }
  ]
}'

Option 2: Use Messaging

The procedure is the same as the previous step. Use the following configuration to create a rule:

shell
{
  "sql": "SELECT avg(int8) AS avg_int8 FROM demo WHERE int8 != nil GROUP BY  TUMBLINGWINDOW(ss, 20) HAVING avg(int8) > 0",
  "actions": [
    {
      "mqtt": {
        "server": "tcp://mqtt-server:1883",
        "topic": "edgex/command/request/Random-Boolean-Device/WriteBoolValue/set",
        "dataTemplate": "{\"ApiVersion\": \"v2\", \"contentType\": \"application/json\", \"CorrelationID\": \"14a42ea6-c394-41c3-8bcd-a29b9f5e6840\", \"RequestId\": \"e6e8a2f4-eb14-4649-9e2b-175247911380\", \"Payload\": \"eyJCb29sIjogImZhbHNlIiwgIkVuYWJsZVJhbmRvbWl6YXRpb25fQm9vbCI6ICJmYWxzZSJ9\"}"
      }
    },
    {
      "log":{}
    }
  ]
}

Watch the eKuiper Logs

Both rules are now created in eKuiper. eKuiper is busy analyzing the event data coming for the virtual devices looking for readings that match the rules you created. You can watch the edgex-kuiper container logs for the rule triggering and command execution.

bash
docker logs edgex-kuiper

Explore the Results

You can also explore the eKuiper analysis that caused the commands to be sent to the service. To see the data from the analysis, use the SQL below to query eKuiper filtering data.

sql
SELECT int8, "true" AS randomization FROM demo WHERE uint8 > 20

The output of the SQL should look similar to the results below.

json
[{"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.

shell
curl -X PUT \
  http://edgex-core-command:59882/api/v2/device/name/${deviceName}/command \
  -H 'Content-Type: application/json' \
  -d '{"value":-75, "EnableRandomization_Bool": "true"}'

eKuiper uses Go template to extract data from analysis result, and the dataTemplate should be similar as following.

text
"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 eKuiper, please refer to below resources.