Skip to content

feat(install): generic-arm64 best-effort support (Armbian SBCs)#2879

Merged
vpetersson merged 9 commits into
masterfrom
worktree-jiggly-sauteeing-stonebraker
May 13, 2026
Merged

feat(install): generic-arm64 best-effort support (Armbian SBCs)#2879
vpetersson merged 9 commits into
masterfrom
worktree-jiggly-sauteeing-stonebraker

Conversation

@vpetersson
Copy link
Copy Markdown
Contributor

@vpetersson vpetersson commented May 12, 2026

Closes #2849 (Tier 1).

Summary

  • Adds arm64 as a recognised DEVICE_TYPE so the installer accepts any aarch64 host that isn't a Raspberry Pi (Armbian on Rock Pi, Orange Pi, Banana Pi and similar).
  • Wires the same Qt6 + cage + wayland viewer path that x86 already uses, with va-driver-all deliberately omitted (Rockchip / Allwinner / Amlogic mainline hwdec is V4L2 M2M / request API, not VAAPI — mesa-va-drivers would be dead weight on these SoCs; per-SoC hwdec is a Tier-2 follow-up).
  • CI matrix + mirror-latest-tags publish latest-arm64 alongside the existing per-board tags, so the next merge gives normal MODE=pull installs a published image to land on.

Notable code paths

  • bin/install.sh::set_device_type and bin/upgrade_containers.sh get an aarch64 fallback branch.
  • bin/install.sh::run_ansible_playbook extends the --skip-tags raspberry-pi skip to arm64 (the Pi boot-partition tweaks don't apply on Armbian).
  • ansible/site.yml validated-set + docker_arch_by_device_type map gain arm64.
  • docker-buildx-plugin added to the ansible apt-install list — needed for MODE=build Dockerfiles that use --platform=$BUILDPLATFORM (legacy builder dies on the very first FROM); harmless on pull-mode boards.
  • tools/image_builder gets a arm64 build target; viewer Dockerfile / runtime apt list / start_viewer.sh / media_player.py treat arm64 the same as x86 (no /dev/fb0, cage compositor, mpv --vo=gpu --gpu-context=wayland). MediaPlayerProxy picks MPV via the DEVICE_TYPE env override that pi4-64 already uses, since device_helper.get_device_type() falls back to 'pi1' on any non-Pi aarch64 host.
  • host_agent::SUPPORTED_INTERFACES gains the end prefix so Rockchip GMACs (which surface as end0 under systemd predictable naming) show up in the splash page's IP list instead of leaving it stuck on "Detecting network…".

Drive-by fixes uncovered by this work

  • anthias-host-agent.service was pinned to ~/installer_venv/bin/python, which became an ephemeral tmpdir in fix(install): tmpdir installer_venv on Bookworm; drop getmac dep #2843 — service failed 203/EXEC on every install since. Split into a persistent ~/.anthias-venv synced by a new ansible task before the unit is enabled.
  • bin/install.sh::install_packages ran sed -i ... /etc/apt/sources.list unconditionally on non-x86; that file doesn't exist on Armbian (deb822 layout), so set -e killed the installer. Now guarded by [ -f /etc/apt/sources.list ].

Docs

  • README + marketing-site supported-hardware table + FAQ get a plain-language "Yes, on a best-effort basis" section: which SoCs are known to work well (RK3399 / RK35xx / Allwinner H6 / Amlogic GXBB-GXL-GXM / S905X3), which to avoid (Allwinner H616 / H618), and that video falls back to software decode.

Test plan

  • Fresh install on Rock Pi 4B (Armbian community trixie, RK3399, 1GB RAM) via build-on-device. Ansible playbook PLAY RECAP: ok=43 failed=0.
  • Web UI reachable at http://<ip>/ (HTTP 200).
  • /api/v2/network/ip-addresses returns ["192.168.200.155"] once host-agent service starts (was failing pre-fix).
  • Image, H.264 1080p60, H.265 1080p60, and webpage assets all cycle cleanly through the viewer (load avg 0.42 1-min during steady-state cycling).
  • mpv pure-decode benchmark on the device: 0 dropped frames, sustained 60 vfps over the full 60s of both BBB clips.
  • Existing Pi / x86 device-type paths unaffected (same install.sh branches, same ansible tags, same image tags).
  • CI matrix run pushes latest-arm64 tags successfully (verified on next push to master).

🤖 Generated with Claude Code

@vpetersson vpetersson requested a review from a team as a code owner May 12, 2026 19:45
@vpetersson vpetersson requested a review from Copilot May 12, 2026 19:46
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends Anthias’ installer, image build pipeline, and viewer runtime wiring to support a best-effort generic-arm64 device type for non-Raspberry-Pi aarch64 SBCs (e.g., Armbian on Rock Pi / Orange Pi / Banana Pi), while also fixing a host-agent systemd venv regression and improving network interface detection on SBCs.

Changes:

  • Add generic-arm64 device detection across install/upgrade scripts, Ansible validation/mapping, and CI image publishing (latest-generic-arm64).
  • Reuse the existing x86 Qt6 + cage + Wayland mpv viewer path for generic-arm64 (omitting VAAPI drivers).
  • Fix host-agent systemd ExecStart venv path by provisioning a persistent ~/.anthias-venv and expand host-agent NIC prefix detection (end*).

Reviewed changes

Copilot reviewed 16 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
website/layouts/_default/get-started.html Update supported-hardware copy/table and add best-effort ARM SBC note.
website/data/faq.yaml Add/expand FAQ entries describing generic ARM SBC support and limitations.
website/content/get-started.md Update page metadata description to include generic ARM SBCs.
tools/image_builder/utils.py Add generic-arm64 build target and align viewer deps/wiring with x86 (cage/Wayland).
tools/image_builder/constants.py Allow generic-arm64 as a build target option.
tests/test_media_player.py Add a MediaPlayerProxy selection test for generic-arm64.
src/anthias_viewer/media_player.py Route generic-arm64 to mpv and Wayland VO like x86; use env override to avoid pi1 fallback misrouting.
src/anthias_host_agent/__main__.py Include end* NIC prefix so SBC Ethernet interfaces are detected for IP display.
README.md Document best-effort generic ARM SBC support and expectations.
docker/Dockerfile.viewer.j2 Use Wayland Qt platform for generic-arm64 same as x86.
bin/upgrade_containers.sh Add aarch64 fallback to generic-arm64 and strip Pi-only /dev/vchiq devices for it.
bin/start_viewer.sh Run viewer under cage for generic-arm64 same as x86.
bin/install.sh Add generic-arm64 support, skip Pi-only Ansible tags, guard sources.list rewrite, and only call main when executed directly.
ansible/site.yml Validate DEVICE_TYPE=generic-arm64.
ansible/roles/system/tasks/docker.yml Map generic-arm64 to arm64 and install docker-buildx-plugin.
ansible/roles/anthias/templates/anthias-host-agent.service Point host-agent ExecStart to the new persistent venv.
ansible/roles/anthias/tasks/main.yml Create a persistent ~/.anthias-venv via uv sync for host-managed services.
.github/workflows/scripts/mirror-latest-tags.sh Mirror latest-generic-arm64 tags alongside existing boards.
.github/workflows/docker-build.yaml Add generic-arm64 to the docker-build matrix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread ansible/roles/anthias/tasks/main.yml Outdated
Comment thread ansible/roles/system/tasks/docker.yml Outdated
Comment thread src/anthias_viewer/media_player.py Outdated
Comment thread tests/test_media_player.py
vpetersson and others added 3 commits May 12, 2026 19:56
… Orange Pi, …)

