Otonomo home-energy intelligence

Otonomo — install modes and integration paths (detailed reference)

Audience. Engineering, support, technical partners. Last updated. 2026-05-25.

This document explains the three install modes a customer can pick when installing Otonomo on their own hardware, what each mode contains, what it leaves out, how integration with Home Assistant works in each, and the hardware / OS / cloud assumptions behind all of it.


1. What gets installed (the invariant)

Every Otonomo install — regardless of mode — places three systemd services on the customer's Linux box, plus a small Python venv at /opt/otonomo/venv and a config file at /etc/otonomo/env.

Service Role Mode-independent?
otonomo-publisher Polls drivers, publishes telemetry to local MQTT + cloud MQTT ✅ always running
otonomo-cmd-subscriber Subscribes to cloud command topic, dispatches to driver execute() ✅ always running
otonomo-local-ui LAN web UI on port 8080 ⚠ mode-dependent
mosquitto (system package) Local MQTT broker on 127.0.0.1:1883 ✅ always running

The first three together form the agent. They are independent of the local web UI. Whichever install mode is picked, telemetry flows to our cloud and cloud commands flow back. That is non-negotiable.

The install mode only changes what runs at port 8080 on the customer's own box.


2. Port 8080 hosts two distinct surfaces

This is the key concept that disambiguates the modes:

Surface Purpose Audience
Graph dashboard — overview, per-device pages, sparklines, 6h ring buffer, JSON time-series API Watching data The customer's eyeballs
Drivers wizard — catalog, pip install, instance create/edit/remove, config-form rendering Setting up hardware The customer during first-time install and on rare hardware changes

The install mode picks which of these two surfaces is exposed.


3. The three install modes

3.1 Full (default)

Port 8080: ┌─ Graph dashboard ─────────┐
           │  /                        │
           │  /device/heating          │
           │  /device/battery          │
           │  /device/solar  /grid /ev │
           │  /api/series   /api/state │
           └───────────────────────────┘
           ┌─ Drivers wizard ──────────┐
           │  /drivers                 │
           │  /drivers/configure/<x>   │
           │  /drivers/install/<x>     │
           └───────────────────────────┘
           Plus an in-process MQTT tap
           subscribing to local broker,
           maintaining a 6h ring buffer
           in RAM (~1.2 MB at 50 metrics).

Best for. Customers who want a local pane of glass during the free trial, or who want a fallback view when the cloud is unreachable. The default in the onboarding wizard.

3.2 Config-only

Port 8080: ┌─ Drivers wizard ──────────┐  ← still on
           │  /drivers                 │
           │  /drivers/configure/<x>   │
           │  /drivers/install/<x>     │
           └───────────────────────────┘
                Graph dashboard turned off:
                • `/` shows a status page
                • `/device/*` → 303 to /drivers
                • `/api/series` → HTTP 410 (Gone)
                • `/api/state`  → HTTP 410 (Gone)
                MQTT tap NOT instantiated.
                Ring buffer NOT allocated.

Best for. Customers who will visualise their data in Home Assistant (or in our cloud dashboard) but still want the friendly driver-setup wizard. The wizard is a setup tool, not a display tool — they need it to configure their hardware once and on rare changes.

What's saved vs Full. ~1.2 MB RAM, one MQTT subscriber thread, one broker connection. Symbolic on a modern box; principled on a Pi Zero.

3.3 None

Port 8080: closed. Service is `systemctl mask`ed so a future
           daemon-reload or third-party hook can't bring it back.

Drivers managed via:
  • SSH to the box
  • Edit /etc/otonomo/site_manifest.yaml
  • systemctl kill -s SIGHUP otonomo-publisher.service

Best for. Power users / sysadmins who prefer config-as-code in YAML, multi-box deployments where one cloud dashboard manages many boxes, or minimal-attack-surface paranoia (no port 8080 = no LAN exposure of the agent at all).


4. Component matrix

