Skip to content
basement-labPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

Repository files navigation

ExBalena

Hex.pm Hex Docs License: MIT

Elixir client for the balena Supervisor HTTP API.

Call the Supervisor from a service on the device (local HTTP API), or from your laptop / CI through the balenaCloud Supervisor proxy.

Hex ex_balena (0.1.3)
Docs hexdocs.pm/ex_balena
Source basement-lab/ex_balena
License MIT

What this is (and is not)

This package Not this package
balena Supervisor HTTP API (/v1, /v2, /ping) balenaCloud OpenAPI / SDK (fleets, releases, devices, billing, …)
Device agent control (state, restart, reboot, host-config, …) Full balena platform management
On-device or remote proxy access A complete typed SDK of every Supervisor route (yet)

Official reference (source of truth):


Versions that matter

There are three independent version axes. Mixing them up is the usual source of “works on my device / fails on yours.”

1. Hex package version (ex_balena)

Package Status
0.1.3 (current) Thin Tesla client, dual-mode auth, generic v1/v2 GET/POST, a few named helpers

Always pin with ~> in mix.exs so you get compatible patch releases only.

2. HTTP API route version (/v1 vs /v2)

The Supervisor documents routes under:

Prefix Role
/ping Unversioned liveness
/v1/... Original device/control endpoints (blink, reboot, device state, host-config, single-container app helpers, …)
/v2/... Multi-container / newer surface (applications state, service actions, state status, local mode, journal, device tags, …)

Balena’s docs still note historically that “the API is versioned (currently at v1)”; in practice both v1 and v2 are first-class in the same reference page. Prefer v2 for multi-container fleets; many v1 app routes return 400 on multi-container devices.

3. Supervisor agent version on the device

Each endpoint (and some response fields) has a minimum supervisor version. The device’s running agent—not the Hex package—decides whether a call succeeds.

Fact Value (verified 2026-08-06)
Latest published agent balena-supervisor v19.0.5 (released 2026-08-05)
Baseline HTTP API Supervisor ≥ 1.1.0 (OS images after 2015-10-14)
BALENA_* env names Prefer these; devices on supervisor < 7.22.0 used RESIN_*
How to check on a device GET /v2/version (since supervisor v7.21) or dashboard / host OS

Minimum supervisor versions (from official API docs)

Endpoint / feature Min supervisor
HTTP API present 1.1.0
GET /v1/device 1.6
GET/POST /v1/apps/:appId... 1.8
GET /v1/healthy 6.5
GET/PATCH /v1/device/host-config 6.6
/v2/applications/:appId/{restart,purge,*-service} 7.0 (serviceName body field: 8.2.2+)
GET /v2/applications/state (+ per-app state) 7.12
GET /v2/version, local-mode routes 7.21
GET /v2/containerId 8.6
GET /v2/state/status 9.7
GET /v2/device/name, GET /v2/device/tags 9.11
GET /v2/cleanup-volumes 10.0
POST /v2/journal-logs 10.2 (format: 10.3; since/until: 14.7.0)
GET /v2/device/vpn 11.4
Host-config respects update locks (PATCH) 12.11.34+ (with balenaOS 2.82.6+)
host-config proxy dns (dnsu2t) 16.6.0
updateStatus / appUuid / service image on applications state 17.7.0
PATCH /v2/device/tags 17.8

ExBalena does not negotiate these versions for you. If you call an endpoint newer than the device supervisor, you will get HTTP errors from the agent.


Library coverage (honest, verified against official API)

Checked 2026-08-06 against Supervisor API and agent v19.0.5.

What ex_balena is today

A practical HTTP foundation:

  • Dual-mode Tesla client (on-device apikey or remote Bearer token)
  • Finch pool under ExBalena.Supervisor
  • Generic GET / POST for /v1 and /v2
  • Named helpers for the most common “is it up / what’s running?” flows

What it is not (yet)

Gap Detail
Full named API Most official routes lack first-class functions
PATCH Required for host-config and device tags; not exposed on helpers
Typed models No request/response structs matching Supervisor JSON
Uniform results V1 returns Tesla results; V2 maps some statuses; 202/204/streams not fully normalized
Remote proxy wrappers Only Balena.current_state/1 builds {uuid, method, ...}; generic calls do not

Endpoint map

Legend: ✅ named helper · 🟡 via ExBalena.API.V1|V2 get/post (you supply path/body) · ❌ needs PATCH or streaming support beyond current helpers · ⚪ local-mode / CLI-oriented

Unversioned & v1

Method Path Min SV Coverage
GET /ping 1.1.0 🟡
POST /v1/blink — 🟡
POST /v1/update — 🟡
POST /v1/reboot — 🟡
POST /v1/shutdown — 🟡
POST /v1/purge — 🟡
POST /v1/restart — 🟡
POST /v1/regenerate-api-key — 🟡
GET /v1/device 1.6 🟡
POST /v1/apps/:appId/stop 1.8 🟡
POST /v1/apps/:appId/start 1.8 🟡
GET /v1/apps/:appId 1.8 🟡
GET /v1/healthy 6.5 ✅ ExBalena.healthy/0
PATCH /v1/device/host-config 6.6 ❌
GET /v1/device/host-config 6.6 🟡

v2

