Skip to content

Commit

Permalink
Support subscription of more telnet events (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
ol-iver authored Jul 9, 2023
1 parent a9beba7 commit 2e59d42
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 14 deletions.
44 changes: 38 additions & 6 deletions denonavr/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,19 @@
import sys
import time
import xml.etree.ElementTree as ET
from collections import defaultdict
from io import BytesIO
from typing import Awaitable, Callable, Dict, Hashable, Optional, Tuple, cast
from typing import (
Awaitable,
Callable,
DefaultDict,
Dict,
Hashable,
List,
Optional,
Tuple,
cast,
)

import attr
import httpx
Expand Down Expand Up @@ -61,6 +72,16 @@ def get_default_async_client() -> httpx.AsyncClient:
return httpx.AsyncClient()


def telnet_event_map_factory() -> Dict[str, List]:
"""Create telnet event map."""
event_map: DefaultDict[str, List] = defaultdict(list)
for event in TELNET_EVENTS:
event_map[event[0:2]].append(event)
for value in event_map.values():
value.sort(key=len, reverse=True)
return dict(event_map)


@attr.s(auto_attribs=True, hash=False, on_setattr=DENON_ATTR_SETATTR)
class DenonAVRApi:
"""Perform API calls to Denon AVR REST interface."""
Expand Down Expand Up @@ -403,6 +424,9 @@ class DenonAVRTelnetApi:
_reconnect_task: asyncio.Task = attr.ib(default=None)
_monitor_handle: asyncio.TimerHandle = attr.ib(default=None)
_protocol: DenonAVRTelnetProtocol = attr.ib(default=None)
_telnet_event_map: Dict[str, List] = attr.ib(
default=attr.Factory(telnet_event_map_factory)
)
_callbacks: Dict[str, Callable] = attr.ib(
validator=attr.validators.instance_of(dict),
default=attr.Factory(dict),
Expand Down Expand Up @@ -568,9 +592,9 @@ def _process_event(self, message: str) -> None:
zone = MAIN_ZONE

# Event is 2 characters
event = message[0:2]
event = self._get_event(message)
# Parameter is the remaining characters
parameter = message[2:]
parameter = message[len(event) :]

if event == "MV":
# This seems undocumented by Denon and appears to basically be a
Expand All @@ -589,9 +613,9 @@ def _process_event(self, message: str) -> None:
event = "SI"
elif parameter.isdigit():
event = "MV"
elif parameter[0:2] in TELNET_EVENTS:
event = parameter[0:2]
parameter = parameter[2:]
elif self._get_event(parameter):
event = self._get_event(parameter)
parameter = parameter[len(event) :]

if event not in TELNET_EVENTS:
return
Expand Down Expand Up @@ -626,6 +650,14 @@ async def _async_run_callbacks(self, event: str, zone: str, parameter: str) -> N
err,
)

def _get_event(self, message: str) -> str:
"""Get event of a telnet message."""
events = self._telnet_event_map.get(message[0:2], [""])
for event in events:
if message.startswith(event):
return event
return ""

def send_commands(self, *commands: str) -> bool:
"""Send telnet commands to the receiver."""
if not self.connected:
Expand Down
24 changes: 23 additions & 1 deletion denonavr/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"NET",
"PANDORA",
"SIRIUSXM",
"SOURCE",
"LASTFM",
"FLICKR",
"IRADIO",
Expand Down Expand Up @@ -412,18 +413,39 @@
command_play=COMMAND_PLAY,
)

# Telnet Commands
# Telnet Events
TELNET_EVENTS = {
"CV",
"DC",
"DIM",
"ECO",
"HD",
"MN",
"MS",
"MU",
"MV",
"NS",
"NSA",
"NSE",
"OP",
"PS",
"PV",
"PW",
"RM",
"SD",
"SI",
"SLP",
"SR",
"SS",
"STBY",
"SV",
"SY",
"TF",
"TM",
"TP",
"TR",
"UG",
"VS",
"ZM",
"Z2",
"Z3",
Expand Down
14 changes: 7 additions & 7 deletions denonavr/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def setup(self) -> None:
power_event, self._async_power_callback
)
self._device.telnet_api.register_callback("SI", self._async_input_callback)
self._device.telnet_api.register_callback("NS", self._async_netaudio_callback)
self._device.telnet_api.register_callback("NSE", self._async_netaudio_callback)
self._device.telnet_api.register_callback("TF", self._async_tuner_callback)
self._device.telnet_api.register_callback("HD", self._async_hdtuner_callback)
self._device.telnet_api.register_callback(
Expand Down Expand Up @@ -285,12 +285,12 @@ async def _async_netaudio_callback(
if self._input_func not in self._netaudio_func_list:
return

if parameter.startswith("E1"):
self._title = parameter[2:]
elif parameter.startswith("E2"):
self._artist = parameter[2:]
elif parameter.startswith("E4"):
self._album = parameter[2:]
if parameter.startswith("1"):
self._title = parameter[1:]
elif parameter.startswith("2"):
self._artist = parameter[1:]
elif parameter.startswith("4"):
self._album = parameter[1:]
self._band = None
self._frequency = None
self._station = None
Expand Down

0 comments on commit 2e59d42

Please sign in to comment.