diff --git a/homeassistant/components/denonavr/__init__.py b/homeassistant/components/denonavr/__init__.py index fa4d16126973..853ade1f8a63 100644 --- a/homeassistant/components/denonavr/__init__.py +++ b/homeassistant/components/denonavr/__init__.py @@ -11,10 +11,12 @@ from homeassistant.helpers.httpx_client import get_async_client from .config_flow import ( CONF_SHOW_ALL_SOURCES, + CONF_UPDATE_AUDYSSEY, CONF_ZONE2, CONF_ZONE3, DEFAULT_SHOW_SOURCES, DEFAULT_TIMEOUT, + DEFAULT_UPDATE_AUDYSSEY, DEFAULT_ZONE2, DEFAULT_ZONE3, DOMAIN, @@ -53,6 +55,9 @@ async def async_setup_entry( hass.data[DOMAIN][entry.entry_id] = { CONF_RECEIVER: receiver, + CONF_UPDATE_AUDYSSEY: entry.options.get( + CONF_UPDATE_AUDYSSEY, DEFAULT_UPDATE_AUDYSSEY + ), UNDO_UPDATE_LISTENER: undo_listener, } diff --git a/homeassistant/components/denonavr/config_flow.py b/homeassistant/components/denonavr/config_flow.py index adcd4e26b6f7..695c323e1f79 100644 --- a/homeassistant/components/denonavr/config_flow.py +++ b/homeassistant/components/denonavr/config_flow.py @@ -30,11 +30,13 @@ CONF_ZONE3 = "zone3" CONF_MODEL = "model" CONF_MANUFACTURER = "manufacturer" CONF_SERIAL_NUMBER = "serial_number" +CONF_UPDATE_AUDYSSEY = "update_audyssey" DEFAULT_SHOW_SOURCES = False DEFAULT_TIMEOUT = 5 DEFAULT_ZONE2 = False DEFAULT_ZONE3 = False +DEFAULT_UPDATE_AUDYSSEY = False CONFIG_SCHEMA = vol.Schema({vol.Optional(CONF_HOST): str}) @@ -67,6 +69,12 @@ class OptionsFlowHandler(config_entries.OptionsFlow): CONF_ZONE3, default=self.config_entry.options.get(CONF_ZONE3, DEFAULT_ZONE3), ): bool, + vol.Optional( + CONF_UPDATE_AUDYSSEY, + default=self.config_entry.options.get( + CONF_UPDATE_AUDYSSEY, DEFAULT_UPDATE_AUDYSSEY + ), + ): bool, } ) diff --git a/homeassistant/components/denonavr/media_player.py b/homeassistant/components/denonavr/media_player.py index d7e0f8510dd5..254b7ffb02cd 100644 --- a/homeassistant/components/denonavr/media_player.py +++ b/homeassistant/components/denonavr/media_player.py @@ -45,12 +45,15 @@ from .config_flow import ( CONF_MODEL, CONF_SERIAL_NUMBER, CONF_TYPE, + CONF_UPDATE_AUDYSSEY, + DEFAULT_UPDATE_AUDYSSEY, DOMAIN, ) _LOGGER = logging.getLogger(__name__) ATTR_SOUND_MODE_RAW = "sound_mode_raw" +ATTR_DYNAMIC_EQ = "dynamic_eq" SUPPORT_DENON = ( SUPPORT_VOLUME_STEP @@ -75,6 +78,8 @@ PARALLEL_UPDATES = 1 # Services SERVICE_GET_COMMAND = "get_command" +SERVICE_SET_DYNAMIC_EQ = "set_dynamic_eq" +SERVICE_UPDATE_AUDYSSEY = "update_audyssey" async def async_setup_entry( @@ -84,14 +89,23 @@ async def async_setup_entry( ): """Set up the DenonAVR receiver from a config entry.""" entities = [] - receiver = hass.data[DOMAIN][config_entry.entry_id][CONF_RECEIVER] + data = hass.data[DOMAIN][config_entry.entry_id] + receiver = data[CONF_RECEIVER] + update_audyssey = data.get(CONF_UPDATE_AUDYSSEY, DEFAULT_UPDATE_AUDYSSEY) for receiver_zone in receiver.zones.values(): if config_entry.data[CONF_SERIAL_NUMBER] is not None: unique_id = f"{config_entry.unique_id}-{receiver_zone.zone}" else: unique_id = f"{config_entry.entry_id}-{receiver_zone.zone}" await receiver_zone.async_setup() - entities.append(DenonDevice(receiver_zone, unique_id, config_entry)) + entities.append( + DenonDevice( + receiver_zone, + unique_id, + config_entry, + update_audyssey, + ) + ) _LOGGER.debug( "%s receiver at host %s initialized", receiver.manufacturer, receiver.host ) @@ -103,6 +117,16 @@ async def async_setup_entry( {vol.Required(ATTR_COMMAND): cv.string}, f"async_{SERVICE_GET_COMMAND}", ) + platform.async_register_entity_service( + SERVICE_SET_DYNAMIC_EQ, + {vol.Required(ATTR_DYNAMIC_EQ): cv.boolean}, + f"async_{SERVICE_SET_DYNAMIC_EQ}", + ) + platform.async_register_entity_service( + SERVICE_UPDATE_AUDYSSEY, + {}, + f"async_{SERVICE_UPDATE_AUDYSSEY}", + ) async_add_entities(entities, update_before_add=True) @@ -115,11 +139,13 @@ class DenonDevice(MediaPlayerEntity): receiver: DenonAVR, unique_id: str, config_entry: config_entries.ConfigEntry, + update_audyssey: bool, ): """Initialize the device.""" self._receiver = receiver self._unique_id = unique_id self._config_entry = config_entry + self._update_audyssey = update_audyssey self._supported_features_base = SUPPORT_DENON self._supported_features_base |= ( @@ -194,6 +220,8 @@ class DenonDevice(MediaPlayerEntity): async def async_update(self) -> None: """Get the latest status information from device.""" await self._receiver.async_update() + if self._update_audyssey: + await self._receiver.async_update_audyssey() @property def available(self): @@ -350,13 +378,22 @@ class DenonDevice(MediaPlayerEntity): @property def extra_state_attributes(self): """Return device specific state attributes.""" + if self._receiver.power != POWER_ON: + return {} + state_attributes = {} if ( self._receiver.sound_mode_raw is not None and self._receiver.support_sound_mode - and self._receiver.power == POWER_ON ): - return {ATTR_SOUND_MODE_RAW: self._receiver.sound_mode_raw} - return {} + state_attributes[ATTR_SOUND_MODE_RAW] = self._receiver.sound_mode_raw + if self._receiver.dynamic_eq is not None: + state_attributes[ATTR_DYNAMIC_EQ] = self._receiver.dynamic_eq + return state_attributes + + @property + def dynamic_eq(self): + """Status of DynamicEQ.""" + return self._receiver.dynamic_eq @async_log_errors async def async_media_play_pause(self): @@ -436,6 +473,23 @@ class DenonDevice(MediaPlayerEntity): """Send generic command.""" return await self._receiver.async_get_command(command) + @async_log_errors + async def async_update_audyssey(self): + """Get the latest audyssey information from device.""" + await self._receiver.async_update_audyssey() + + @async_log_errors + async def async_set_dynamic_eq(self, dynamic_eq: bool): + """Turn DynamicEQ on or off.""" + if dynamic_eq: + result = await self._receiver.async_dynamic_eq_on() + else: + result = await self._receiver.async_dynamic_eq_off() + + if self._update_audyssey: + await self._receiver.async_update_audyssey() + return result + # Decorator defined before is a staticmethod async_log_errors = staticmethod( # pylint: disable=no-staticmethod-decorator async_log_errors diff --git a/homeassistant/components/denonavr/services.yaml b/homeassistant/components/denonavr/services.yaml index 62157426bb22..d79652dd1f8a 100644 --- a/homeassistant/components/denonavr/services.yaml +++ b/homeassistant/components/denonavr/services.yaml @@ -9,3 +9,22 @@ get_command: command: description: Endpoint of the command, including associated parameters. example: "/goform/formiPhoneAppDirect.xml?RCKSK0410370" +set_dynamic_eq: + description: "Enable or disable DynamicEQ." + target: + entity: + integration: denonavr + domain: media_player + fields: + dynamic_eq: + description: "True/false for enable/disable." + default: true + example: true + selector: + boolean: +update_audyssey: + description: "Update Audyssey settings." + target: + entity: + integration: denonavr + domain: media_player diff --git a/homeassistant/components/denonavr/strings.json b/homeassistant/components/denonavr/strings.json index c754c9060626..5e5c7665a47d 100644 --- a/homeassistant/components/denonavr/strings.json +++ b/homeassistant/components/denonavr/strings.json @@ -40,7 +40,8 @@ "data": { "show_all_sources": "Show all sources", "zone2": "Set up Zone 2", - "zone3": "Set up Zone 3" + "zone3": "Set up Zone 3", + "update_audyssey": "Update Audyssey settings" } } } diff --git a/homeassistant/components/denonavr/translations/en.json b/homeassistant/components/denonavr/translations/en.json index 8c8f26d9b8cd..b39a5608f81c 100644 --- a/homeassistant/components/denonavr/translations/en.json +++ b/homeassistant/components/denonavr/translations/en.json @@ -38,7 +38,8 @@ "data": { "show_all_sources": "Show all sources", "zone2": "Set up Zone 2", - "zone3": "Set up Zone 3" + "zone3": "Set up Zone 3", + "update_audyssey": "Update Audyssey settings" }, "description": "Specify optional settings", "title": "Denon AVR Network Receivers" diff --git a/tests/components/denonavr/test_config_flow.py b/tests/components/denonavr/test_config_flow.py index 74ce77f1db76..b38c43775f93 100644 --- a/tests/components/denonavr/test_config_flow.py +++ b/tests/components/denonavr/test_config_flow.py @@ -11,6 +11,7 @@ from homeassistant.components.denonavr.config_flow import ( CONF_SERIAL_NUMBER, CONF_SHOW_ALL_SOURCES, CONF_TYPE, + CONF_UPDATE_AUDYSSEY, CONF_ZONE2, CONF_ZONE3, DOMAIN, @@ -28,6 +29,7 @@ TEST_IGNORED_MODEL = "HEOS 7" TEST_RECEIVER_TYPE = "avr-x" TEST_SERIALNUMBER = "123456789" TEST_MANUFACTURER = "Denon" +TEST_UPDATE_AUDYSSEY = False TEST_SSDP_LOCATION = f"http://{TEST_HOST}/" TEST_UNIQUE_ID = f"{TEST_MODEL}-{TEST_SERIALNUMBER}" TEST_DISCOVER_1_RECEIVER = [{CONF_HOST: TEST_HOST}] @@ -397,6 +399,7 @@ async def test_options_flow(hass): CONF_TYPE: TEST_RECEIVER_TYPE, CONF_MANUFACTURER: TEST_MANUFACTURER, CONF_SERIAL_NUMBER: TEST_SERIALNUMBER, + CONF_UPDATE_AUDYSSEY: TEST_UPDATE_AUDYSSEY, }, title=TEST_NAME, ) @@ -420,6 +423,7 @@ async def test_options_flow(hass): CONF_SHOW_ALL_SOURCES: True, CONF_ZONE2: True, CONF_ZONE3: True, + CONF_UPDATE_AUDYSSEY: False, } diff --git a/tests/components/denonavr/test_media_player.py b/tests/components/denonavr/test_media_player.py index 71c873a2b9d7..0607e7d42f7f 100644 --- a/tests/components/denonavr/test_media_player.py +++ b/tests/components/denonavr/test_media_player.py @@ -13,7 +13,10 @@ from homeassistant.components.denonavr.config_flow import ( ) from homeassistant.components.denonavr.media_player import ( ATTR_COMMAND, + ATTR_DYNAMIC_EQ, SERVICE_GET_COMMAND, + SERVICE_SET_DYNAMIC_EQ, + SERVICE_UPDATE_AUDYSSEY, ) from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST @@ -94,3 +97,41 @@ async def test_get_command(hass, client): await hass.async_block_till_done() client.async_get_command.assert_awaited_with("test_command") + + +async def test_dynamic_eq(hass, client): + """Test that dynamic eq method works.""" + await setup_denonavr(hass) + + data = { + ATTR_ENTITY_ID: ENTITY_ID, + ATTR_DYNAMIC_EQ: True, + } + # Verify on call + await hass.services.async_call(DOMAIN, SERVICE_SET_DYNAMIC_EQ, data) + await hass.async_block_till_done() + + # Verify off call + data[ATTR_DYNAMIC_EQ] = False + await hass.services.async_call(DOMAIN, SERVICE_SET_DYNAMIC_EQ, data) + await hass.async_block_till_done() + + client.async_dynamic_eq_on.assert_called_once() + client.async_dynamic_eq_off.assert_called_once() + + +async def test_update_audyssey(hass, client): + """Test that dynamic eq method works.""" + await setup_denonavr(hass) + + # Verify call + await hass.services.async_call( + DOMAIN, + SERVICE_UPDATE_AUDYSSEY, + { + ATTR_ENTITY_ID: ENTITY_ID, + }, + ) + await hass.async_block_till_done() + + client.async_update_audyssey.assert_called_once()