Compare commits

...

4 Commits

Author SHA1 Message Date
009cde1619 fix(round): disable agent + storage-gadget services at boot (ARMv6 SIGILL + UDC conflict)
Two boot-time failures observed in the rpiz journal (Pi Zero W BCM2835,
ARMv6):

1. `secubox-eye-agent.service` crashes in an infinite loop with
   `status=4/ILL` (SIGILL) every ~10s. The agent's `pip install fastapi`
   pulls Pydantic v2 whose `pydantic_core` is Rust-built and has no
   ARMv6 wheel — pip serves an ARMv7 wheel that the BCM2835 cannot
   execute. Since v2.2.1 the dashboard is rendered by
   `secubox-fallback-display.service` (pure-Python Pillow) anyway, so
   the agent is redundant for normal operation. Install the unit file
   but don't enable it at boot — leaves an explicit one-line
   `systemctl enable` for ARMv7+ users who need the FastAPI endpoint.

2. `secubox-eye-gadget.service` (storage-only, U-Boot rescue) and
   `secubox-otg-gadget.service` (composite ECM+ACM, normal operation)
   both auto-start at boot and fight for the dwc2 UDC. journal shows
   eye-gadget claims it first (`Storage-only gadget started on
   20980000.usb`), then ~1 min later otg-gadget says "Gadget déjà
   configuré, redémarrage…" and tears it down to reconfigure — racy and
   indeterministic; the MOCHAbin sometimes sees no gadget at all.
   Install eye-gadget unit but don't enable it at boot — recovery boot
   recipe documented inline.

Net effect after this fix: rpiz boots → HyperPixel inits → fallback
display draws → composite ECM+ACM gadget appears on the MOCHAbin → DHCP
client takes a lease from secubox-eye-remote-dhcp.service.
2026-05-17 10:13:55 +02:00
8580af571d fix(round): fallback_manager finds the 6 brand icons (auth/wall/boot/mind/root/mesh)
The build script installs remote-ui/common/ at /var/www/common/ so the
real brand icons (auth-48.png … mesh-48.png) land at
/var/www/common/assets/icons/ on the image. fallback_manager.py however
only searched /usr/lib/secubox-eye/assets/icons/ (which holds the
round/-side menu placeholders) and so couldn't load any of the six
canonical module icons — the fallback radar's central icon stack came
out either blank or substituted with a placeholder.

Two-pronged fix:

1. fallback_manager.ICON_PATHS gains /var/www/common/assets/icons as the
   third lookup path, before the local round/assets/icons fallback. First
   existing file wins per icon name; the round-side dir keeps owning any
   icon name not present in common/.

