Arete Control Plane for Smart Buildings

This example demonstrates use of the Arete SDK for smart buildings. It reproduces the Arete SDK example called "the switch and the light", by restructuring its flow as Lambda Trigger control loops, and Lambdas.

On a 1st node, the On Prem Agent runs "the switch", which consists of:

  • a Lambda Trigger that subscribes to GPIO 04 edge events, and
  • a Lambda that translates those events into a new desired state, and publishes it to the Arete control plane.

On a 2nd node, the On Prem Agent runs "the light", whcih consists of:

  • a Lambda Trigger that subscribes to Arete control plane events containing desired state changes, and
  • a Lambda that takes those events with new changes to desired state, and realizes it by setting a GPIO 23 pin.

Initial Provisioning

graph LR;

cli --> control_plane;
console --> control_plane;
control_plane <-- tunnel --> agent_1;
control_plane <-- tunnel --> agent_2;

subgraph user_edge[User Edge]
cli[CLI];
console[Console];
end

subgraph cloud[Cloud <small>api.on-prem.net</small>]
control_plane[Control Plane];
end

subgraph device_edge_1[Device Edge]
agent_1[Agent 1];
agent_2[Agent 2];
end

Subsequent Autonomous Edge Operation

graph TB;

switch --> arete_control_plane;
arete_control_plane --> light;

subgraph device_edge[Device Edge]
agent_1;
agent_2;
arete_control_plane;
end

subgraph agent_1[Agent 1]
gpio_04_pin[GPIO 04 pin];
switch[Switch];
gpio_04_pin -- edge trigger --> switch;
end

subgraph agent_2[Agent 2]
gpio_23_pin[GPIO 23 pin];
light[Light];
light --> gpio_23_pin;
end

arete_control_plane[(Arete Control Plane)];

Part 1: The Switch

Define the Lambda Trigger to detect the GPIO edge triggers

$ onprem generate xid
cj7ca3berad6gieb3rbg
# arete_switch_gpio_trigger.yaml
id: cj7ca3berad6gieb3rbg
kind: LambdaTrigger
name: arete_switch_gpio_trigger
description: >
  Detect GPIO edge events, and emit them to a downstream lambda.
scriptContentType: Lua
script: >
  local GPIO = require('periphery.GPIO')

  local M = {}

  function M.init(context)
    -- Configure GPIO 04 pin for input
    local params = {
      path      = '/dev/gpiochip0',
      line      = 4,
      direction = 'in',
      edge      = 'both',
    }
    local pin = GPIO(params)
    context['pin'] = pin
  end

  function M.run(context)
    local pin = context.pin
    while true do
      local event = pin:read_event()
      coroutine.yield(event)
    end
  end

  return M
$ onprem apply ./arete_switch_gpio_trigger.yaml

Define the Lambda that will receive the GPIO events, and transmit to Arete

$ onprem generate xid
d322bqpcaq0mr0n3a2bg
# arete_switch.yaml
id: d322bqpcaq0mr0n3a2bg
kind: Lambda
name: arete_switch
description: >
  Respond to GPIO edge events, and transmit as new desired state to the Arete control plane.
triggerId: cj7ca3berad6gieb3rbg
scriptContentType: Lua
script: >
  local NODE_ID = 'ozr9fZbU8i7hMdjEjuTS2o'
  local NODE_NAME = 'On Prem Arete Switch'

  local CONTEXT_ID = 'uRLoYsXEY7nsbs9fRdjM8A'
  local CONTEXT_NAME = 'Building 23, Office 41-B'

  local PADI_LIGHT_PROFILE = 'padi.light'

  local M = {}

  function M.handler(event, context)
    -- Configure Arete client, the first time
    if context.areteClient == nil then
      context['areteClient'] = M.newAreteClient()
    end
    local areteClient = context.areteClient
  
    -- Transmit new desired state to Arete control plane
    local desiredState = if event.edge == 'falling' then '1' else '0' end
    areteClient:putProperty(NODE_ID, CONTEXT_ID, PADI_LIGHT_PROFILE, 'sOut', desiredState)
  end
  
  function M.newAreteClient()
    local arete = require('arete-sdk')

    local areteClient = arete.Client:new('wss://dashboard.test.cns.dev:443')
    areteClient:waitForOpen()
    areteClient:addSystem()
    areteClient:addNode(NODE_ID, NODE_NAME)
    areteClient:addContext(NODE_ID, CONTEXT_ID, CONTEXT_NAME)
    areteClient:addProvider(NODE_ID, CONTEXT_ID, PADI_LIGHT_PROFILE)
    return areteClient
  end
  
  return M
$ onprem apply ./arete_switch.yaml

Part 2: The Light

Define the Lambda Trigger that will detect changes to desired state

$ onprem generate xid
cj7ca3berad6gieb3rbg
# arete_light_trigger.yaml
id: cj7ca3berad6gieb3rbg
kind: LambdaTrigger
name: arete_light_trigger
description: >
  Subscribe to the Arete control plane for the desired state of a light.
scriptContentType: Lua
script: >
  local M = {}

  function M.init(context)
    context['areteClient'] = M.newAreteClient()
  end

  function M.run(context)
    local areteClient = context.areteClient
    for event, abort in areteClient:onUpdate() do
      coroutine.yield(event)
    end
  end

  function M.newAreteClient()
    local arete = require('arete-sdk')

    local NODE_ID = 'onqXVczGoymQkFc3UN6qcM'
    local NODE_NAME = 'On Prem Arete Light'

    local CONTEXT_ID = 'uRLoYsXEY7nsbs9fRdjM8A'
    local CONTEXT_NAME = 'Building 23, Office 41-B'

    local PADI_LIGHT_PROFILE = 'padi.light'

    local areteClient = arete.Client:new('wss://dashboard.test.cns.dev:443')
    areteClient:waitForOpen()
    areteClient:addSystem()
    areteClient:addNode(NODE_ID, NODE_NAME)
    areteClient:addContext(NODE_ID, CONTEXT_ID, CONTEXT_NAME)
    areteClient:addConsumer(NODE_ID, CONTEXT_ID, PADI_LIGHT_PROFILE)
    return areteClient
  end

  return M
$ onprem apply ./arete_light_trigger.yaml

Define the Lambda that will realize the desired state by turning on a light

$ onprem generate xid
d322gs1caq0mvt65gb4g
# arete_light.yaml
id: d322gs1caq0mvt65gb4g
kind: Lambda
name: arete_light_trigger
description: >
  Turn on a light.
triggerId: cj7ca3berad6gieb3rbg
scriptContentType: Lua
script: >
  local GPIO = require('periphery.GPIO')

  local M = {}

  function M.handler(event, context)
    -- Configure GPIO 23 pin for output, the first time
    if context.pin == nil then
      local params = {
        path      = '/dev/gpiochip0',
        line      = 23,
        direction = 'out',
      }
      local pin = GPIO(params)
      context['pin'] = pin
    end
    local pin = context.pin
  
    -- Realize the desired state
    local desiredState = event.sState == '1'
    pin:write(desiredState)
  end

  return M
$ onprem apply ./arete_light.yaml

©2025 Megalithic LLC | Website | GitLab | GitLab (Megalithic)