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
246 lines
12 KiB
Markdown
246 lines
12 KiB
Markdown
# 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 1–100 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 0–255 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 0–100 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 0–255 brightness, and tolerates malformed entities.
|
||
2. Brightness validates entity membership and 0–100 bounds, uses
|
||
`light.turn_on` for 1–100, 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.
|