Files
Panama/docs/superpowers/specs/2026-08-17-home-accessories-customization-design.md
T
Gabriel Brown d96863b687 Convert British spellings to American across the repo
colour -> color, behaviour -> behavior, centre -> center, favourite ->
favorite, and about twenty other pairs, applied consistently across
comments, docs, error/UI copy, and a handful of QML identifiers that
used the British spelling as their actual name: SystemSettings'
serialiseValue/serialiseTable/normaliseGradient, Displays'
normaliseModes, Wallpaper's normalisePolicy, SettingsBackup's
serialiseHomeState, DateTime's ntpSynchronised property, Clipboard's
_normalise helper, and ShortcutCapture's cancelled signal (with its
onCancelled handler in ShortcutsPage.qml). Every call site and the two
tests that assert on the literal source text (settings-ownership and
settings-backup-live contracts) were updated in lockstep.

Left untouched: config/dot/espanso/match/packages/misspell-en/ is a
vendored third-party autocorrect dictionary -- its entries are typo
corrections, not our prose, and rewriting them would fight the
package's own purpose (and any future re-sync from upstream).

The already-American `favorites` property (Home page pinned
accessories) was never actually misspelled -- only nearby comments and
error strings said "favourites" -- so no data migration was needed
there.

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
2026-08-19 08:07:55 -04:00

12 KiB
Raw Blame History

Panama Home accessories customization design

Summary

Panama will turn the existing Home Assistant card into the approved A · Accessory shelf: a two-column grid of larger light controls with an always-visible brightness slider on every tile. Panama Settings will gain a first-class Home & Phone page where the user can discover all Home Assistant lights, choose which ones appear, reorder them, and assign concise Panama-only aliases.

The Phone card will add Messages, which opens the installed BlueBubbles desktop application. Messages remains available when KDE Connect is asleep because it is a local application handoff rather than a KDE Connect action.

Goals

  • Discover every Home Assistant light instead of limiting Panama to the old GNOME extension selection.
  • Let the user choose any number of lights, order them, and give them readable local names without changing Home Assistant itself.
  • Show the first four selected lights in Control Center's resting state and all selected lights in its expanded state.
  • Make brightness directly adjustable on every visible light tile.
  • Preserve quick on/off control, stale-state handling, and per-light failure isolation.
  • Add a Messages action that opens BlueBubbles from the Phone card.
  • Keep credentials, Home Assistant response bodies, and private preferences out of Git and logs.

Non-goals

  • Panama will not rename Home Assistant entities or friendly names globally.
  • This release will not add color, color-temperature, scenes, automations, rooms, dashboards, or non-light domains.
  • Panama will not send or read messages itself. BlueBubbles remains the complete messaging client.
  • Panama will not make BlueBubbles availability depend on KDE Connect or the iPhone's local-network reachability.
  • Panama will not continuously send brightness updates while the pointer is moving.

Verified system state

The live Home Assistant instance currently exposes 22 light entities. All 22 advertise a brightness-capable color mode. The current compatibility selection contains seven lights and omits the available Living Room group. Several source friendly names begin with Generic Zigbee Coordinator (EZSP), which is why Panama needs local aliases rather than additional truncation rules in the Control Center.

BlueBubbles is installed as the Flatpak desktop application app.bluebubbles.BlueBubbles.

Control Center interaction

Accessory shelf

The resting Home section uses a two-column, two-row grid. Each selected light tile contains:

  • a bulb power control;
  • the Panama alias, falling back to the Home Assistant friendly name;
  • On, Off, Unavailable, or a concise busy/error state;
  • the confirmed brightness percentage; and
  • a full-width amber brightness slider.

The first four selected lights appear in the resting grid. The existing N accessories action expands the Home section to a scrollable two-column grid of every selected light in preference order. A Manage in Settings row at the end opens Panama Settings directly to Home & Phone.

The tile body and bulb toggle power, except for the slider's own hit area. Dragging a slider updates only its visual preview. Releasing it sends one Home Assistant request. A value from 1100 calls light.turn_on with brightness_pct; zero calls light.turn_off. Dragging an off light above zero turns it on at the chosen brightness. This avoids network chatter and makes the final value deterministic.

Brightness displayed in Panama is derived from Home Assistant's 0255 value and rounded to a percentage. An off light whose current state has no brightness attribute displays zero. A normal power toggle lets Home Assistant restore its own previous brightness.

Only the affected light becomes busy. A successful action refreshes the catalog and remains globally quiet. A failed action restores the last confirmed value and shows a concise inline error on that tile; it does not make unrelated lights stale or emit a global toast.

Phone Messages action

The Phone action grid becomes four equal controls: Send File, Clipboard, Ring, and Messages. The first three retain their capability and reachability checks. Messages is enabled whenever BlueBubbles is installed, even if the phone is not nearby, and launches the allow-listed desktop application without a shell.

If BlueBubbles is unavailable, the Messages action is visibly disabled and the Phone detail section offers a plain BlueBubbles is not installed explanation. Opening BlueBubbles is globally quiet.

Panama Settings

Home & Phone page

Panama Settings gains a Home & Phone sidebar destination between Network & Devices and Desktop & Dock. Its page contains three cards.

  1. Home Assistant shows connection health, discovered-light count, Refresh, and Open Home Assistant.
  2. Control Center favorites shows selected accessories as a two-column card shelf. Each item exposes a drag handle, editable alias, source friendly name, and Remove action. Dragging reorders the list; the first four are explicitly marked as the resting Control Center shelf.
  3. Available lights is a searchable list of the remaining discovered lights. Add appends a light to the selected list. Source names are always visible here so similarly named physical devices remain distinguishable.

