Skip to content

Commit 6e4a898

Browse files
committed
Handle SDNO digital mode and speed up probe tests
1 parent fa9e39a commit 6e4a898

4 files changed

Lines changed: 46 additions & 11 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ await receiver.set_digital_input(DigitalInputMode.AUTO)
175175
await receiver.set_digital_input(DigitalInputMode.HDMI)
176176
await receiver.set_digital_input(DigitalInputMode.DIGITAL)
177177
await receiver.set_digital_input(DigitalInputMode.ANALOG)
178-
mode = await receiver.query_digital_input() # DigitalInputMode enum
178+
mode = await receiver.query_digital_input() # DigitalInputMode enum or None ("NO")
179179
```
180180

181181
Legacy models also support `PCM`, `DTS`, `RF`, `EXT_IN_1`, `EXT_IN_2`.

src/denon_rs232/__init__.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
BAUD_RATE = 9600
2121
COMMAND_TIMEOUT = 2.0 # seconds to wait for a response
2222
MULTI_RESPONSE_DELAY = 0.3 # seconds to wait for multi-response query results
23-
PROBE_TIMEOUT = 0.5 # seconds to wait for each probe attempt
23+
PROBE_TIMEOUT = 0.8 # seconds to wait for each probe attempt
2424
CR = b"\r"
2525

2626
# Volume range constants (dB)
@@ -526,8 +526,11 @@ async def set_digital_input(self, mode: DigitalInputMode) -> None:
526526
"""Set digital input mode."""
527527
await self._send_command("SD", mode.value)
528528

529-
async def query_digital_input(self) -> DigitalInputMode:
530-
return DigitalInputMode(await self._query("SD"))
529+
async def query_digital_input(self) -> DigitalInputMode | None:
530+
param = await self._query("SD")
531+
if param == "NO":
532+
return None
533+
return DigitalInputMode(param)
531534

532535
# -- Video select commands --
533536

@@ -638,7 +641,9 @@ async def zone3_set_volume(self, db: float) -> None:
638641

639642
# -- Probing --
640643

641-
async def probe_sources(self) -> frozenset[InputSource]:
644+
async def probe_sources(
645+
self, timeout: float | None = None
646+
) -> frozenset[InputSource]:
642647
"""Probe which input sources the receiver supports.
643648
644649
Tries setting each input source and checks if the receiver accepts it.
@@ -650,6 +655,9 @@ async def probe_sources(self) -> frozenset[InputSource]:
650655
if not self._connected:
651656
raise ConnectionError("Not connected")
652657

658+
if timeout is None:
659+
timeout = PROBE_TIMEOUT
660+
653661
original = self._state.input_source
654662
available: set[InputSource] = set()
655663

@@ -660,7 +668,7 @@ async def probe_sources(self) -> frozenset[InputSource]:
660668
for source in InputSource:
661669
if source == original:
662670
continue
663-
resp = await self._send_and_wait("SI", source.value)
671+
resp = await self._send_and_wait("SI", source.value, timeout=timeout)
664672
if resp == source.value:
665673
available.add(source)
666674

@@ -844,11 +852,15 @@ def _process_message(self, message: str) -> None:
844852
changed = self._process_ps_param(param)
845853

846854
elif prefix == "SD":
847-
try:
848-
self._state.digital_input = DigitalInputMode(param)
855+
if param == "NO":
856+
self._state.digital_input = None
849857
changed = True
850-
except ValueError:
851-
_LOGGER.warning("Unknown digital input mode: %s", param)
858+
else:
859+
try:
860+
self._state.digital_input = DigitalInputMode(param)
861+
changed = True
862+
except ValueError:
863+
_LOGGER.warning("Unknown digital input mode: %s", param)
852864

853865
elif prefix == "SV":
854866
if param in ("SOURCE", "OFF"):

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
# Speed up tests by reducing delays
1313
denon_rs232.MULTI_RESPONSE_DELAY = 0.01
14-
denon_rs232.PROBE_TIMEOUT = 0.1
14+
denon_rs232.PROBE_TIMEOUT = 0.01
1515

1616
# Default responses for all query prefixes during startup.
1717
DEFAULT_QUERY_RESPONSES: dict[str, list[str]] = {

tests/test_denon_rs232.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,17 @@ async def respond():
626626
assert result == DigitalInputMode.AUTO
627627

628628

629+
async def test_query_digital_input_no_returns_none(receiver, mock_serial):
630+
async def respond():
631+
await asyncio.sleep(0.05)
632+
mock_serial.inject_response("SDNO")
633+
634+
task = asyncio.create_task(respond())
635+
result = await receiver.query_digital_input()
636+
await task
637+
assert result is None
638+
639+
629640
async def test_query_video_select(receiver, mock_serial):
630641
async def respond():
631642
await asyncio.sleep(0.05)
@@ -872,6 +883,18 @@ async def test_digital_input_event(receiver, mock_serial):
872883
assert states[-1].digital_input == DigitalInputMode.AUTO
873884

874885

886+
async def test_digital_input_no_event(receiver, mock_serial, caplog):
887+
"""SD NO should clear digital_input to None without warning."""
888+
states: list[DenonState] = []
889+
receiver.subscribe(lambda s: states.append(s))
890+
891+
mock_serial.inject_response("SDNO")
892+
await asyncio.sleep(0.1)
893+
894+
assert states[-1].digital_input is None
895+
assert "Unknown digital input mode: NO" not in caplog.text
896+
897+
875898
# -- Event tests: video select --
876899

877900

0 commit comments

Comments
 (0)