IR remote: power key switches the screen; count irserver's repeats

KEY_POWER emits ToggleScreenRequested, which a new ScreenService turns into the
optional general.screen.toggle_command (musicdolphin: ansible's kiosk-screen). It is
a service, not a reaction, so the subprocess runs in its own task instead of holding
the bus; a press while one is still running is dropped, and failures, hangs and a
missing command are only logged.

irserver reports every line of a held button as repeat 00, so a slightly long press
on Next skipped several tracks and Power would switch the screen off and on again.
A line of the same button within 0.25s of the previous one now counts as a repeat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 16:13:22 +02:00
parent 92644e9519
commit 2d0caeb732
8 changed files with 303 additions and 2 deletions

View File

@@ -21,6 +21,7 @@ from musicmouse.events import (
PlayRequested,
PlaySeriesLatestRequested,
PreviousTrackRequested,
ToggleScreenRequested,
VolumeChangeRequested,
)
from musicmouse.services.lirc import LircService
@@ -265,6 +266,56 @@ async def test_volume_buttons_act_on_every_repeat(
assert all(event.delta < 0 for event in seen)
async def test_a_held_button_from_irserver_acts_once(
lircd: tuple[ScriptedLircd, asyncio.base_events.Server], sim: Simulation
) -> None:
# irserver sends every line of a held button as repeat 00.
station, server = lircd
port = server.sockets[0].getsockname()[1]
seen: list[Event] = []
sim.bus.subscribe(NextTrackRequested, seen.append)
sim.bus.subscribe(VolumeChangeRequested, seen.append)
assert isinstance(sim.clock, FakeClock)
task = await _run_service(sim, _lirc_config(port))
try:
await station.wait_connected()
for _ in range(3):
await station.send("b7b0000000000000 00 key_forward hauppauge")
await sim.clock.advance(0.11)
await sim.clock.advance(1.0)
await station.send("b7b0000000000000 00 key_forward hauppauge")
# Volume still ramps for as long as it is held.
for _ in range(3):
await station.send("b720000000000000 00 key_volumeup hauppauge")
await sim.clock.advance(0.11)
await sim.bus.drain()
finally:
task.cancel()
assert [type(event) for event in seen] == [NextTrackRequested] * 2 + [VolumeChangeRequested] * 3
async def test_the_power_button_toggles_the_screen(
lircd: tuple[ScriptedLircd, asyncio.base_events.Server], sim: Simulation
) -> None:
station, server = lircd
port = server.sockets[0].getsockname()[1]
seen: list[Event] = []
sim.bus.subscribe(ToggleScreenRequested, seen.append)
task = await _run_service(sim, _lirc_config(port))
try:
await station.wait_connected()
await station.send("b7d0000000000000 00 key_power hauppauge")
await station.send("b7d0000000000000 00 key_power hauppauge") # still held
await sim.bus.drain()
finally:
task.cancel()
assert len(seen) == 1
async def test_mute_toggles_and_restores(
lircd: tuple[ScriptedLircd, asyncio.base_events.Server], sim: Simulation
) -> None:
@@ -281,6 +332,9 @@ async def test_mute_toggles_and_restores(
await sim.bus.drain()
assert sim.player.volume == 0
# A second press, not the first one held - see the repeat counting below.
assert isinstance(sim.clock, FakeClock)
await sim.clock.advance(1.0)
await station.send("0 00 KEY_MUTE Hauppauge")
await sim.bus.drain()
assert sim.player.volume == 37