Custom Logic Blocks

A Custom Logic Block can be used to evaluate complex logic that can not be implemented with a simple comparison block.

A set of example logic blocks can be found here:

https://github.com/akenza-io/akenza-logic-block-examples

Emitting actions

If a condition is met, an action has to be emitted that will invoke the consecutive rule actions.

if (currentTemperature > threshold) {
  emit("action", {
    message: `temperature (${currentTemperature} °C) is above threshold (${threshold} °C)`,
  });
}

Re-invoking the rule engine

It is possible to re-invoke the rule engine by enabling the setting in the rule action. This is useful, to apply another rule to the output of a custom logic block.

Note that the emit action is expected to have a specific format (same structure as the sample output in device type scripts), see Emit Function for details. This means that properties like topic, timestamp (optional) and data should be provided and will be processed in subsequent rules.

if (currentTemperature > threshold) {
  emit("action", {
    data: { temperature, threshold, message: `temperature (${currentTemperature} °C) is above threshold (${threshold} °C)` },
    topic: "alert"
  });
}java

If the topic is specified in the emit action, it will override the one specified in the custom akenza db rule action.

Rule Action - Custom Payload

When using a custom payload template in the rule action, make sure to use {{result.*}} to access data that has been emitted as part of the rule action. For example, to store the result of a rule action that has been used to re-invoke the rule engine, use {{result.data}}. Otherwise the whole result object will be stored as a sample meaning topic, timestamp, data and meta (if specified) will be contained in the data object.

Emitting a timer

By emitting a timer, you can schedule a rule to run be invoked again in the future.

emit("timer", {
    runAt: new Date(Date.now() + 60 * 60 * 1000), //the timestamp of when the rule should be invoked
    meta: {} //metadata that will be available during the invocation of the time
  });

meta can then be accessed using event.timer.meta.

Event examples

A decoded uplink that triggers a custom logic block, looks as follows. Note that the state is controlled by the script author (see Stateful Operations):

{
  "inputs": {
    "occupied": false
  },
  "state": {
    "devices": {
      "00000000000000ff": {
        "lastOccupiedTimestamp": 1716553293784,
        "currentlyOccupied": false,
        "lastMessageTimestamp": 1716553385376,
        "sent": true
      }
    }
  },
  "type": "uplink",
  "dataSources": {
    "1": {
      "correlationId": "77777777-7777-7777-7777-77777777",
      "device": {
        "connectivity": "LORA",
        "customFields": {
          "FloorNumber": 1,
          "SiteId": "ZURICH",
          "IsWarmDeskEnabled": "true",
          "SpaceId": "1OGR35"
        },
        "name": "Meeting Room R35",
        "description": "",
        "id": "00000000000000ff",
        "deviceId": "1234567891012131",
        "workspaceId": "2900000000000000",
        "tags": [
          "occupancy",
          "climate"
        ]
      },
      "deviceId": "1234567891012131",
      "akenzaDeviceId": "00000000000000ff",
      "topic": "occupancy",
      "timestamp": "2024-05-24T12:38:06.122Z",
      "data": {
        "occupied": false,
        "motionCount": 0
      },
      "trigger": true,
      "deviceInput": false,
      "tagInput": true,
      "tagCombinationInput": false,
      "triggerOnUplink": true,
      "lastSample": false
    }
  },
  "device": {
    "connectivity": "LORA",
    "customFields": {
      "FloorNumber": 1,
      "SiteId": "ZURICH",
      "SpaceId": "1OGR35"
    },
    "name": "Meeting Room R35",
    "description": "",
    "id": "00000000000000ff",
    "deviceId": "1234567891012131",
    "workspaceId": "2900000000000000",
    "tags": [
      "occupancy",
      "climate"
    ]
  },
  "numberOfInvocations": 0,
  "properties": {}
}

Logic Block timer event

A time-based event that triggers a custom logic block, looks as follows. Note that the state is controlled by the script author (see Stateful Operations):

{
  "inputs": {
    "occupied": null
  },
  "state": {
    "devices": {
      "00000000000fffff": {
        "lastOccupiedTimestamp": 1716553293784,
        "currentlyOccupied": false,
        "lastMessageTimestamp": 1716560583110,
        "sent": false
      }
    }
  },
  "type": "timer",
  "dataSources": {},
  "numberOfInvocations": 0,
  "properties": {}
}

Logic Block last sample timer event

A time-based event that triggers a custom logic block, looks as follows.

Note that the state is controlled by the script author (see Stateful Operations):

{
  "inputs": {
    "temperature": 23.84
  },
  "state": {},
  "type": "timer",
  "dataSources": {
    "1": {
      "correlationId": "77777777-7777-7777-7777-777777777777",
      "device": {
        "connectivity": "LORA",
        "customFields": {},
        "name": "Watteco Senso",
        "description": null,
        "id": "1998877667788991",
        "deviceId": "000000000000ffff",
        "workspaceId": "2929292929292929",
        "tags": []
      },
      "deviceId": "000000000000ffff",
      "akenzaDeviceId": "1998877667788991",
      "topic": "default",
      "timestamp": "2024-05-24T13:20:14.869Z",
      "data": {
        "temperature": 23.84,
        "humidity": 51.3,
        "voc": 553,
        "co2": 518
      },
      "meta": null,
      "uplinkMeta": {
        "dataReceived": "2024-05-24T13:20:14.150224453Z",
        "bytesReceived": 952,
        "processingStart": "2024-05-24T13:20:14.220414139Z",
        "scriptRunUplinkStart": null,
        "scriptRunUplinkEnd": null,
        "processingEnd": "2024-05-24T13:20:14.259641209Z",
        "outputProduced": null,
        "ruleResolutionStart": "2024-05-24T13:20:14.805071863Z",
        "ruleResolutionEnd": null,
        "ruleExecutionStart": null,
        "ruleExecutionEnd": null,
        "uplinkDuration": "PT0S",
        "processingDuration": "PT0.03922707S",
        "ruleResolutionDuration": "PT0S",
        "ruleExecutionDuration": "PT0S",
        "scriptRunningDuration": "PT0S"
      },
      "trigger": false,
      "deviceInput": true,
      "tagInput": false,
      "tagCombinationInput": false,
      "triggerOnUplink": false,
      "lastSample": true
    }
  },
  "numberOfInvocations": 0,
  "properties": {}
}

Last updated