Component Full Config None
otonomo-publisher
otonomo-cmd-subscriber
Local mosquitto broker
otonomo-local-ui service ✅ (trimmed) ❌ masked
Port 8080 open on LAN
Graph dashboard pages
6h in-memory ring buffer
Local MQTT tap (subscriber inside local-UI)
Hand-rolled SVG sparklines
/api/series, /api/state JSON HTTP 410 n/a
Drivers wizard (catalog, install, configure)
/healthz
Telemetry to Otonomo cloud
Cloud dashboard (app.otonomo.be/?box=...)
Cloud orchestrators (active mode)
Cmd path cloud → driver → hardware
Cloud-watchdog safe-mode fallback
Approx extra RAM vs base ~1.5 MB base base

Three things to notice from this table:

  1. All three modes ship the full product. Telemetry, control, optimization, billing, safety rails — all unchanged across modes.
  2. The difference between Full and Config is the graph dashboard only.
  3. The difference between Config and None is the drivers wizard.

5. Home Assistant integration

HA integration is identical across all three modes: HA connects to the local MQTT broker on the Otonomo box.

Drivers ──> mosquitto on box (127.0.0.1:1883)
                  │
                  ├── Otonomo local-UI tap   (Full mode only)
                  ├── Home Assistant         (all modes, optional)
                  └── (fan-out to cloud)     (always)

Setup (3 steps, ~2 minutes)

  1. In HA: Settings → Devices & Services → Add Integration → MQTT
  2. Broker: the Otonomo box's IP, port 1883, no auth (LAN-trusted)
  3. Subscribe to hems/<box_id>/telemetry/#

Every metric (dhw.temp_c, battery.soc_pct, pv.power_w, …) becomes an MQTT message HA can turn into entities, charts, automations.

Why MQTT and not /api/state?

/api/state is a JSON projection of the local-UI's 6h ring buffer. That buffer exists only in Full mode. In Config and None mode it is not allocated — and /api/state would have nothing to return.

MQTT is the right integration anyway: push-based, lower latency, same source of truth as our cloud ingester. We recommend it even for Full-mode customers.

Future (planned ~Q3 2026): official HACS integration

One-click install. Customer pastes box-IP + box-id. The integration: - Subscribes to the box's MQTT topics - Creates HA entities from our canonical schema (sensor.otonomo_*) - Surfaces per-capability override switches that map to our customer-override mechanism in active mode

Once it ships, Config and None modes become functionally indistinguishable for HA users — the wizard moves to the cloud, the agent on their box becomes a pure background process.


6. Hardware, OS, and cloud — what actually works

6.1 Operating system

OS family Status
Debian 12 / Ubuntu 22.04+ / Raspberry Pi OS Bookworm ✅ supported (install.sh tests for apt-get)
Other apt-based (Mint, PopOS, Armbian) ✅ works in practice, untested
Fedora / RHEL / Rocky / Alma ⚠ install.sh exits — customer needs to install python3, mosquitto, curl, ca-certificates manually, then run the activator
Arch / openSUSE ⚠ same as Fedora
NixOS ⚠ would need a flake; not v0.1
Alpine ⚠ uses apk and OpenRC instead of systemd; install.sh refuses
Windows ❌ no
macOS ❌ no (no systemd)

Practical answer. For the founding-100 we target Debian / Ubuntu / Raspberry Pi OS only. Other distros are a "we'll help you over email" proposition until M3. The agent code itself is pure Python + paho-mqtt + FastAPI — it will run on anything Linux. The friction is install.sh hardcoding apt-get and systemctl.

6.2 Hardware

Box Status
Raspberry Pi 4 / 5 (1+ GB RAM) ✅ recommended sweet spot
Raspberry Pi Zero 2 W (512 MB) ✅ works; this is our shipping SKU's hardware tier
Orange Pi Zero 3 ✅ this is our SKU; reference target
Intel NUC / mini-PC (any age) ✅ overkill but fine
Old laptop running Linux ✅ works — needs to stay always-on
Cloud VPS (Hetzner / Scaleway / AWS …) ⚠ see §6.3 below — depends entirely on which drivers
Synology / QNAP NAS Docker ⚠ untested but should work
Truenas / Unraid ⚠ untested
Pi Zero W (original, 512 MB ARMv6) ❌ Python 3.11+ unsupported on ARMv6

