From 0c8672789dcd9b2753578573fe5e42467eeda9d0 Mon Sep 17 00:00:00 2001 From: franzz Date: Tue, 22 Sep 2026 15:37:07 +0200 Subject: [PATCH] Set hard-coded rooms order in config file --- README.md | 6 +++--- app.py | 33 ++++++++++++++++--------------- config.json.example | 29 +++++++++++++++------------- config.py | 34 +++++++++++++++++++++++++------- controller.py | 34 ++++++++++++++++---------------- demo.py | 20 +++++++++---------- static/app.js | 46 +++++++++++--------------------------------- static/panel.css | 15 +++------------ templates/index.html | 4 ++-- tests/test_panel.py | 6 +++--- tests/test_zidoo.py | 4 ++-- 11 files changed, 111 insertions(+), 120 deletions(-) diff --git a/README.md b/README.md index fe5cfb1..5ec7085 100644 --- a/README.md +++ b/README.md @@ -91,11 +91,11 @@ sudo nginx -t && sudo systemctl reload nginx Copy `config.json.example` to `config.json` and fill in the exact `name` HEOS reports for each device. The names come from whatever you typed in the HEOS app, so they rarely match the model names. -`web_port` is this app listening port. +`app_port` is this app listening port. -Open `http://:/api/targets`. +Open `http://:/api/targets`. -`host_key` is the group host into which the room will be grouped into (the AVR), and `room_keys` sets which rooms can be grouped (also set the card order on the app). +`host_room` is the group host into which the room will be grouped into (the AVR), and `guest_rooms` sets which rooms can be grouped. Each room in `rooms` (the host included) also needs an `order` -- the card's position on the app, lowest first. `heos_host` only needs to point at **one** device: HEOS is distributed, so any unit can see and control the whole network. `heos_port`, `zidoo_host` and `zidoo_port` all work the same way. diff --git a/app.py b/app.py index ef427c9..3630dc1 100644 --- a/app.py +++ b/app.py @@ -44,14 +44,14 @@ spotify: dict = {} # account key -> SpotifyClient, configured accounts only # controller.py's module docstring), so its API has no field that says how # many units heos_name actually names -- that has to come from config.json's # "in_room_group" instead (config.IN_ROOM_GROUPS). The AVR/speaker split -# needs no such flag: this app's own design always makes HOST_KEY the AVR -# and ROOM_KEYS plain speakers, so it is known before any HEOS call is made. +# needs no such flag: this app's own design always makes HOST_ROOM the AVR +# and GUEST_ROOMS plain speakers, so it is known before any HEOS call is made. # # "kind" is passed straight through to the template as-is (one of # config.IN_ROOM_GROUPS, or "avr") -- which icon that draws is the # interface's business, not ours: see ICONS in static/app.js. def _room_meta(key: str, kind: str) -> dict: - return {"key": key, "kind": kind, **config.TARGETS[key]} + return {"key": key, "kind": kind, **config.ROOMS[key]} def _build_spotify() -> dict: @@ -104,9 +104,9 @@ def _payload() -> dict: def _target_from(data: dict, field: str = "target") -> str: key = data.get(field) if not key: - raise ValueError(f"Missing '{field}'. Valid rooms: {', '.join(config.TARGETS)}") - if key not in config.TARGETS: - raise ValueError(f"Unknown room '{key}'. Valid rooms: {', '.join(config.TARGETS)}") + raise ValueError(f"Missing '{field}'. Valid rooms: {', '.join(config.ROOMS)}") + if key not in config.ROOMS: + raise ValueError(f"Unknown room '{key}'. Valid rooms: {', '.join(config.ROOMS)}") return key @@ -122,7 +122,7 @@ def _spotify_from(data: dict) -> SpotifyClient: def _spotify_name(key: str) -> str: - target = config.TARGETS[key] + target = config.ROOMS[key] return target.get("spotify_name", target["heos_name"]) @@ -234,7 +234,7 @@ def _release_over_heos(key: str): inputs = controller.heos_inputs(key) if not inputs: raise ValueError( - f"'{config.TARGETS[key]['label']}' did not answer on the network, and HEOS lists " + f"'{config.ROOMS[key]['label']}' did not answer on the network, and HEOS lists " "no input on it to fall back to -- so there is no way from here to take this room " "off Spotify.") # An AUX jack with nothing in it is the quietest thing a speaker can be @@ -329,14 +329,14 @@ def _link_zidoo_poster(avr: dict): # --- The UI ----------------------------------------------------------- @app.route("/") def index(): + host = _room_meta(config.HOST_ROOM, "avr") + rooms = {config.HOST_ROOM: host, **{key: _room_meta(key, config.ROOMS[key].get("in_room_group", "none")) for key in config.GUEST_ROOMS}} return render_template( "index.html", app_name=config.APP_NAME, - host=_room_meta(config.HOST_KEY, "avr"), - rooms=[ - _room_meta(key, config.TARGETS[key].get("in_room_group", "none")) - for key in config.ROOM_KEYS - ], + version=config.APP_VERSION, + host=host, + rooms=sorted(rooms.values(), key=lambda room: room["order"]), step=config.VOLUME_STEP, spotify_accounts=[{"key": key, "label": config.SPOTIFY_ACCOUNTS[key]["label"]} for key in spotify], ) @@ -360,6 +360,7 @@ def api_state(): if not data.get("demo"): _mark_spotify_accounts(data["rooms"]) _link_zidoo_poster(data["avr"]) + data["version"] = config.APP_VERSION return jsonify(data) @@ -433,7 +434,7 @@ def api_playback(): state = data.get("state") if state is not None and state not in ("play", "pause", "stop"): raise ValueError("'state' must be play, pause or stop -- or left out to toggle") - if key == config.HOST_KEY: + if key == config.HOST_ROOM: if state == "stop": raise ValueError("The AVR's card plays a device on one of its inputs, which can only " "play or pause -- 'stop' is for a HEOS room") @@ -465,7 +466,7 @@ def api_seek(): if data.get("position_ms") is None: raise ValueError("Provide 'position_ms', where to jump to") position = max(0, int(data["position_ms"])) - if key == config.HOST_KEY: + if key == config.HOST_ROOM: controller.zidoo_seek(position) else: account = _spotify_playing_on().get(_spotify_name(key)) @@ -711,7 +712,7 @@ def legacy_avr_input(): def main(): global controller, spotify parser = argparse.ArgumentParser(description="HEOS panel") - parser.add_argument("--port", type=int, default=config.WEB_PORT) + parser.add_argument("--port", type=int, default=config.APP_PORT) parser.add_argument("--host", default="0.0.0.0", help="0.0.0.0 so your phone can reach it directly; " "127.0.0.1 to allow only a local reverse proxy") diff --git a/config.json.example b/config.json.example index bbbf926..4b04727 100644 --- a/config.json.example +++ b/config.json.example @@ -1,27 +1,30 @@ { - "web_port": 5443, + "app_port": 5443, "heos_host": "REPLACE_WITH_HEOS_HOST", "heos_port": 1255, "zidoo_host": "REPLACE_WITH_ZIDOO_HOST", "zidoo_port": 9529, - "targets": { - "avr": { - "label": "Home Cinema", - "heos_name": "REPLACE_WITH_EXACT_HEOS_NAME" - }, - "lego_room": { - "label": "Lego Room", - "heos_name": "REPLACE_WITH_EXACT_HEOS_NAME" - }, + "rooms": { "living_room": { "label": "Living Room", "heos_name": "REPLACE_WITH_EXACT_HEOS_NAME", "spotify_name": "REPLACE_ONLY_IF_DIFFERENT_FROM_HEOS_NAME", - "in_room_group": "stereo-pair" + "in_room_group": "stereo-pair", + "order": 1 + }, + "avr": { + "label": "Home Cinema", + "heos_name": "REPLACE_WITH_EXACT_HEOS_NAME", + "order": 2 + }, + "lego_room": { + "label": "Lego Room", + "heos_name": "REPLACE_WITH_EXACT_HEOS_NAME", + "order": 3 } }, - "host_key": "avr", - "room_keys": ["living_room", "lego_room"], + "host_room": "avr", + "guest_rooms": ["living_room", "lego_room"], "volume_step": 5, "spotify_accounts": { "account1": "REPLACE_WITH_ACCOUNT_1_NAME", diff --git a/config.py b/config.py index c4d690a..17b462c 100644 --- a/config.py +++ b/config.py @@ -7,6 +7,7 @@ reports for your own devices. import json import os +import subprocess from pathlib import Path @@ -58,29 +59,31 @@ except FileNotFoundError: "and fill in your own rooms (see the README's Configure section)." ) -TARGETS = _cfg["targets"] +ROOMS = _cfg["rooms"] -for _key, _target in TARGETS.items(): - _group = _target.get("in_room_group", "none") +for _index, (_key, _room) in enumerate(ROOMS.items()): + _group = _room.get("in_room_group", "none") if _group not in IN_ROOM_GROUPS: raise SystemExit( f"{_config_path}: '{_key}' has in_room_group '{_group}', not one " f"of {', '.join(IN_ROOM_GROUPS)}" ) + # No 'order' in config.json just means "wherever it falls in rooms". + _room.setdefault("order", _index) # 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 = _cfg["host_key"] +HOST_ROOM = _cfg["host_room"] -# The rooms that get a card with volume + a join/leave button, in order. -ROOM_KEYS = _cfg["room_keys"] +# The rooms that get a card with volume + a join/leave button. +GUEST_ROOMS = _cfg["guest_rooms"] # 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 = _cfg["volume_step"] # Port the panel itself listens on. -WEB_PORT = _cfg["web_port"] +APP_PORT = _cfg["app_port"] # --- Network ---------------------------------------------------------- # Any ONE HEOS device's IP is enough: HEOS is a distributed system, so @@ -104,6 +107,23 @@ ZIDOO_INPUT_CODE = "inputs/mediaplayer" # see GET /api/avr/inputs # Shown as the app's name on the iOS home screen. APP_NAME = "Heos" +# The deployed commit, so the UI can tell when the Pi has moved on to a +# newer version and reload itself -- iOS otherwise resumes a suspended +# home-screen session without ever checking back with the server. Empty +# when git isn't available; app.js treats that as "nothing to compare". +def _app_version() -> str: + try: + result = subprocess.run( + ["git", "rev-parse", "--short", "HEAD"], + cwd=Path(__file__).resolve().parent, + capture_output=True, text=True, timeout=1, + ) + return result.stdout.strip() if result.returncode == 0 else "" + except OSError: + return "" + +APP_VERSION = _app_version() + # --- 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 diff --git a/controller.py b/controller.py index 07d0aca..4a9c4ef 100644 --- a/controller.py +++ b/controller.py @@ -107,7 +107,7 @@ class Controller: """The AVR is always a plain player. Resolving it by player name matters: once it leads a group, HEOS also reports a *group* under the very same name.""" - target = self.cfg.TARGETS[self.cfg.HOST_KEY] + target = self.cfg.ROOMS[self.cfg.HOST_ROOM] pid = self._player_pid(target["heos_name"]) if pid is None: raise TargetError(f"No HEOS player named '{target['heos_name']}' (the AVR) was found") @@ -115,12 +115,12 @@ class Controller: def member_pids(self, key: str) -> list: """The pid of the one player that is this room, as a list.""" - if key not in self.cfg.TARGETS: + if key not in self.cfg.ROOMS: raise TargetError(f"Unknown room '{key}'") - if key == self.cfg.HOST_KEY: + if key == self.cfg.HOST_ROOM: return [self._host_pid()] - name = self.cfg.TARGETS[key]["heos_name"] + name = self.cfg.ROOMS[key]["heos_name"] pid = self._player_pid(name) if pid is None: raise TargetError( @@ -221,7 +221,7 @@ class Controller: def joined_keys(self) -> list: joined, host_pids = [], self._host_group_pids() - for key in self.cfg.ROOM_KEYS: + for key in self.cfg.GUEST_ROOMS: try: if host_pids & set(self.member_pids(key)): joined.append(key) @@ -256,7 +256,7 @@ class Controller: with self._lock: self.scan() wanted = set(self.joined_keys()) | {key} - self.group_targets(self.cfg.HOST_KEY, [k for k in self.cfg.ROOM_KEYS if k in wanted]) + self.group_targets(self.cfg.HOST_ROOM, [k for k in self.cfg.GUEST_ROOMS if k in wanted]) self.scan() self._nudge_avr_input() return self.joined_keys() @@ -274,7 +274,7 @@ class Controller: try: current = self.avr_current_input() if current: - self.play_heos_input(self.cfg.HOST_KEY, current["code"]) + self.play_heos_input(self.cfg.HOST_ROOM, current["code"]) except HeosError: pass @@ -292,12 +292,12 @@ class Controller: """Make the AVR's group contain exactly these rooms and no others.""" with self._lock: self.scan() - wanted = [k for k in self.cfg.ROOM_KEYS if k in joined] + wanted = [k for k in self.cfg.GUEST_ROOMS if k in joined] for key in list(self.joined_keys()): if key not in wanted: self.ungroup(key) if wanted: - self.group_targets(self.cfg.HOST_KEY, wanted) + self.group_targets(self.cfg.HOST_ROOM, wanted) self.scan() return self.joined_keys() @@ -414,7 +414,7 @@ class Controller: """{"code", "name"} pairs for the picker -- heos_inputs()'s shape, renamed to match what the UI and /api/avr/* already send and expect.""" - sources = self.heos_inputs(self.cfg.HOST_KEY) + sources = self.heos_inputs(self.cfg.HOST_ROOM) return [{"code": s["input_id"], "name": s["name"]} for s in sources] def avr_current_input(self): @@ -435,7 +435,7 @@ class Controller: return {"code": mid, "name": payload.get("station") or payload.get("song") or mid} def avr_select_input(self, code: str) -> dict: - self.play_heos_input(self.cfg.HOST_KEY, code) + self.play_heos_input(self.cfg.HOST_ROOM, code) name = next((s["name"] for s in self.avr_inputs() if s["code"] == code), code) return {"code": code, "name": name} @@ -476,7 +476,7 @@ class Controller: matched up as replies come back rather than asked for one at a time.""" snapshot = { - "host": {"key": self.cfg.HOST_KEY, "label": self.cfg.TARGETS[self.cfg.HOST_KEY]["label"]}, + "host": {"key": self.cfg.HOST_ROOM, "label": self.cfg.ROOMS[self.cfg.HOST_ROOM]["label"]}, "rooms": [], "avr": {"connected": False, "input": None, "inputs": [], "volume": None}, "heos_ok": True, @@ -491,7 +491,7 @@ class Controller: joined = set(self.joined_keys()) room_pids, room_errors = {}, {} - for key in self.cfg.ROOM_KEYS: + for key in self.cfg.GUEST_ROOMS: try: room_pids[key] = self.member_pids(key)[0] except TargetError as exc: @@ -526,10 +526,10 @@ class Controller: else: by_room.setdefault(key, {})[field] = result - for key in self.cfg.ROOM_KEYS: + for key in self.cfg.GUEST_ROOMS: room = { "key": key, - "label": self.cfg.TARGETS[key]["label"], + "label": self.cfg.ROOMS[key]["label"], "available": True, "grouped": key in joined, "volume": None, @@ -574,10 +574,10 @@ class Controller: snapshot["heos_ok"] = False snapshot["errors"].append(str(exc)) snapshot["rooms"] = [ - {"key": key, "label": self.cfg.TARGETS[key]["label"], "available": False, + {"key": key, "label": self.cfg.ROOMS[key]["label"], "available": False, "grouped": False, "volume": None, "play_state": None, "spotify": False, "now_playing": None, "error": str(exc)} - for key in self.cfg.ROOM_KEYS + for key in self.cfg.GUEST_ROOMS ] try: diff --git a/demo.py b/demo.py index 8ff9af0..49b74d5 100644 --- a/demo.py +++ b/demo.py @@ -52,11 +52,11 @@ class DemoController: self.cfg = cfg self.avr = _FakeAvr() self.heos = None - self._volume = {key: 22 + 7 * i for i, key in enumerate(cfg.TARGETS)} - self._play = {key: "play" for key in cfg.TARGETS} + self._volume = {key: 22 + 7 * i for i, key in enumerate(cfg.ROOMS)} + self._play = {key: "play" for key in cfg.ROOMS} self._joined = set() # One room on Spotify and one not, so both kinds of card show up. - self._spotify = {key: i == 0 for i, key in enumerate(cfg.ROOM_KEYS)} + self._spotify = {key: i == 0 for i, key in enumerate(cfg.GUEST_ROOMS)} # No cover, since the demo has no network to fetch one from. self._track = {"song": "Harvest Moon", "artist": "Neil Young", "image": None} # Its play button only shows for a stream one of your accounts plays. @@ -67,19 +67,19 @@ class DemoController: # -- what the UI uses --------------------------------------------- def state(self): return { - "host": {"key": self.cfg.HOST_KEY, "label": self.cfg.TARGETS[self.cfg.HOST_KEY]["label"]}, + "host": {"key": self.cfg.HOST_ROOM, "label": self.cfg.ROOMS[self.cfg.HOST_ROOM]["label"]}, "rooms": [ - {"key": key, "label": self.cfg.TARGETS[key]["label"], "available": True, + {"key": key, "label": self.cfg.ROOMS[key]["label"], "available": True, "grouped": key in self._joined, "volume": self._volume[key], "play_state": self._play[key], "spotify": self._spotify[key], "spotify_account": self._account if self._spotify[key] else None, "now_playing": self._track if self._spotify[key] and self._play[key] != "stop" else None, "error": None} - for key in self.cfg.ROOM_KEYS + for key in self.cfg.GUEST_ROOMS ], "avr": { "connected": True, "inputs": self.avr.inputs(), "input": self.avr.current_input(), - "volume": self._volume[self.cfg.HOST_KEY], + "volume": self._volume[self.cfg.HOST_ROOM], # Standing in for a Zidoo plugged into this input, so the # AVR card's now-playing block has something to show here too. "now_playing": {"song": "Big Buck Bunny", "artist": "2008", "image": None, @@ -126,7 +126,7 @@ class DemoController: return self.joined_keys() def set_membership(self, joined): - self._joined = {k for k in self.cfg.ROOM_KEYS if k in joined} + self._joined = {k for k in self.cfg.GUEST_ROOMS if k in joined} return self.joined_keys() def zidoo_play_state(self, state=None): @@ -141,13 +141,13 @@ class DemoController: self._film_ms = min(596000, int(position_ms)) def joined_keys(self): - return [k for k in self.cfg.ROOM_KEYS if k in self._joined] + return [k for k in self.cfg.GUEST_ROOMS if k in self._joined] # -- enough of the rest to keep the legacy routes answering -------- def scan(self): return { "players": [{"name": t["heos_name"], "pid": 1000 + i, "model": "Demo"} - for i, t in enumerate(self.cfg.TARGETS.values())], + for i, t in enumerate(self.cfg.ROOMS.values())], "groups": [], } diff --git a/static/app.js b/static/app.js index 4da2949..74abb7c 100644 --- a/static/app.js +++ b/static/app.js @@ -5,6 +5,9 @@ const STEP = Number(document.documentElement.dataset.step) || 2; // Where the app is mounted: "/" on its own port, "/heos/" behind a proxy. const BASE = document.documentElement.dataset.base || '/'; +// The commit this page was rendered from, so a resumed iOS home-screen +// session can tell the Pi has moved on and reload itself. +const VERSION = document.documentElement.dataset.version || ''; const POLL_MS = 5000; // How long a dropped cursor waits for the player to report it got there. const SEEK_HOLD_MS = 10000; @@ -13,8 +16,6 @@ const SEEK_KEY_MS = 10000; // And how long a pressed play or pause on the AVR waits for the same. The // Zidoo acknowledges the key press at once but takes a moment to act on it. const PLAY_HOLD_MS = 6000; -// Motion turned down in the OS means cards change places without sliding. -const CALM = matchMedia('(prefers-reduced-motion: reduce)'); // Which way each arrow key moves a slider. const ARROWS = { ArrowRight: 1, ArrowUp: 1, ArrowLeft: -1, ArrowDown: -1 }; @@ -77,10 +78,6 @@ const ui = { // theirs do. Which one it is, everything that only it can do goes through. const HOST = ui.avr.dataset.room; -// Named, so a view transition can follow the card when it moves to the top -// and back. A room's name is set as it is placed; the host's never moves. -ui.avr.style.viewTransitionName = 'avr'; - const rooms = {}; let inputs = []; let currentInput = null; @@ -229,7 +226,6 @@ function paintRoom(room) { paintTransport(room); paintSources(room); placeRoom(room); - placeCards(); } /* Song, artist, cover and progress, each only when there is one. The @@ -432,10 +428,6 @@ function placeRoom(room) { // Nothing left in the column below it means it goes last, before the host. ui.app.insertBefore(room.node, next || ui.avr); } - // A view transition only follows an element it can name, and the name has - // to be one of a kind on the page (see placeCards). Inside the host's card - // the card travels with it, so it takes no name of its own there. - room.node.style.viewTransitionName = room.grouped ? 'none' : `room-${room.key}`; } function paintGrouping() { @@ -453,30 +445,6 @@ function paintGrouping() { const playing = inside.some((node) => node.classList.contains('playing')) || shownPlayState(rooms[HOST]) === 'play'; ui.avr.classList.toggle('playing', playing); - placeCards(); -} - -let placing = false; -function placeCards() { - if (placing) return; - placing = true; - queueMicrotask(() => { - placing = false; - // Grouped, a room's card has left the column and the AVR's is the one - // that moves up. The AVR's tint and its position answer the same - // question, and paintGrouping() has just settled it. - const wanted = Object.values(rooms).map((room) => [ - room.node, - // The AVR's tint already answers this: paintGrouping has just settled - // it, over the whole group rather than the host's own stream alone. - room.avr ? room.node.classList.contains('playing') : room.playing() && !room.grouped, - ]); - - const move = () => wanted.forEach(([node, top]) => node.classList.toggle('on-top', top)); - const moves = wanted.some(([node, top]) => node.classList.contains('on-top') !== top); - if (!moves || CALM.matches || !document.startViewTransition) move(); - else document.startViewTransition(move); - }); } /* Press and hold to keep moving, accelerating as you hold. */ @@ -830,6 +798,14 @@ function applyRoom(room, incoming) { } function render(state) { + // The Pi shipped a newer version while this tab (or a resumed iOS + // home-screen session) was still showing an old one -- catch up rather + // than keep polling a page that no longer matches the server. + if (VERSION && state.version && state.version !== VERSION && !busy()) { + location.reload(); + return; + } + (state.rooms || []).forEach((incoming) => applyRoom(rooms[incoming.key], incoming)); const avr = state.avr || {}; diff --git a/static/panel.css b/static/panel.css index ca40179..e39f31d 100644 --- a/static/panel.css +++ b/static/panel.css @@ -47,13 +47,13 @@ @media (prefers-color-scheme: dark) { :root { --bg: #0a0d14; - --card: #151a25; + --card: #202736; --edge: #232b3b; --ink: #eef2f9; --muted: #98a3b8; --outline: #5f6b87; --playing: #1f4a42; - --raised: #29334a; + --raised: #34405b; --scrim: rgba(4, 6, 11, .6); --shadow: rgba(0, 0, 0, .45); --shade: rgba(255, 255, 255, .05); @@ -135,7 +135,7 @@ svg { width: 22px; height: 22px; fill: currentColor; } .ghost { background: transparent; border: 1px solid var(--outline); color: var(--muted); box-shadow: none; } /* nothing to lift */ @keyframes spin { to { transform: rotate(360deg); } } -@keyframes rise { from { transform: translateY(14%); opacity: .4; } } +@keyframes rise { from { transform: translateY(100%); opacity: .4; } } /* Header */ @@ -148,15 +148,6 @@ header .logo { height: 44px; width: auto; display: block; margin: var(--space-xs /* Card */ -/* A playing card goes to the top. order does not transition, so the swap - rides on a view transition instead -- see placeCards() in app.js. */ -.app > .on-top { order: -1; } - -::view-transition-group(*) { - animation-duration: .4s; - animation-timing-function: cubic-bezier(.22, 1, .36, 1); -} - .card { background: var(--card); border-radius: var(--radius-xl); diff --git a/templates/index.html b/templates/index.html index 64e277a..d5e2435 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,5 +1,5 @@ - + @@ -130,7 +130,7 @@ - {% for room in rooms + [host] %} + {% for room in rooms %} {{ room_card(room, spotify_accounts) }} {% endfor %} diff --git a/tests/test_panel.py b/tests/test_panel.py index 5a79c75..554611f 100644 --- a/tests/test_panel.py +++ b/tests/test_panel.py @@ -22,9 +22,9 @@ def build(): heos = FakeHeos() cfg = SimpleNamespace( HEOS_HOST="127.0.0.1", HEOS_PORT=heos.port, - HOST_KEY="avr", - ROOM_KEYS=["lego_room", "living_room"], - TARGETS={ + HOST_ROOM="avr", + GUEST_ROOMS=["lego_room", "living_room"], + ROOMS={ "avr": {"label": "Home Cinema", "heos_name": "Home Cinema"}, "lego_room": {"label": "Lego Room", "heos_name": "Lego Room"}, "living_room": {"label": "Living Room", "heos_name": "Denon Home 200 L"}, diff --git a/tests/test_zidoo.py b/tests/test_zidoo.py index eda1d80..f495e6a 100644 --- a/tests/test_zidoo.py +++ b/tests/test_zidoo.py @@ -169,8 +169,8 @@ class ZidooThroughTheControllerTest(unittest.TestCase): threading.Thread(target=self.server.serve_forever, args=(0.05,), daemon=True).start() self.cfg = SimpleNamespace( HEOS_HOST="127.0.0.1", HEOS_PORT=1255, - HOST_KEY="avr", ROOM_KEYS=[], - TARGETS={"avr": {"label": "Home Cinema", "heos_name": "Home Cinema"}}, + HOST_ROOM="avr", GUEST_ROOMS=[], + ROOMS={"avr": {"label": "Home Cinema", "heos_name": "Home Cinema"}}, VOLUME_STEP=5, ZIDOO_HOST="127.0.0.1", ZIDOO_PORT=self.server.server_address[1], )