A short Phone continuity row reports that Messages opens BlueBubbles and provides an Open action. There is no redundant enable switch: if BlueBubbles is installed, the button is useful.

Changes save automatically after a short debounce. Alias input is trimmed; an empty alias falls back to the source friendly name. Duplicate aliases are allowed because households can legitimately contain similarly named lights. Selection may be empty, in which case Control Center shows a setup row that opens this page.

Persistence and migration

Add config/HomePreferences.qml as the durable owner of selected entity IDs, order, aliases, and an initialization marker. It uses an atomically written JSON adapter under Quickshell's per-shell state directory, beside the existing Panama Settings preferences. The file contains no token, URL, or Home Assistant response data.

On first launch only, Panama seeds the preference order from the existing GNOME-extension-compatible selection so the current Control Center does not reset. After initialization, an intentionally empty selection remains empty and is never reseeded. New Home Assistant entities appear only in Available lights; Panama does not silently add them to Control Center.

Aliases affect Panama only. Home Assistant's current friendly name is retained as sourceName and shown in Settings. If a selected entity disappears from the catalog, its preference remains in place as unavailable until the user removes it, preventing temporary Home Assistant outages from destroying configuration.

Home Assistant boundary

Extend panama-home-assistant with these normalized interfaces:

  • catalog returns every light.* entity with id, sourceName, state, available, active, dimmable, and brightnessPct;
  • brightness ENTITY_ID PERCENT validates a 0100 integer and calls the appropriate light service; and
  • the existing toggle ENTITY_ID remains the on/off action.

The helper authorizes actions against the current discovered light catalog, not against arbitrary entity IDs supplied by QML. It never returns unrelated Home Assistant domains or arbitrary attributes. Action requests use homeassistant.toggle, light.turn_on, and light.turn_off with an exact entity ID and, when relevant, brightness_pct.

The existing URL/token precedence remains unchanged: private Panama environment values first, then the GNOME extension URL and Secret Service token. The legacy entity list is used only for first-run preference migration.

services/HomeAssistant.qml owns the live catalog, resolves it against HomePreferences, exposes ordered selected entities and the first four shelf items, and tracks per-entity pending values and errors. Settings and Control Center consume this one service rather than maintaining separate copies.

BlueBubbles boundary

Extend SystemSettings.openApplication() with an allow-listed bluebubbles entry that launches flatpak run app.bluebubbles.BlueBubbles as separate arguments. Add a read-only bluebubblesAvailable property based on the installed desktop application or Flatpak metadata. PhoneControls and the Settings page consume those interfaces; neither constructs a command string.

Failure behavior

  • Home Assistant unreachable: retain the last catalog and selected states, mark them stale, and offer Retry.
  • Authentication rejected: show Authentication required without exposing the response body.
  • Catalog contains a malformed entity: omit that entity and keep healthy lights.
  • Selected entity temporarily missing: keep its alias/order and show it as unavailable.
  • Preference write fails: retain the in-memory edit, show an inline Settings error, and allow Retry; do not overwrite the previous valid file.
  • Brightness request fails: snap the tile to its last confirmed value and show the error on that tile only.
  • BlueBubbles missing: disable Messages without affecting KDE Connect actions.

Files and components

  • config/dot/quickshell/config/HomePreferences.qml — private selected-light order and aliases.
  • config/dot/quickshell/config/qmldir — register the preference singleton.
  • config/dot/quickshell/scripts/panama-home-assistant — catalog and brightness contracts.
  • config/dot/quickshell/services/HomeAssistant.qml — catalog/preference/action composition.
  • config/dot/quickshell/services/SystemSettings.qml — BlueBubbles detection and allow-listed launch.
  • config/dot/quickshell/modules/quicksettings/HomeControls.qml — two-column accessory shelf and expanded selected grid.
  • config/dot/quickshell/modules/quicksettings/HomeTile.qml — power, percentage, busy/error state, and slider.
  • config/dot/quickshell/modules/quicksettings/PhoneControls.qml — Messages action and independent enablement.
  • config/dot/quickshell/modules/settings/HomePhonePage.qml — discovery, selection, aliases, ordering, and phone handoff.
  • config/dot/quickshell/modules/settings/SettingsSidebar.qml and SettingsShell.qml — page registration and routing.
  • config/dot/quickshell/services/ShellState.qml and shell.qml — allow the Control Center and tests to open the Home & Phone page directly.

Testing and verification

Focused automated coverage will prove:

  1. Catalog filtering returns all valid lights, excludes other domains and raw attributes, normalizes 0255 brightness, and tolerates malformed entities.
  2. Brightness validates entity membership and 0100 bounds, uses light.turn_on for 1100, and uses light.turn_off for zero.
  3. First-run migration seeds the legacy order once; selection, aliases, reordering, removal, and intentionally empty state survive a shell restart.
  4. The first four selected lights form the resting shelf and the expanded grid contains every selected light in order.
  5. Slider preview does not issue an action until release; success refreshes; failure restores the confirmed value and remains local to one tile.
  6. Settings routes to Home & Phone, searches the complete catalog, and exposes source names separately from aliases.
  7. Messages maps only to the allow-listed BlueBubbles command and remains independent of KDE Connect reachability.
  8. Existing Control Center, Settings, Home Assistant, KDE Connect, Ongoing, notification, and shell contracts remain green.
  9. Fresh Quickshell construction has no QML errors, Hyprland configuration is valid, and visual captures cover resting, expanded, off-light drag, unavailable light, and Settings states.

Automated tests will not toggle or dim a real light and will not open BlueBubbles. Those final checks require explicit user actions in the finished interfaces.