Minimum spec realistically: 512 MB RAM, Python 3.11+, systemd.

6.3 Cloud VPS — the wrinkle

Yes, the agent software runs perfectly on a cloud VPS. The drivers are the question.

Driver class Works on a cloud VPS?
Cloud-API drivers (Aquarea Smart Cloud, Easee, Tado, etc.) ✅ yes — they talk to the vendor's cloud, location doesn't matter
Modbus TCP drivers (SolarEdge, Huawei, Marstek, etc. over LAN) ❌ no — VPS isn't on the customer's LAN; can't see the inverter
Local MQTT drivers (Shelly, Heishamon, …) ❌ no — same reason
USB-serial drivers (Vaillant via USB-eBUS, BlueCorner EV via USB-RS485) ❌ no — VPS has no USB ports to the customer's hardware
Cloud-API EV chargers (Easee, Wallbox, go-e cloud) ✅ yes
Cloud-API heat pumps (Aquarea Smart Cloud, LG ThinQ) ✅ yes

Honest summary. A cloud VPS works as an Otonomo box only if every device the customer has is reachable through a vendor cloud API. If any device is LAN- or USB-bound, the agent must run on a box on the customer's LAN. That's not an Otonomo limitation; it's physics.

For most real customers, a Pi or NUC on their LAN is mandatory because they have at least one Modbus / USB device. Cloud VPS is a nice option for the all-cloud-API edge case (e.g. a customer who only has an Aquarea + an Easee).

6.4 Containers

Docker / Podman are supported in principle but not packaged in v0.1. The blockers are: mounting /dev/ttyUSB* for USB drivers, host networking for mDNS discovery, systemd-in-container complications. We plan a docker-compose.yml in M2 for the all-network-driver case.


7. How to pick (decision guide)

Customer flow:

  Does the customer want a *local* pane of glass?
  │
  ├── YES → Full
  │
  └── NO → Will they use Home Assistant or just the cloud dashboard?
           │
           ├── HA / cloud, but wants the friendly setup wizard → Config
           │
           └── Power user, comfortable with YAML + SSH      → None

Default in the onboarding picker is Full. Reasonable for ~70% of the founding-100 cohort. Config and None are honest options for the remaining 30% (HA-heavy users + sysadmin types).


8. Switching modes after install

Re-run the one-liner with a different OTONOMO_LOCAL_UI value. The installer is idempotent: it detects the existing enrollment, doesn't re-issue a token, just rewrites LOCAL_UI_MODE in /etc/otonomo/env and re-applies the systemd state (enable + start, or disable + mask).

# Add the graph dashboard back to a Config-only install
curl -fsSL https://app.otonomo.be/install.sh \
  | OTONOMO_TOKEN=<your-token> OTONOMO_LOCAL_UI=full bash

# Drop to None
curl -fsSL https://app.otonomo.be/install.sh \
  | OTONOMO_TOKEN=<your-token> OTONOMO_LOCAL_UI=off bash

Configured drivers, the site manifest, the box's identity — all preserved across mode switches. The customer loses nothing.


9. What changes in active mode (€3/mo)

Active vs observe is orthogonal to the install mode. A customer in None mode can be in active mode; a customer in Full mode can be in observe. The two axes don't interact.

Axis Values
Install mode (sets local UI surface) Full / Config / None
Billing mode (sets whether cloud writes) Observe (free) / Active (€3/mo, per-capability opt-in)

A box in observe mode receives no cloud commands — the otonomo-cmd-subscriber still runs but the cloud doesn't publish anything for it to consume. Customer flips to active at app.otonomo.be/account/control, opt-in per capability, override anytime in HA via the cmd contract.


10. References