Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raise AvrProcessingError exception when sending telnet commands while telnet is not connected and healthy #283

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions denonavr/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
AvrIncompleteResponseError,
AvrInvalidResponseError,
AvrNetworkError,
AvrProcessingError,
AvrTimoutError,
)

Expand Down Expand Up @@ -425,6 +426,7 @@ class DenonAVRTelnetApi:
)
_callback_tasks: Set[asyncio.Task] = attr.ib(attr.Factory(set))
_send_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))
_send_confirmation_timeout: float = attr.ib(converter=float, default=2.0)
_send_confirmation_event: asyncio.Event = attr.ib(
default=attr.Factory(asyncio.Event)
)
Expand Down Expand Up @@ -734,37 +736,34 @@ async def _async_send_command(self, command: str) -> None:
async with self._send_lock:
self._send_confirmation_command = command
self._send_confirmation_event.clear()
if not self.connected or not self.healthy:
raise AvrProcessingError(
f"Error sending command {command}. Telnet connected: "
f"{self.connected}, Connection healthy: {self.healthy}"
)
self._protocol.write(f"{command}\r")
try:
await asyncio.wait_for(self._send_confirmation_event.wait(), 2.0)
await asyncio.wait_for(
self._send_confirmation_event.wait(),
self._send_confirmation_timeout,
)
except asyncio.TimeoutError:
_LOGGER.warning(
"Timeout waiting for confirmation of command: %s", command
)
finally:
self._send_confirmation_command = ""

async def async_send_commands(self, *commands: str) -> bool:
async def async_send_commands(self, *commands: str) -> None:
"""Send telnet commands to the receiver."""
if not self.connected:
return False
if not self.healthy:
return False
for command in commands:
await self._async_send_command(command)

return True

def send_commands(self, *commands: str) -> bool:
def send_commands(self, *commands: str) -> None:
"""Send telnet commands to the receiver."""
if not self.connected:
return False
if not self.healthy:
return False
task = asyncio.create_task(self.async_send_commands(*commands))
self._send_tasks.add(task)
task.add_done_callback(self._send_tasks.discard)
return True

##############
# Properties #
Expand Down
13 changes: 9 additions & 4 deletions denonavr/denonavr.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,13 +226,13 @@ def get_command(self, request: str) -> str:
def send_get_command(self, request: str) -> str:
"""Send HTTP GET command to Denon AVR receiver...for compatibility."""

async def async_send_telnet_commands(self, *commands: str) -> bool:
async def async_send_telnet_commands(self, *commands: str) -> None:
"""Send telnet commands to the receiver."""
return await self._device.telnet_api.async_send_commands(*commands)
await self._device.telnet_api.async_send_commands(*commands)

def send_telnet_commands(self, *commands: str) -> bool:
def send_telnet_commands(self, *commands: str) -> None:
"""Send telnet commands to the receiver."""
return self._device.telnet_api.send_commands(*commands)
self._device.telnet_api.send_commands(*commands)