Wires up a `generic-arm64` device_type so the installer recognises any
aarch64 host that isn't a Raspberry Pi and runs the same Anthias stack
on it. Closes #2849 (Tier 1).

* `bin/install.sh::set_device_type` + `bin/upgrade_containers.sh` get
  an `aarch64` fallback branch, INTRO_MESSAGE / unsupported-message
  copy refreshed, raspberry-pi-tagged ansible tasks skipped on
  generic-arm64 (same as x86), vchiq strip extended.
* ansible: validated set in `site.yml`, `docker_arch_by_device_type`
  gains `generic-arm64: arm64`. `docker-buildx-plugin` added to the
  apt-install list — required for MODE=build with `--platform=`
  Dockerfiles, harmless on pull-mode boards. Pre-existing host_agent
  service unit hardcoded `~/installer_venv/bin/python` (an ephemeral
  tmpdir post-#2843); split into a persistent `~/.anthias-venv` that
  ansible syncs before installing the unit.
* image_builder: `generic-arm64` build target, Qt6 + cage + wayland
  like x86; `va-driver-all` deliberately *not* shipped — Rockchip /
  Allwinner / Amlogic mainline hwdec goes through V4L2 M2M /
  request API, not VAAPI, so mesa-va-drivers would be dead weight.
* viewer: `start_viewer.sh` reuses the x86 cage path for
  generic-arm64; `media_player.py` routes generic-arm64 to MPV (the
  `device_helper.get_device_type()` fallback returns 'pi1' on
  non-Pi aarch64 hosts, so the proxy needs the DEVICE_TYPE env
  override that pi4-64 already uses). New test added.
* host_agent: `SUPPORTED_INTERFACES` gains `end` prefix —
  Rockchip GMAC etc. surface as `end0` on systemd predictable
  naming, which was previously filtered out, leaving the splash
  page stuck on "Detecting network…".
* CI: docker-build matrix + mirror-latest-tags publish
  `latest-generic-arm64` alongside the existing per-board tags.
* Docs: README, marketing site supported-hardware table, and FAQ
  get a plain-language "Yes, on a best-effort basis" entry that
  spells out the software-decode trade-off, the SoCs known to work
  well (RK3399 / RK35xx / Allwinner H6 / Amlogic GXBB-GXL-GXM /
  S905X3), and the boards to avoid (Allwinner H616 / H618). Per-SoC
  hardware decode (`rkmpp`, `cedrus`, `meson-vdec`) is the planned
  Tier-2 follow-up.

Validated end-to-end on a Rock Pi 4B (Armbian trixie, RK3399, 1GB
RAM) via build-on-device: install completes, web UI reachable, all
four asset types (image, H.264 1080p60, H.265 1080p60, webpage)
cycle through the viewer cleanly, mpv pure-decode benchmark shows
0 dropped frames over the full 60s of each clip.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… task

ansible-lint's partial-become rule fires on `become_user:` without a
matching `become:` at the same level, even when the play-level become
already covers it. Explicit pairing keeps lint quiet without changing
runtime behaviour.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- ansible: drop `creates:` guard on the runtime venv sync — `uv sync`
  is idempotent (sub-second resolver check when nothing changed), so
  re-running unconditionally means dependency updates from a
  pyproject.toml / uv.lock change actually land on upgrade instead of
  silently skipping. Idempotency surfaced via `changed_when` keyed on
  uv's `+/-/~` package-action prefix so steady-state runs stay `ok`.
- ansible: rework docker-buildx-plugin comment to justify the
  install on its own merits (any MODE=build run needs it because of
  `FROM --platform=$BUILDPLATFORM` in Dockerfiles) rather than tying
  it to generic-arm64 lacking published tags — that explanation
  becomes stale the moment this PR merges and CI publishes them.
- viewer: `get_alsa_audio_device()` short-circuits on
  `DEVICE_TYPE=generic-arm64` before the Pi-firmware dispatch, since
  the Rock Pi / Orange Pi / Banana Pi class of board has none of the
  `vc4hdmi*` or `Headphones` ALSA cards. Defers to ALSA's `default`
  device; operators with a non-standard sink can override via
  `~/.asoundrc` (already bind-mounted into the viewer container).
- tests: new assertions that generic-arm64 routes mpv through
  `--vo=gpu --gpu-context=wayland` and `--audio-device=alsa/default`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vpetersson vpetersson force-pushed the worktree-jiggly-sauteeing-stonebraker branch from d7ec3af to 6a961f2 Compare May 12, 2026 19:57
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 19 changed files in this pull request and generated 1 comment.

Comment thread website/layouts/_default/get-started.html Outdated
…ware copy

Copilot flagged the previous wording — "running Raspberry Pi OS, Debian, or
Armbian (Trixie or Bookworm)" — as misleading: the parenthetical reads as
if Raspberry Pi OS and Armbian are themselves "Trixie or Bookworm", but
those are Debian codenames, and Armbian builds can also be Ubuntu-based.
Split the sentence so the codenames are tied explicitly to Debian.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 19 changed files in this pull request and generated 1 comment.

Comment thread ansible/roles/system/tasks/docker.yml Outdated
Copilot caught that the `is_raspberry_pi` helper in docker.yml was
defined as `ansible_architecture in ['aarch64', 'armv7l', 'armv6l']`,
which is also true on generic-arm64 (Rock Pi / Orange Pi / …). That
silently applied the Pi-only `gpio` group to non-Pi SBCs.

device_type is the authoritative discriminator and is validated
upstream in ansible/site.yml's pre_tasks, so use it directly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review feedback: `generic-arm64` was the original working name for
the new aarch64 non-Pi fallback. `arm64` is shorter and parallels `x86`
— both are architecture-generic device_types that catch any host
without a board-specific image, sitting alongside the per-board labels
(pi2 / pi3 / pi4-64 / pi5). User-facing prose still says "generic
64-bit ARM" or "Armbian on Rock Pi / Orange Pi / …" for context.

Mechanical s/generic-arm64/arm64/ across install scripts, ansible,
image_builder, viewer / start_viewer, host_agent, tests, CI matrix,
mirror-latest-tags, Dockerfile.viewer.j2, README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 19 changed files in this pull request and generated no new comments.

* Master's #2881 (e2e-test findings) added an `installer_venv` persistent
  venv provisioned by `bin/install.sh::provision_host_agent_venv` and
  kept the systemd unit ExecStart pointed at that stable path. Drops the
  duplicate ansible-side `.anthias-venv` task and reverts the
  unit-template path I'd introduced — master's approach is upstream
  and avoids rewriting the unit path on devices installed pre-refactor.
* Master's #2880 replaced the gum UI with whiptail. The auto-merge took
  whiptail's wiring; my arm64-aware INTRO_MESSAGE / set_device_type /
  Pi-tag-skip branches survived alongside it.
* Master's #2878 viewer locale changes auto-merged with my arm64
  start_viewer.sh conditional.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 17 changed files in this pull request and generated 2 comments.

Comment thread .github/workflows/docker-build.yaml
Comment thread .github/workflows/scripts/mirror-latest-tags.sh
- viewer: get_alsa_audio_device's arm64 short-circuit now logs the
  registered ALSA cards (from /proc/asound/cards — aplay isn't in
  the viewer image) once per process when DEVICE_TYPE=arm64, so an
  operator reporting "no HDMI audio" carries enough breadcrumbs in
  journalctl alone to pick the right ~/.asoundrc override.
- ansible: rewrite the docker-buildx-plugin size claim — 15 MB
  download / 67 MB extracted, from the deb metadata on arm64.
- viewer: MediaPlayerProxy.get_instance comment block split into a
  two-bullet rationale, calling out the pi4-64 and arm64 cases
  separately so a future reader doesn't mistake the lead sentence
  for "pi4-64-only".
- install.sh / upgrade_containers.sh: spell out that the aarch64
  catch-all in set_device_type is intentional — a future Pi model
  whose model string drifts past the regexes lands here too,
  trading software decode + no Pi-boot tweaks for a louder fail.
- README + FAQ: tighten the Plymouth caveat from "few seconds of
  black" to "kernel boot log scrolls until the viewer takes over",
  which is what actually happens on most U-Boot ARM SBCs.
- ansible: rename the docker.yml var from `is_raspberry_pi` to
  `device_is_pi` now that it's derived from device_type rather
  than `ansible_architecture`, so the name matches what it does.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 17 changed files in this pull request and generated 3 comments.

Comment thread website/layouts/_default/get-started.html Outdated
Comment thread README.md
Comment thread website/data/faq.yaml Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 17 changed files in this pull request and generated no new comments.

Copilot flagged that "Armbian" in the new docs is ambiguous —
Armbian builds come in both Debian-based (Bookworm/Trixie) and
Ubuntu-based (Jammy/Noble) flavours. The installer's ansible role
wires Docker's apt repo under
download.docker.com/linux/debian/{{ ansible_distribution_release }},
which 404s on the Ubuntu codenames, so an Ubuntu-Armbian user
following the current docs would hit a broken install at the very
first `apt update`.

Narrowing the wording in README, the marketing site's
supported-hardware blurb, and the FAQ to "Debian-based Armbian" so
users pick the right image. Extending the installer/playbook to
handle Ubuntu-based Armbian is a separate follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vpetersson vpetersson requested a review from Copilot May 13, 2026 08:59
@sonarqubecloud
Copy link
Copy Markdown

@vpetersson vpetersson merged commit 7f8bbe4 into master May 13, 2026
15 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 17 changed files in this pull request and generated 1 comment.

<div class="max-w-3xl mx-auto">
<h2 id="supported-hardware" class="text-2xl font-bold">Supported hardware</h2>
<p class="text-zinc-500 mt-2">Anthias runs on Raspberry Pi single-board computers and 64-bit x86 PCs running Raspberry Pi OS or Debian (Trixie or Bookworm).</p>
<p class="text-zinc-500 mt-2">Anthias runs on Raspberry Pi single-board computers, 64-bit x86 PCs, and 64-bit ARM single-board computers (Rock Pi, Orange Pi, Banana Pi and similar via Armbian). Supported on Raspberry Pi OS, Debian (Trixie or Bookworm), and the corresponding Armbian builds.</p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Armbian / generic 64-bit ARM SBCs (Orange Pi, Rock Pi, Banana Pi, …)

2 participants