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:
- All three modes ship the full product. Telemetry, control, optimization, billing, safety rails — all unchanged across modes.
- The difference between Full and Config is the graph dashboard only.
- 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)
- In HA: Settings → Devices & Services → Add Integration → MQTT
- Broker: the Otonomo box's IP, port
1883, no auth (LAN-trusted) - 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
installer/install.sh— installer entry pointinstaller/local_ui/app.py— local-UI FastAPI app with mode awarenessinstaller/local_ui/templates/config_only.html— what Config-mode customers see at/installer/README.md— install-modes table for opscloud/app/onboarding.py—/onboarding?ui=...pickercloud/_claude_memory/feedback_no_third_party_charts.md— why we hand-roll SVG sparklines instead of Chart.js