def register_callback(
self, event: str, callback: Callable[[str, str, str], Awaitable[None]]
Expand Down Expand Up @@ -439,6 +439,11 @@ def receiver_type(self) -> Optional[str]:
return None
return self._device.receiver.type

@property
def telnet_available(self) -> bool:
"""Return True if telnet is connected and healthy."""
return self._device.telnet_available

@property
def telnet_connected(self) -> bool:
"""Return True if telnet is connected."""
Expand Down
23 changes: 15 additions & 8 deletions denonavr/foundation.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,24 +507,31 @@ def power(self) -> Optional[str]:
"""
return self._power

@property
def telnet_available(self) -> bool:
"""Return true if telnet is connected and healthy."""
return self.telnet_api.connected and self.telnet_api.healthy

##########
# Setter #
##########

async def async_power_on(self) -> None:
"""Turn on receiver via HTTP get command."""
success = await self.telnet_api.async_send_commands(
self.telnet_commands.command_power_on
)
if not success:
if self.telnet_available:
await self.telnet_api.async_send_commands(
self.telnet_commands.command_power_on
)
else:
await self.api.async_get_command(self.urls.command_power_on)

async def async_power_off(self) -> None:
"""Turn off receiver via HTTP get command."""
success = await self.telnet_api.async_send_commands(
self.telnet_commands.command_power_standby
)
if not success:
if self.telnet_available:
await self.telnet_api.async_send_commands(
self.telnet_commands.command_power_standby
)
else:
await self.api.async_get_command(self.urls.command_power_standby)


Expand Down
23 changes: 13 additions & 10 deletions denonavr/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -1001,8 +1001,9 @@ async def async_set_input_func(self, input_func: str) -> None:
else:
command_url = self._device.urls.command_sel_src + linp
telnet_command = self._device.telnet_commands.command_sel_src + linp
success = await self._device.telnet_api.async_send_commands(telnet_command)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(telnet_command)
else:
await self._device.api.async_get_command(command_url)

async def async_toggle_play_pause(self) -> None:
Expand All @@ -1024,21 +1025,23 @@ async def async_play(self) -> None:
if self._state == STATE_PLAYING:
_LOGGER.info("Already playing, play command not sent")
return
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_play
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_play
)
else:
await self._device.api.async_get_command(self._device.urls.command_play)
self._state = STATE_PLAYING

async def async_pause(self) -> None:
"""Send pause command to receiver command via HTTP post."""
# Use pause command only for sources which support NETAUDIO
if self._input_func in self._netaudio_func_list:
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_play
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_play
)
else:
await self._device.api.async_get_command(
self._device.urls.command_pause
)
Expand Down
10 changes: 6 additions & 4 deletions denonavr/soundmode.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,9 @@ async def _async_set_all_zone_stereo(self, zst_on: bool) -> None:
else:
command_url += "ZST OFF"
telnet_command += "ZST OFF"
success = await self._device.telnet_api.async_send_commands(telnet_command)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(telnet_command)
else:
await self._device.api.async_get_command(command_url)

##############
Expand Down Expand Up @@ -303,8 +304,9 @@ async def async_set_sound_mode(self, sound_mode: str) -> None:
self._device.telnet_commands.command_sel_sound_mode + sound_mode
)
# sent command
success = await self._device.telnet_api.async_send_commands(telnet_command)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(telnet_command)
else:
await self._device.api.async_get_command(command_url)


Expand Down
47 changes: 26 additions & 21 deletions denonavr/volume.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,20 +143,22 @@ def volume(self) -> Optional[float]:
##########
async def async_volume_up(self) -> None:
"""Volume up receiver via HTTP get command."""
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_volume_up
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_volume_up
)
else:
await self._device.api.async_get_command(
self._device.urls.command_volume_up
)

async def async_volume_down(self) -> None:
"""Volume down receiver via HTTP get command."""
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_volume_down
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_volume_down
)
else:
await self._device.api.async_get_command(
self._device.urls.command_volume_down
)
Expand All @@ -173,31 +175,34 @@ async def async_set_volume(self, volume: float) -> None:

# Round volume because only values which are a multi of 0.5 are working
volume = round(volume * 2) / 2.0
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_set_volume.format(
volume=int(volume + 80)
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_set_volume.format(
volume=int(volume + 80)
)
)
)
if not success:
else:
await self._device.api.async_get_command(
self._device.urls.command_set_volume.format(volume=volume)
)

async def async_mute(self, mute: bool) -> None:
"""Mute receiver via HTTP get command."""
if mute:
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_mute_on
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_mute_on
)
else:
await self._device.api.async_get_command(
self._device.urls.command_mute_on
)
else:
success = await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_mute_off
)
if not success:
if self._device.telnet_available:
await self._device.telnet_api.async_send_commands(
self._device.telnet_commands.command_mute_off
)
else:
await self._device.api.async_get_command(
self._device.urls.command_mute_off
)
Expand Down
Loading
Loading