Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interact with I²C Bus

This lambda reads the input voltage on a SixFab UPS Hat. The On Prem CLI is used to demonstrate manually triggering the lambda and taking delivery of the event JSON using a remote desktop.

graph LR;

cli --> control_plane;
control_plane <-- tunnel --> agent;
agent -- i2c --> hat;

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

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

subgraph device_edge[Device Edge]
agent[Agent];
hat[SixFab UPS Fan HAT];
end

Note that manually triggering a lambda is unusual in that it requires device connectivity to the control plane. A more typical scenario is where Lambdas and their Lambda Trigger control loops run autonomously at the device edge, regardless of the device's connectivity to the control plane.

Register the lambda

$ onprem generate xid
clut5qm56a1d39be96j0
# get_sixfab_ups_hat_input_voltage.yaml
name: get_sixfab_ups_hat_input_voltage
kind: Lambda
id: clut5qm56a1d39be96j0
description: >
  Read the input voltage on a SixFab UPS HAT.
runAt:
  deviceId: ci2fabp32ckvhk1g9qe0
scriptContentType: text/x-lua
script: >
  local socket = require('socket')
  local I2C = require('periphery.I2C')

  function lshift(a, b)
    return a * 2 ^ b
  end
  
  local M={}
  
  function M.handler(event, context)
    local i2c = I2C('/dev/i2c-1')
    local addr = 0x41
  
    -- send GetInputVoltage (0x02) command
    local req = {0xcd, 0x02, 0x01, 0x00, 0x00, 0xc8, 0x9a}
    i2c:transfer(addr, { req })
  
    -- wait for HAT to prepare response
    socket.sleep(0.01)

    -- read response
    local res = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, flags=I2C.I2C_M_RD}
    i2c:transfer(addr, { res })
  
    -- decode response
    local crc_hi, crc_lo = res[2], res[3]
    local crc = lshift(crc_hi, 8) + crc_lo
    local datalen_hi, datalen_lo = res[4], res[5]
    local datalen = lshift(datalen_hi, 8) + datalen_lo
    assert(datalen == 4)
    local x3, x2, x1, x0 = res[6], res[7], res[8], res[9]
    local raw_reading = lshift(x3, 24) + lshift(x2, 16) + lshift(x1, 8) + x0
    local voltage = raw_reading / 1000
  
    -- respond
    return {voltage=voltage, rawReading=raw_reading, crc=crc}
  end
  
  return M
$ onprem apply get_sixfab_ups_hat_input_voltage.yaml

It will now show up in the cloud console.

Cloud Console

Invoke it

$ onprem run lambda clut5qm56a1d39be96j0
{"crc":514,"rawReading":4928,"voltage":4.928}