"""Everything you might want to change lives here. Copy the values out of `GET /api/targets` (or the old `/targets`) the first time you run this, so the names below match exactly what HEOS reports for your own devices. """ import os from pathlib import Path def _load_dotenv(path: Path): """A `source .env` a shell might forget to `export` is a whole class of bug this sidesteps: read the file directly, rather than trusting whatever the calling shell's environment happens to contain. Existing environment variables still win, so a real export (or systemd's EnvironmentFile) overrides the file rather than the other way round.""" if not path.exists(): return for line in path.read_text().splitlines(): line = line.strip() if not line or line.startswith("#") or "=" not in line: continue key, _, value = line.partition("=") os.environ.setdefault(key.strip(), value.strip()) _load_dotenv(Path(__file__).resolve().parent / ".env") # --- Network ---------------------------------------------------------- # Any ONE HEOS device's IP is enough: HEOS is a distributed system, so # whichever unit you connect to can see and control every player and # group on the network. HEOS_HOST = "192.168.0.10" HEOS_PORT = 1255 # Port the panel itself listens on. WEB_PORT = 5443 # --- Rooms ------------------------------------------------------------ # key -> how to find it on the network, and how to label it in the UI. # # heos_name : the EXACT name HEOS reports for that player or group. # players : only for a target that is a HEOS *group* (a stereo pair # or an In-Room Group). List its member players, leader # first. Leave it out and the panel learns the members the # first time it sees the group un-merged, then remembers # them in members.json -- which is what lets it rebuild the # pair after you unmerge it from the AVR. # spotify_name : only needed if a room's Spotify Connect name differs # from heos_name -- GET /api/spotify/devices?account=fifou shows what # Spotify actually calls it. Defaults to heos_name. TARGETS = { "avr": { "label": "Home Cinema", "heos_name": "Home Cinema", # AVR-X3800H }, "home400": { "label": "Lego Room", "heos_name": "Lego Room", # Denon Home 400 }, "living_room_group": { "label": "Living Room", "heos_name": "Denon Home 200 L", # 2x Denon Home 200, In-Room Group "spotify_name": "Living Room", # what Spotify Connect calls the pair # "players": ["Denon Home 200 L", "Denon Home 200 R"], }, } # The AVR is always the group host: its content takes over every room # that joins, which is the whole point of the merge buttons. HOST_KEY = "avr" # The rooms that get a card with volume + a join/leave button, in order. ROOM_KEYS = ["home400", "living_room_group"] # --- Behaviour -------------------------------------------------------- # The grid the volume buttons snap to. A tap moves to the next multiple of # this rather than adding it, so at 5 a level of 23 goes to 25, not 28. VOLUME_STEP = 5 # Narrows the AVR's input picker to the sources you actually use, by their # HEOS input id (see GET /api/avr/inputs for the exact strings, e.g. # "inputs/aux_in_1"), and sets their order in the list. Empty = every # source HEOS reports for it. AVR_INPUT_CODES = [] # Shown as the app's name on the iOS home screen. APP_NAME = "Heos" # --- Spotify (optional) ------------------------------------------------- # One Spotify button per account on each speaker's card (not the AVR's), # resuming that account's playback there -- see the README's Spotify section and # tools/spotify_auth.py. Credentials come from .env, never from here, so # they stay out of git. One developer app serves every account; only the # refresh token differs, since that is what each account's login produces. SPOTIFY_CLIENT_ID = os.environ.get("SPOTIFY_CLIENT_ID") SPOTIFY_CLIENT_SECRET = os.environ.get("SPOTIFY_CLIENT_SECRET") # key -> button label and that account's refresh token, in button order. # An account without a token gets no button. SPOTIFY_ACCOUNTS = { "fifou": {"label": "Fifou", "refresh_token": os.environ.get("SPOTIFY_FIFOU_REFRESH_TOKEN")}, "clarita": {"label": "Clarita", "refresh_token": os.environ.get("SPOTIFY_CLARITA_REFRESH_TOKEN")}, }