7bfbf4de9a
Spec for packaging the Alexa Media Player HACS component declaratively on jupiter (HA -> Echo: TTS/announce, media, sensors). Requires bumping alexapy 1.29.22 -> 1.29.25 and packaging dictor 0.1.12 (absent from nixpkgs) to satisfy the manifest's exact requirement pins. Alexa -> HA voice control is explicitly deferred. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RCn8YgGQMGpauatdeTdQYf
153 lines
6.7 KiB
Markdown
153 lines
6.7 KiB
Markdown
# Amazon Alexa integration for Home Assistant (jupiter) — design
|
|
|
|
**Date:** 2026-07-29
|
|
**Machine:** jupiter
|
|
**Status:** approved, ready for implementation plan
|
|
|
|
## Goal
|
|
|
|
Let Home Assistant control and read the household Amazon Echo devices via the
|
|
unofficial [`alexa_media_player`](https://github.com/Alandtse/alexa_media_player)
|
|
integration: text-to-speech / announcements, media control, and per-device
|
|
sensors (last-called device, next alarm/timer, DND state, etc.).
|
|
|
|
This uses the user's Amazon account through an unofficial API. It is a
|
|
config-flow integration: after the rebuild it is added through the HA UI, not
|
|
via YAML.
|
|
|
|
## Non-goals (deferred)
|
|
|
|
Alexa → HA voice control ("Alexa, turn on the light") is **out of scope**. It
|
|
would need either `emulated_hue` bound to port 80 on the LAN, or a public HTTPS
|
|
endpoint plus the AWS-Lambda Smart Home Skill. The user chose to decide on that
|
|
later. Nothing in this change touches the firewall, port 80, systemd unit
|
|
capabilities, or network exposure.
|
|
|
|
## Approach
|
|
|
|
Package the integration declaratively, following the existing `ha-sourdough`
|
|
pattern in `modules/environments/home-assistant/default.nix` (a
|
|
`buildHomeAssistantComponent` entry in `services.home-assistant.customComponents`).
|
|
No HACS runtime.
|
|
|
|
Unlike sourdough, `alexa_media_player` has real Python dependencies. Its
|
|
`manifest.json` (v5.15.7) declares:
|
|
|
|
```
|
|
alexapy==1.29.25
|
|
packaging>=20.3
|
|
wrapt>=1.14.0
|
|
dictor>=0.1.12,<0.2
|
|
```
|
|
|
|
`buildHomeAssistantComponent` runs `manifestCheckPhase` at build time
|
|
(`check_manifest.py`): every requirement must resolve to an installed
|
|
distribution **whose version satisfies the specifier**, or the build fails.
|
|
Home Assistant repeats this check at runtime. Therefore each requirement must be
|
|
satisfied exactly — the exact `==1.29.25` pin in particular.
|
|
|
|
Dependency status in the pinned nixpkgs (`nixos-25.11`):
|
|
|
|
| Requirement | nixpkgs today | Action |
|
|
| ---------------------- | ------------- | --------------------------------------- |
|
|
| `alexapy==1.29.25` | 1.29.22 | **Bump** to 1.29.25 via override |
|
|
| `dictor>=0.1.12,<0.2` | *absent* | **Package** dictor 0.1.12 (new) |
|
|
| `wrapt>=1.14.0` | 1.17.2 | none — already satisfied |
|
|
| `packaging>=20.3` | 26.1 | none — already satisfied |
|
|
|
|
`authcaptureproxy` (in nixpkgs at 1.3.7) is a transitive dependency of
|
|
`alexapy`, not listed in the manifest, so it needs no direct handling.
|
|
|
|
## Components
|
|
|
|
All changes live in `modules/environments/home-assistant/default.nix` (plus the
|
|
hashes below). Three small pieces, wired together in the module's `let` block:
|
|
|
|
### 1. `dictor` package (new)
|
|
|
|
Not in nixpkgs. Pure-Python, no runtime dependencies (`requires_dist: null`),
|
|
ships a `setup.py`. A minimal `pkgs.python3Packages.buildPythonPackage`:
|
|
|
|
- pname `dictor`, version `0.1.12`
|
|
- `src = fetchPypi { pname = "dictor"; version = "0.1.12"; hash = "sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs="; }`
|
|
- setuptools format (legacy `setup.py`); `build-system = [ setuptools ]`
|
|
- `doCheck = false` (no meaningful test suite); `pythonImportsCheck = [ "dictor" ]`
|
|
|
|
Build against the HA Python set so the version lands in HA's venv — i.e. use
|
|
`config.services.home-assistant.package.python.pkgs` (the same interpreter the
|
|
component check and HA runtime use), not the top-level `pkgs.python3Packages`.
|
|
|
|
### 2. `alexapy` 1.29.25 (override)
|
|
|
|
nixpkgs `alexapy` is fetched from **GitLab** (`keatontaylor/alexapy`, tag
|
|
`v<version>`), not PyPI. Override just the version + src via
|
|
`overridePythonAttrs`, reusing the existing build-system and dependency list:
|
|
|
|
- `version = "1.29.25"`
|
|
- `src = fetchFromGitLab { owner = "keatontaylor"; repo = "alexapy"; tag = "v1.29.25"; hash = "sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4="; }`
|
|
|
|
This is a patch bump (1.29.22 → 1.29.25); the dependency set is expected to be
|
|
unchanged. Override the HA-Python-set `alexapy` so it shares the interpreter
|
|
with dictor and the component.
|
|
|
|
### 3. `alexa_media_player` component (new `customComponents` entry)
|
|
|
|
```
|
|
buildHomeAssistantComponent {
|
|
owner = "Alandtse";
|
|
domain = "alexa_media";
|
|
version = "5.15.7";
|
|
src = fetchFromGitHub {
|
|
owner = "Alandtse";
|
|
repo = "alexa_media_player";
|
|
rev = "v5.15.7";
|
|
hash = "sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI=";
|
|
};
|
|
dependencies = [ alexapy' dictor' wrapt packaging ]; # HA-python-set packages
|
|
}
|
|
```
|
|
|
|
`dependencies` must make every manifest requirement importable at the required
|
|
version for `manifestCheckPhase` to pass. Include all four (the two custom ones
|
|
plus `wrapt` and `packaging` from the HA Python set) to be explicit.
|
|
|
|
## Data flow
|
|
|
|
1. `nixos-rebuild switch` builds the component; `manifestCheckPhase` validates
|
|
the four requirements against the provided `dependencies`.
|
|
2. HA starts; the custom component is present but not configured.
|
|
3. User adds **Alexa Media Player** in Settings → Devices & Services, signs in
|
|
with the Amazon account (email/password; 2FA or app-password handled in the
|
|
UI flow at runtime).
|
|
4. HA creates media_player entities and per-device sensors; TTS/announce
|
|
services become available for automations.
|
|
|
|
## Error handling / risks
|
|
|
|
- **Version-pin drift.** If a future `alexa_media_player` bump changes the
|
|
`alexapy==` pin, `alexapy` must be re-bumped in lockstep, or the build fails
|
|
loudly at `manifestCheckPhase` (fail-safe, not silent).
|
|
- **Amazon login fragility.** The unofficial API can break on Amazon's side
|
|
(captcha/2FA changes). This is a runtime concern, independent of packaging;
|
|
not addressed here.
|
|
- **`dictor` upper bound `<0.2`.** 0.1.12 is the current release and satisfies
|
|
it. If nixpkgs later gains a `dictor` ≥ 0.2, prefer our pinned 0.1.12 for
|
|
this component.
|
|
|
|
## Verification
|
|
|
|
- `nix build '.#nixosConfigurations.jupiter.config.system.build.toplevel'`
|
|
succeeds — this exercises the build-time manifest-requirements check for all
|
|
three new/overridden derivations.
|
|
- `nixfmt-rfc-style` clean on the edited module.
|
|
- Post-deploy (manual, by the user): the integration appears under Add
|
|
Integration, and a TTS/announce call reaches an Echo.
|
|
|
|
## Pinned artifacts
|
|
|
|
| Artifact | Source | Ref / version | Hash |
|
|
| --------------------------- | ---------- | ------------- | ------------------------------------------------- |
|
|
| alexa_media_player | GitHub | v5.15.7 | sha256-1rcZVSX1xA1Lc4qSu39MOitVEciZFhoPQy2y5+PpoAI= |
|
|
| alexapy | GitLab | v1.29.25 | sha256-P/hvgqZVaBJF5dbmHrDjQMC+pwV3EEhKyFIS5KmhgD4= |
|
|
| dictor | PyPI sdist | 0.1.12 | sha256-bbSDda4eU9ye2EToWzj04/v79qTmC+yjd1Fa0URTuRs= |
|