# 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`), 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= |