2. build-eye-remote-image.sh now also copies common/assets/icons/*.png
   into /usr/lib/secubox-eye/assets/icons/ (with cp -n so the round/
   placeholders aren't overwritten when names collide — none do today
   anyway). Pure defense-in-depth so any consumer resolving icons via
   either of the two canonical paths finds them.

Issue reported: on the rpiz boot, the offline fallback radar showed
five of the six module icons correctly but one slot was wrong/empty.
2026-05-17 10:11:04 +02:00
31e094172c fix(round): use common/ brand-icon glyphs (recolored to text-primary) for the 6 root menu slices
Replaces the letter-in-circle placeholders shipped for DEVICES, SECUBOX,
LOCAL, NETWORK, SECURITY, EXIT with the corresponding SecuBox brand
icons from remote-ui/common/assets/icons/ — the same glyphs the fallback
connected dashboard already uses on its rotating cube. To keep contrast
on every slice color, the brand-icon alpha mask is preserved but the
fill is normalized to text-primary (#e8e6d9), matching the existing
label color in radial_renderer.

Mapping mirrors the fallback dashboard's cube order so the menu reads
as a logical continuation of the connected state:

  DEVICES  → auth   (CPU)
  SECUBOX  → wall   (Memory / Firewall)
  LOCAL    → boot   (Disk)
  NETWORK  → mind   (Load / Brain)
  SECURITY → root   (Temp / Root)
  EXIT     → mesh   (Network)

Drops the hand-drawn glyph generator (generate_root_icons.py) from the
previous commit — superseded by this approach.
2026-05-17 10:11:04 +02:00
d3c5905747 feat(round): real glyphs for the 6 root-menu icons
The radial dashboard's ROOT menu (DEVICES, SECUBOX, LOCAL, NETWORK,
SECURITY, EXIT) was rendering with the letter-in-circle placeholders
emitted by assets/icons/generate_menu_icons.py — never replaced with
actual designs, so each slice on the Pi screen showed a coloured disk
with a single capital letter (D/S/L/N/S/E) over the slice label.

Replace those 12 PNGs (22 + 48 each) with proper PIL-drawn vector
glyphs (white #e8e6d9, transparent background, 4x supersampled AA):

  devices   — tablet + phone overlay with home dot
  secubox   — isometric cube outline (brand cube)
  local     — house silhouette with door
  network   — globe with meridians
  security  — shield with embedded checkmark
  exit      — door frame + arrow pointing out

New generator script assets/icons/generate_root_icons.py is committed
alongside the PNGs so the design can be tweaked and re-emitted; the
existing generate_menu_icons.py still owns the remaining ~40
sub-menu icons (which remain placeholders for now — a separate
follow-up will design those properly).
2026-05-17 10:11:04 +02:00
14 changed files with 41 additions and 9 deletions

View File

@ -93,10 +93,15 @@ LOGO_PATHS = [
Path("/etc/secubox/eye-remote/assets/phoenix_logo.png"),
]
# Icon paths - module icons
# Icon paths - module icons.
# Order matters: first existing path wins per icon name. /var/www/common/
# holds the real brand icons (auth, wall, boot, mind, root, mesh) installed
# by build-eye-remote-image.sh; the local /usr/lib/secubox-eye/assets/icons/
# fallback path holds the round-specific placeholder set.
ICON_PATHS = [
Path("/tmp/assets/icons"),
Path("/etc/secubox/eye-remote/assets/icons"),
Path("/var/www/common/assets/icons"),
Path(__file__).parent.parent.parent.parent / "assets" / "icons",
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 241 B

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 400 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 677 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 B

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 410 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 521 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 383 B

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 530 B

After

Width:  |  Height:  |  Size: 826 B

View File

@ -650,9 +650,17 @@ mkdir -p "$ROOT_MNT/etc/systemd/system/dnsmasq.service.d"
cp "$SCRIPT_DIR/files/etc/systemd/system/dnsmasq.service.d/secubox-eye.conf" \
"$ROOT_MNT/etc/systemd/system/dnsmasq.service.d/"
# Enable new gadget service
ln -sf /etc/systemd/system/secubox-eye-gadget.service \
"$ROOT_MNT/etc/systemd/system/multi-user.target.wants/"
# secubox-eye-gadget is STORAGE-only mode for U-Boot rescue boot. Enabling
# it alongside the composite secubox-otg-gadget.service (ECM+ACM, enabled
# below) causes two services to fight for the UDC at boot: eye-gadget
# claims it first as mass-storage, then otg-gadget tears it down to
# reconfigure as composite — racy and indeterministic, the MOCHAbin
# sometimes sees no gadget at all. Install the unit but DO NOT enable it
# at boot. To enable U-Boot rescue mode manually:
# systemctl disable secubox-otg-gadget.service
# systemctl enable --now secubox-eye-gadget.service
# ln -sf /etc/systemd/system/secubox-eye-gadget.service \
# "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/"
# Copy framebuffer dashboard (Pi Zero W has no NEON, can't run Chromium)
log "Installing framebuffer dashboard..."
@ -684,18 +692,34 @@ if [[ -f "$SCRIPT_DIR/secubox-eye-agent.service" && -f "$SCRIPT_DIR/config.toml.
# Install agent service
cp "$SCRIPT_DIR/secubox-eye-agent.service" "$ROOT_MNT/etc/systemd/system/"
# Enable agent service via symlink (atomic, no chroot needed)
# The agent depends on Pydantic v2 (pydantic_core, Rust) which has no
# ARMv6 wheel — pip ships an ARMv7 wheel that crashes with SIGILL on
# the Pi Zero W BCM2835 (status=4/ILL, observed in journal).
# v2.2.1 design moved metrics rendering to secubox-fallback-display.service
# (pure-Python Pillow), so we install the unit file but DO NOT enable it
# at boot. To re-enable manually on an ARMv7+ board:
# systemctl enable --now secubox-eye-agent.service
mkdir -p "$ROOT_MNT/etc/systemd/system/multi-user.target.wants"
ln -sf /etc/systemd/system/secubox-eye-agent.service \
"$ROOT_MNT/etc/systemd/system/multi-user.target.wants/"
# ln -sf /etc/systemd/system/secubox-eye-agent.service \
# "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/"
# v2.2.0: Install menu system icons for radial menu
if [[ -d "$SCRIPT_DIR/assets/icons" ]]; then
log "Installing menu system icons..."
mkdir -p "$ROOT_MNT/usr/lib/secubox-eye/assets/icons"
cp "$SCRIPT_DIR/assets/icons"/*.png "$ROOT_MNT/usr/lib/secubox-eye/assets/icons/" 2>/dev/null || true
# Defense-in-depth: also drop the brand-icon PNGs (auth/wall/boot/mind/
# root/mesh) from remote-ui/common/assets/icons/ into the same dir so
# any consumer that resolves icons only via /usr/lib/secubox-eye/ finds
# them. fallback_manager.py ALSO searches /var/www/common/assets/icons/
# directly — this is just a redundant shipping path.
_COMMON_ICONS="$(dirname "$SCRIPT_DIR")/common/assets/icons"
if [[ -d "$_COMMON_ICONS" ]]; then
cp -n "$_COMMON_ICONS"/*.png \
"$ROOT_MNT/usr/lib/secubox-eye/assets/icons/" 2>/dev/null || true
fi
ICON_COUNT=$(ls "$ROOT_MNT/usr/lib/secubox-eye/assets/icons"/*.png 2>/dev/null | wc -l)
log "Installed $ICON_COUNT menu icons"
log "Installed $ICON_COUNT menu icons (round/ + common/ brand)"
fi
else
warn "Eye Agent files not found, skipping installation"
@ -766,7 +790,10 @@ ln -sf /etc/systemd/system/eye-firstboot-hostname.service "$ROOT_MNT/etc/systemd
ln -sf /etc/systemd/system/hyperpixel2r-init.service "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/" 2>/dev/null || true
# Eye Remote services
ln -sf /etc/systemd/system/secubox-eye-gadget.service "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/" 2>/dev/null || true
# secubox-eye-gadget (storage-only, U-Boot rescue) intentionally NOT enabled
# at boot — it conflicts with the composite secubox-otg-gadget.service.
# See the comment near line 653 for the manual-enable recipe.
# ln -sf /etc/systemd/system/secubox-eye-gadget.service "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/" 2>/dev/null || true
# v2.2.1: Use fallback-display instead of eye-agent (3D cube + rainbow rings, stable)
ln -sf /etc/systemd/system/secubox-fallback-display.service "$ROOT_MNT/etc/systemd/system/multi-user.target.wants/" 2>/dev/null || true
# NOTE: secubox-eye-agent is broken (import errors) - disabled pending fix