Method Path Min SV Coverage
GET /v2/applications/state 7.12 ✅ Balena.current_state/0 · remote current_state/1
GET /v2/applications/:appId/state 7.12 🟡
GET /v2/state/status 9.7 🟡
POST /v2/applications/:appId/restart-service 7.0 🟡
POST /v2/applications/:appId/stop-service 7.0 🟡
POST /v2/applications/:appId/start-service 7.0 🟡
POST /v2/applications/:appId/restart 7.0 🟡
POST /v2/applications/:appId/purge 7.0 🟡
GET /v2/version 7.21 🟡
GET /v2/containerId 8.6 🟡
GET/POST /v2/local/target-state 7.21 ⚪ / 🟡
GET /v2/local/device-info 7.21 ⚪ / 🟡
GET /v2/local/logs 7.21 ⚪ stream
GET /v2/device/name 9.11 🟡
GET /v2/device/tags 9.11 🟡
PATCH /v2/device/tags 17.8 ❌
GET /v2/device/vpn 11.4 🟡
GET /v2/cleanup-volumes 10.0 🟡
POST /v2/journal-logs 10.2 🟡 / stream caveats

Installation

def deps do
  [
    {:ex_balena, "~> 0.1.3"}
  ]
end
mix deps.get

Setup

Start Finch

# application.ex
children = [
  ExBalena.Supervisor
  # ...
]

Or dynamically:

{:ok, _pid} = ExBalena.Supervisor.start_link()
# equivalent:
:ok = ExBalena.start()

On-device: enable Supervisor API

Label services that need the API:

services:
  my-service:
    labels:
      io.balena.features.supervisor-api: "1"

See multi-container labels.

Credentials & environment

On device

Variable Used for
BALENA Client treats "1" / "true" as on-device mode
BALENA_SUPERVISOR_ADDRESS Base URL, e.g. http://127.0.0.1:48484
BALENA_SUPERVISOR_API_KEY Query apikey (required for all routes except /ping)
BALENA_APP_ID Fleet id for many v1/v2 paths

Supervisor < 7.22.0: use RESIN_* names instead of BALENA_*.

Remote (dev machine / CI)

Source Used for
~/.balena/token Bearer token (balena login)
Device uuid / deviceId / fleet appId Proxy targeting

Remote base URL used by this client:

https://api.balena-cloud.com/supervisor

Official proxy: POST /supervisor/<path> with JSON including uuid or deviceId or appId, optional method (default POST), optional data for the supervisor body. See Balena’s remote examples in the Supervisor API docs.


Usage

Health (supervisor ≥ 6.5)

ExBalena.healthy()
# GET /v1/healthy

Application state (supervisor ≥ 7.12)

# On device
Balena.current_state()
# GET /v2/applications/state

# Remote proxy
Balena.current_state("your-device-uuid")
# POST .../supervisor/v2/applications/state
# body: %{"uuid" => "...", "method" => "GET"}

Fields such as updateStatus, appUuid, and service image require supervisor ≥ 17.7.0.

Generic v1 / v2

ExBalena.API.V1.get("/device")
ExBalena.API.V1.post("/reboot", %{})
ExBalena.API.V1.post("/update", %{"force" => true})

ExBalena.API.V2.get("/version")
ExBalena.API.V2.get("/state/status")
ExBalena.API.V2.post("/applications/#{app_id}/restart-service", %{
  "serviceName" => "main",
  "force" => false
})

Paths are appended after /v1 or /v2. Bodies are JSON maps.

Remote caveat: generic get/1 and post/2 use the remote base URL and Bearer token, but do not auto-wrap {uuid, method, data}. Use Balena.current_state/1 as a pattern, or build the proxy body yourself.

Raw Tesla client

client = ExBalena.Client.new()
Tesla.get(client, "/v2/version")

Mode selection inside ExBalena.Client:

Condition Base URL Auth
BALENA in {"1","true"} BALENA_SUPERVISOR_ADDRESS ?apikey=
otherwise https://api.balena-cloud.com/supervisor Authorization: Bearer from ~/.balena/token

Modules

Module Responsibility
ExBalena Entry: start/0, healthy/0
ExBalena.Supervisor OTP; Finch pool ExBalena.Finch
ExBalena.Client Tesla client (base URL + auth)
ExBalena.API.V1 Generic GET/POST under /v1
ExBalena.API.V2 Generic GET/POST under /v2 + light response handling
Balena Domain helpers (current_state/0, current_state/1)
Balena.Device Types (uuid)
Balena.API Shared types (endpoint, body)

Runtime requirements

Requirement Notes
Elixir Declared ~> 1.0 in mix.exs; this repo’s .tool-versions uses Elixir 1.12.3 / OTP 24.1.2
On-device io.balena.features.supervisor-api + env vars; agent ≥ endpoint minimum
Remote ~/.balena/token + permission on target device/fleet
Runtime deps tesla ~> 1.4, finch ~> 0.9.1, jason ~> 1.2

Documentation

Resource Link
Hex https://hex.pm/packages/ex_balena
ExDoc https://hexdocs.pm/ex_balena
Supervisor API https://docs.balena.io/reference/supervisor/supervisor-api/
Supervisor changelog https://github.com/balena-os/balena-supervisor/blob/master/CHANGELOG.md
Update locks https://docs.balena.io/learn/deploy/release-strategy/update-locking/
Labels https://www.balena.io/docs/learn/develop/multicontainer/#labels
mix deps.get
mix docs

Development

mix deps.get
mix test
mix credo
mix dialyzer

Roadmap (toward fuller Supervisor coverage)

  1. PATCH (and other methods) on the client layer
  2. Named function per documented endpoint, with @doc since: "<supervisor version>"
  3. Request/response types aligned to official JSON
  4. First-class remote options (uuid | deviceId | appId + method + data) on all calls
  5. Streaming helpers for journal / local logs
  6. Compatibility notes / tests keyed to minimum supervisor versions

Until then, use generic V1 / V2 accessors for routes without named wrappers—and check the device supervisor version before relying on newer fields.


License

MIT


Disclaimer

balena® and balenaOS® are trademarks of Balena Ltd. This project is not affiliated with or endorsed by Balena. The Supervisor HTTP API is defined and versioned by Balena; ExBalena is an independent Elixir client.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages