Skip to content

Commit

Permalink
Validate for all models if sound mode and tone control are supported (#…
Browse files Browse the repository at this point in the history
…306)

* Validate for all models if sound mode is supported

* Validate if tone control is supported

* Allow status.xml as fallback for sound mode
  • Loading branch information
ol-iver authored Sep 23, 2024
1 parent 3adfc85 commit cd04edc
Show file tree
Hide file tree
Showing 58 changed files with 396 additions and 59 deletions.
9 changes: 7 additions & 2 deletions denonavr/denonavr.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ async def async_setup(self) -> None:
# Setup other functions
self.input.setup()
await self.soundmode.async_setup()
self.tonecontrol.setup()
await self.tonecontrol.async_setup()
self.vol.setup()
self.audyssey.setup()

Expand Down Expand Up @@ -320,7 +320,7 @@ def input_func_list(self) -> List[str]:

@property
def support_sound_mode(self) -> Optional[bool]:
"""Return True if sound mode supported."""
"""Return True if sound mode is supported."""
return self.soundmode.support_sound_mode

@property
Expand Down Expand Up @@ -435,6 +435,11 @@ def show_all_inputs(self) -> Optional[bool]:
"""Indicate if all inputs are shown or just active one."""
return self._show_all_inputs

@property
def support_tone_control(self) -> Optional[bool]:
"""Return True if tone control is supported."""
return self.tonecontrol.support_tone_control

@property
def tone_control_status(self) -> Optional[bool]:
"""Return value of tone control status."""
Expand Down
83 changes: 47 additions & 36 deletions denonavr/soundmode.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@
import attr

from .appcommand import AppCommands
from .const import (
ALL_ZONE_STEREO,
AVR_X,
AVR_X_2016,
DENON_ATTR_SETATTR,
SOUND_MODE_MAPPING,
)
from .exceptions import AvrCommandError, AvrProcessingError
from .const import ALL_ZONE_STEREO, DENON_ATTR_SETATTR, SOUND_MODE_MAPPING
from .exceptions import AvrCommandError, AvrIncompleteResponseError, AvrProcessingError
from .foundation import DenonAVRFoundation

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -94,6 +88,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
init=False,
)
_setup_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))
_appcommand_active: bool = attr.ib(converter=bool, default=True, init=False)

# Update tags for attributes
# AppCommand.xml interface
Expand All @@ -106,16 +101,14 @@ async def async_setup(self) -> None:
"""Ensure that the instance is initialized."""
async with self._setup_lock:
_LOGGER.debug("Starting sound mode setup")
# Add tags for a potential AppCommand.xml update
for tag in self.appcommand_attrs:
self._device.api.add_appcommand_update_tag(tag)

# Soundmode is always available for AVR-X and AVR-X-2016 receivers
# For AVR receiver it will be tested during the first update
if self._device.receiver in [AVR_X, AVR_X_2016]:
self._support_sound_mode = True
else:
await self.async_update_sound_mode()

# The first update determines if sound mode is supported
await self.async_update_sound_mode()

if self._support_sound_mode and self._appcommand_active:
# Add tags for a potential AppCommand.xml update
for tag in self.appcommand_attrs:
self._device.api.add_appcommand_update_tag(tag)

self._device.telnet_api.register_callback(
"MS", self._async_soundmode_callback
Expand Down Expand Up @@ -157,29 +150,47 @@ async def async_update_sound_mode(
"Device is not setup correctly, update method not set"
)

if self._device.use_avr_2016_update:
await self.async_update_attrs_appcommand(
self.appcommand_attrs, global_update=global_update, cache_id=cache_id
)
else:
urls = [self._device.urls.status, self._device.urls.mainzone]
if self._is_setup and not self._support_sound_mode:
if self._is_setup and not self._support_sound_mode:
return

if self._device.use_avr_2016_update and self._appcommand_active:
try:
await self.async_update_attrs_appcommand(
self.appcommand_attrs,
global_update=global_update,
cache_id=cache_id,
)
except (AvrProcessingError, AvrIncompleteResponseError):
self._appcommand_active = False
_LOGGER.debug(
"Appcommand.xml does not support Sound mode. "
"Testing status.xml interface next"
)
else:
if not self._is_setup:
self._support_sound_mode = True
_LOGGER.info("Sound mode supported")
return
# There are two different options of sound mode tags

urls = [self._device.urls.status, self._device.urls.mainzone]
# There are two different options of sound mode tags
try:
await self.async_update_attrs_status_xml(
self.status_xml_attrs_01, urls, cache_id=cache_id
)
except AvrProcessingError:
try:
await self.async_update_attrs_status_xml(
self.status_xml_attrs_01, urls, cache_id=cache_id
self.status_xml_attrs_02, urls, cache_id=cache_id
)
except AvrProcessingError:
try:
await self.async_update_attrs_status_xml(
self.status_xml_attrs_02, urls, cache_id=cache_id
)
except AvrProcessingError:
_LOGGER.info("Sound mode not supported")
self._support_sound_mode = False
return
self._support_sound_mode = False
_LOGGER.info("Sound mode not supported")
return

if not self._is_setup:
self._support_sound_mode = True
_LOGGER.info("Sound mode supported")

def match_sound_mode(self) -> Optional[str]:
"""Match the raw_sound_mode to its corresponding sound_mode."""
Expand Down Expand Up @@ -252,7 +263,7 @@ async def _async_set_all_zone_stereo(self, zst_on: bool) -> None:
##############
@property
def support_sound_mode(self) -> Optional[bool]:
"""Return True if sound mode supported."""
"""Return True if sound mode is supported."""
return self._support_sound_mode

@property
Expand Down
70 changes: 50 additions & 20 deletions denonavr/tonecontrol.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:license: MIT, see LICENSE for more details.
"""

import asyncio
import logging
import time
from collections.abc import Hashable
Expand All @@ -16,7 +17,7 @@

from .appcommand import AppCommandCmdParam, AppCommands
from .const import DENON_ATTR_SETATTR
from .exceptions import AvrCommandError, AvrProcessingError
from .exceptions import AvrCommandError, AvrIncompleteResponseError, AvrProcessingError
from .foundation import DenonAVRFoundation, convert_string_int_bool

_LOGGER = logging.getLogger(__name__)
Expand All @@ -26,6 +27,9 @@
class DenonAVRToneControl(DenonAVRFoundation):
"""This class implements tone control functions of Denon AVR receiver."""

_support_tone_control: Optional[bool] = attr.ib(
converter=attr.converters.optional(bool), default=None
)
_tone_control_status: Optional[bool] = attr.ib(
converter=attr.converters.optional(convert_string_int_bool), default=None
)
Expand All @@ -44,22 +48,31 @@ class DenonAVRToneControl(DenonAVRFoundation):
_treble_level: Optional[str] = attr.ib(
converter=attr.converters.optional(str), default=None
)
_setup_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))

# Update tags for attributes
# AppCommand.xml interface
appcommand_attrs = {AppCommands.GetToneControl: None}

def setup(self) -> None:
async def async_setup(self) -> None:
"""Ensure that the instance is initialized."""
# Add tags for a potential AppCommand.xml update
for tag in self.appcommand_attrs:
self._device.api.add_appcommand_update_tag(tag)
async with self._setup_lock:
_LOGGER.debug("Starting tone control setup")

self._device.telnet_api.register_callback(
"PS", self._async_sound_detail_callback
)
# The first update determines if sound mode is supported
await self.async_update_tone_control()

# Add tags for a potential AppCommand.xml update
if self.support_tone_control:
for tag in self.appcommand_attrs:
self._device.api.add_appcommand_update_tag(tag)

self._device.telnet_api.register_callback(
"PS", self._async_sound_detail_callback
)

self._is_setup = True
self._is_setup = True
_LOGGER.debug("Finished tone control setup")

async def _async_sound_detail_callback(
self, zone: str, event: str, parameter: str
Expand Down Expand Up @@ -88,7 +101,7 @@ async def async_update(
_LOGGER.debug("Starting tone control update")
# Ensure instance is setup before updating
if not self._is_setup:
self.setup()
await self.async_setup()

# Update state
await self.async_update_tone_control(
Expand All @@ -105,17 +118,29 @@ async def async_update_tone_control(
"Device is not setup correctly, update method not set"
)

if self._is_setup and not self._support_tone_control:
return

# Tone control is only available for avr 2016 update
if self._device.use_avr_2016_update:
try:
await self.async_update_attrs_appcommand(
self.appcommand_attrs,
global_update=global_update,
cache_id=cache_id,
)
except AvrProcessingError as err:
# Don't raise an error here, because not all devices support it
_LOGGER.debug("Updating tone control failed: %s", err)
if not self._device.use_avr_2016_update:
self._support_tone_control = False
_LOGGER.info("Tone control not supported")
return

try:
await self.async_update_attrs_appcommand(
self.appcommand_attrs,
global_update=global_update,
cache_id=cache_id,
)
except (AvrProcessingError, AvrIncompleteResponseError):
self._support_tone_control = False
_LOGGER.info("Tone control not supported")
return

if not self._is_setup:
self._support_tone_control = True
_LOGGER.info("Tone control supported")

async def async_set_tone_control_command(
self, parameter_type: str, value: int
Expand All @@ -134,6 +159,11 @@ async def async_set_tone_control_command(
##############
# Properties #
##############
@property
def support_tone_control(self) -> Optional[bool]:
"""Return True if tone control is supported."""
return self._support_tone_control

@property
def tone_control_status(self) -> Optional[bool]:
"""Return value of tone control status."""
Expand Down
6 changes: 5 additions & 1 deletion tests/test_denonavr.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ def custom_matcher(self, request: httpx.Request, *args, **kwargs):
content_str = request.read().decode("utf-8")
if "GetFriendlyName" in content_str:
ep_suffix = "-setup"
else:
elif "GetAllZoneSource" in content_str:
ep_suffix = "-update"
elif "GetSurroundModeStatus" in content_str:
ep_suffix = "-update-soundmode"
else:
ep_suffix = "-update-tonecontrol"
content = get_sample_content(
f"{self.testing_receiver}-AppCommand{ep_suffix}{port_suffix}.xml"
)
Expand Down
6 changes: 6 additions & 0 deletions tests/xml/AV7703-AppCommand-update-soundmode-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<surround>Dolby Digital + + Neural:X </surround>
</cmd>
</rx>
11 changes: 11 additions & 0 deletions tests/xml/AV7703-AppCommand-update-tonecontrol-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<status>0</status>
<adjust></adjust>
<basslevel></basslevel>
<bassvalue></bassvalue>
<treblelevel></treblelevel>
<treblevalue></treblevalue>
</cmd>
</rx>
6 changes: 6 additions & 0 deletions tests/xml/AVC-8500H-AppCommand-update-soundmode-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<surround>DTS Neo:X Cinema </surround>
</cmd>
</rx>
11 changes: 11 additions & 0 deletions tests/xml/AVC-8500H-AppCommand-update-tonecontrol-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<status>0</status>
<adjust></adjust>
<basslevel></basslevel>
<bassvalue></bassvalue>
<treblelevel></treblelevel>
<treblevalue></treblevalue>
</cmd>
</rx>
6 changes: 6 additions & 0 deletions tests/xml/AVC-X3700H-AppCommand-update-soundmode-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<surround>Stereo </surround>
</cmd>
</rx>
11 changes: 11 additions & 0 deletions tests/xml/AVC-X3700H-AppCommand-update-tonecontrol-8080.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<status>0</status>
<adjust></adjust>
<basslevel></basslevel>
<bassvalue></bassvalue>
<treblelevel></treblelevel>
<treblevalue></treblevalue>
</cmd>
</rx>
6 changes: 6 additions & 0 deletions tests/xml/AVR-1713-AppCommand-update-soundmode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<cmd>
<surround>PLII Game </surround>
</cmd>
</rx>
4 changes: 4 additions & 0 deletions tests/xml/AVR-1713-AppCommand-update-tonecontrol.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8" ?>
<rx>
<error>2</error>
</rx>
3 changes: 3 additions & 0 deletions tests/xml/AVR-1912-AppCommand-update-soundmode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
3 changes: 3 additions & 0 deletions tests/xml/AVR-1912-AppCommand-update-tonecontrol.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
3 changes: 3 additions & 0 deletions tests/xml/AVR-2312CI-AppCommand-update-soundmode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
3 changes: 3 additions & 0 deletions tests/xml/AVR-2312CI-AppCommand-update-tonecontrol.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
3 changes: 3 additions & 0 deletions tests/xml/AVR-3311CI-AppCommand-update-soundmode.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
3 changes: 3 additions & 0 deletions tests/xml/AVR-3311CI-AppCommand-update-tonecontrol.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<html><head><title>Document Error: Data follows</title></head>
<body><h2>Access Error: Data follows</h2>
<p>Form Deviceinfo.xml is not defined</p></body></html>
Loading

0 comments on commit cd04edc

Please sign in to comment.