denonavr 0.11.5__py3-none-any.whl → 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
denonavr/foundation.py CHANGED
@@ -143,16 +143,19 @@ class DenonAVRDeviceInfo:
143
143
  async def async_setup(self) -> None:
144
144
  """Ensure that configuration is loaded from receiver asynchronously."""
145
145
  async with self._setup_lock:
146
- # Own setup
146
+ _LOGGER.debug("Starting device setup")
147
147
  # Reduce read timeout during receiver identification
148
148
  # deviceinfo endpoint takes very long to return 404
149
149
  timeout = self.api.timeout
150
150
  self.api.timeout = httpx.Timeout(self.api.timeout.connect)
151
151
  try:
152
+ _LOGGER.debug("Identifying receiver")
152
153
  await self.async_identify_receiver()
154
+ _LOGGER.debug("Getting device info")
153
155
  await self.async_get_device_info()
154
156
  finally:
155
157
  self.api.timeout = timeout
158
+ _LOGGER.debug("Identifying update method")
156
159
  await self.async_identify_update_method()
157
160
 
158
161
  # Add tags for a potential AppCommand.xml update
@@ -166,17 +169,20 @@ class DenonAVRDeviceInfo:
166
169
  self.telnet_api.register_callback(power_event, self._async_power_callback)
167
170
 
168
171
  self._is_setup = True
172
+ _LOGGER.debug("Finished device setup")
169
173
 
170
174
  async def async_update(
171
175
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
172
176
  ) -> None:
173
177
  """Update status asynchronously."""
178
+ _LOGGER.debug("Starting device update")
174
179
  # Ensure instance is setup before updating
175
180
  if not self._is_setup:
176
181
  await self.async_setup()
177
182
 
178
183
  # Update power status
179
184
  await self.async_update_power(global_update=global_update, cache_id=cache_id)
185
+ _LOGGER.debug("Finished device update")
180
186
 
181
187
  async def async_identify_receiver(self) -> None:
182
188
  """Identify receiver asynchronously."""
@@ -196,9 +202,9 @@ class DenonAVRDeviceInfo:
196
202
  )
197
203
  except (AvrTimoutError, AvrNetworkError) as err:
198
204
  _LOGGER.debug(
199
- "Connection error on port %s when identifying receiver",
205
+ "Connection error on port %s when identifying receiver: %s",
200
206
  r_type.port,
201
- exc_info=err,
207
+ err,
202
208
  )
203
209
 
204
210
  # Raise error only when occurred at both types
@@ -210,22 +216,32 @@ class DenonAVRDeviceInfo:
210
216
  _LOGGER.debug(
211
217
  (
212
218
  "Request error on port %s when identifying receiver, "
213
- "device is not a %s receivers"
219
+ "device is not a %s receiver: %s"
214
220
  ),
215
221
  r_type.port,
216
222
  r_type.type,
217
- exc_info=err,
223
+ err,
218
224
  )
219
225
  else:
220
226
  is_avr_x = self._is_avr_x(xml)
221
227
  if is_avr_x:
222
228
  self.receiver = r_type
229
+ _LOGGER.info(
230
+ "Identified %s receiver using port %s",
231
+ r_type.type,
232
+ r_type.port,
233
+ )
223
234
  # Receiver identified, return
224
235
  return
225
236
 
226
237
  # If check of Deviceinfo.xml was not successful, receiver is type AVR
227
238
  self.receiver = AVR
228
239
  self.api.port = AVR.port
240
+ _LOGGER.info(
241
+ "Identified %s receiver using port %s",
242
+ AVR.type,
243
+ AVR.port,
244
+ )
229
245
 
230
246
  @staticmethod
231
247
  def _is_avr_x(deviceinfo: ET.Element) -> bool:
@@ -275,13 +291,11 @@ class DenonAVRDeviceInfo:
275
291
  )
276
292
  except (AvrTimoutError, AvrNetworkError) as err:
277
293
  _LOGGER.debug(
278
- "Connection error when identifying update method", exc_info=err
294
+ "Connection error when identifying update method: %s", err
279
295
  )
280
296
  raise
281
297
  except AvrRequestError as err:
282
- _LOGGER.debug(
283
- "Request error when identifying update method", exc_info=err
284
- )
298
+ _LOGGER.debug("Request error when identifying update method: %s", err)
285
299
  self.use_avr_2016_update = False
286
300
  _LOGGER.info("AVR-X device, AppCommand.xml interface not supported")
287
301
  else:
@@ -294,11 +308,11 @@ class DenonAVRDeviceInfo:
294
308
  xml = await self.api.async_get_xml(self.urls.mainzone)
295
309
  except (AvrTimoutError, AvrNetworkError) as err:
296
310
  _LOGGER.debug(
297
- "Connection error when identifying update method", exc_info=err
311
+ "Connection error when identifying update method: %s", err
298
312
  )
299
313
  raise
300
314
  except AvrRequestError as err:
301
- _LOGGER.debug("Request error getting friendly name", exc_info=err)
315
+ _LOGGER.debug("Request error getting friendly name: %s", err)
302
316
  _LOGGER.info(
303
317
  "Receiver name could not be determined. Using standard"
304
318
  " name: Denon AVR"
@@ -320,7 +334,7 @@ class DenonAVRDeviceInfo:
320
334
  # Result is cached that it can be reused during update
321
335
  await self.api.async_get_global_appcommand(cache_id=cache_id)
322
336
  except (AvrTimoutError, AvrNetworkError) as err:
323
- _LOGGER.debug("Connection error when verifying update method", exc_info=err)
337
+ _LOGGER.debug("Connection error when verifying update method: %s", err)
324
338
  raise
325
339
  except AvrForbiddenError:
326
340
  # Recovery in case receiver changes port from 80 to 8080 which
@@ -338,7 +352,7 @@ class DenonAVRDeviceInfo:
338
352
  else:
339
353
  raise
340
354
  except AvrIncompleteResponseError as err:
341
- _LOGGER.debug("Request error when verifying update method", exc_info=err)
355
+ _LOGGER.debug("Request error when verifying update method: %s", err)
342
356
  # Only AVR_X devices support both interfaces
343
357
  if self.receiver == AVR_X:
344
358
  _LOGGER.warning(
@@ -378,10 +392,10 @@ class DenonAVRDeviceInfo:
378
392
  try:
379
393
  res = await self.api.async_get(command, port=port)
380
394
  except AvrTimoutError as err:
381
- _LOGGER.debug("Timeout when getting device info", exc_info=err)
395
+ _LOGGER.debug("Timeout when getting device info: %s", err)
382
396
  raise
383
397
  except AvrNetworkError as err:
384
- _LOGGER.debug("Network error getting device info", exc_info=err)
398
+ _LOGGER.debug("Network error getting device info: %s", err)
385
399
  raise
386
400
  except AvrRequestError as err:
387
401
  _LOGGER.error(
@@ -444,7 +458,7 @@ class DenonAVRDeviceInfo:
444
458
  self.urls.appcommand, tuple(power_appcommand), cache_id=cache_id
445
459
  )
446
460
  except AvrRequestError as err:
447
- _LOGGER.debug("Error when getting power status", exc_info=err)
461
+ _LOGGER.debug("Error when getting power status: %s", err)
448
462
  raise
449
463
 
450
464
  # Extract relevant information
@@ -482,7 +496,7 @@ class DenonAVRDeviceInfo:
482
496
  xml = await self.api.async_get_xml(url, cache_id=cache_id)
483
497
  except AvrRequestError as err:
484
498
  _LOGGER.debug(
485
- "Error when getting power status from url %s", url, exc_info=err
499
+ "Error when getting power status from url %s: %s", url, err
486
500
  )
487
501
  continue
488
502
 
@@ -535,6 +549,87 @@ class DenonAVRDeviceInfo:
535
549
  else:
536
550
  await self.api.async_get_command(self.urls.command_power_standby)
537
551
 
552
+ async def async_cursor_up(self) -> None:
553
+ """Cursor Up on receiver via HTTP get command."""
554
+ if self.telnet_available:
555
+ await self.telnet_api.async_send_commands(
556
+ self.telnet_commands.command_cusor_up
557
+ )
558
+ else:
559
+ await self.api.async_get_command(self.urls.command_cusor_up)
560
+
561
+ async def async_cursor_down(self) -> None:
562
+ """Cursor Down on receiver via HTTP get command."""
563
+ if self.telnet_available:
564
+ await self.telnet_api.async_send_commands(
565
+ self.telnet_commands.command_cusor_down
566
+ )
567
+ else:
568
+ await self.api.async_get_command(self.urls.command_cusor_down)
569
+
570
+ async def async_cursor_left(self) -> None:
571
+ """Cursor Left on receiver via HTTP get command."""
572
+ if self.telnet_available:
573
+ await self.telnet_api.async_send_commands(
574
+ self.telnet_commands.command_cusor_left
575
+ )
576
+ else:
577
+ await self.api.async_get_command(self.urls.command_cusor_left)
578
+
579
+ async def async_cursor_right(self) -> None:
580
+ """Cursor Right on receiver via HTTP get command."""
581
+ if self.telnet_available:
582
+ await self.telnet_api.async_send_commands(
583
+ self.telnet_commands.command_cusor_right
584
+ )
585
+ else:
586
+ await self.api.async_get_command(self.urls.command_cusor_right)
587
+
588
+ async def async_cursor_enter(self) -> None:
589
+ """Cursor Enter on receiver via HTTP get command."""
590
+ if self.telnet_available:
591
+ await self.telnet_api.async_send_commands(
592
+ self.telnet_commands.command_cusor_enter
593
+ )
594
+ else:
595
+ await self.api.async_get_command(self.urls.command_cusor_enter)
596
+
597
+ async def async_back(self) -> None:
598
+ """Back command on receiver via HTTP get command."""
599
+ if self.telnet_available:
600
+ await self.telnet_api.async_send_commands(self.telnet_commands.command_back)
601
+ else:
602
+ await self.api.async_get_command(self.urls.command_back)
603
+
604
+ async def async_info(self) -> None:
605
+ """Info OSD on receiver via HTTP get command."""
606
+ if self.telnet_available:
607
+ await self.telnet_api.async_send_commands(self.telnet_commands.command_info)
608
+ else:
609
+ await self.api.async_get_command(self.urls.command_info)
610
+
611
+ async def async_options(self) -> None:
612
+ """Options menu on receiver via HTTP get command."""
613
+ await self.api.async_get_command(self.urls.command_options)
614
+
615
+ async def async_settings_menu(self) -> None:
616
+ """Options menu on receiver via HTTP get command."""
617
+ res = await self.api.async_get_command(self.urls.command_setup_query)
618
+ if self.telnet_available:
619
+ if res is not None and res == "MNMEN ON":
620
+ await self.telnet_api.async_send_commands(
621
+ self.telnet_commands.command_setup_close
622
+ )
623
+ else:
624
+ await self.telnet_api.async_send_commands(
625
+ self.telnet_commands.command_setup_open
626
+ )
627
+ else:
628
+ if res is not None and res == "MNMEN ON":
629
+ await self.api.async_get_command(self.urls.command_setup_close)
630
+ else:
631
+ await self.api.async_get_command(self.urls.command_setup_open)
632
+
538
633
 
539
634
  @attr.s(auto_attribs=True, on_setattr=DENON_ATTR_SETATTR)
540
635
  class DenonAVRFoundation:
@@ -558,7 +653,6 @@ class DenonAVRFoundation:
558
653
  appcommand0300: bool = False,
559
654
  global_update: bool = False,
560
655
  cache_id: Optional[Hashable] = None,
561
- ignore_missing_response: bool = False,
562
656
  ):
563
657
  """Update attributes from AppCommand.xml."""
564
658
  # Copy that we do not accidently change the wrong dict
@@ -581,7 +675,7 @@ class DenonAVRFoundation:
581
675
  url, tags, cache_id=cache_id
582
676
  )
583
677
  except AvrRequestError as err:
584
- _LOGGER.debug("Error when getting status update", exc_info=err)
678
+ _LOGGER.debug("Error when getting status update: %s", err)
585
679
  raise
586
680
 
587
681
  # Extract relevant information
@@ -616,10 +710,10 @@ class DenonAVRFoundation:
616
710
 
617
711
  except (AttributeError, IndexError) as err:
618
712
  _LOGGER.debug(
619
- "Failed updating attribute %s for zone %s",
713
+ "Failed updating attribute %s for zone %s: %s",
620
714
  pattern.update_attribute,
621
715
  self._device.zone,
622
- exc_info=err,
716
+ err,
623
717
  )
624
718
 
625
719
  if start == success:
@@ -627,24 +721,17 @@ class DenonAVRFoundation:
627
721
  update_attrs.pop(app_command, None)
628
722
 
629
723
  # Check if each attribute was updated
630
- if update_attrs and not ignore_missing_response:
724
+ if update_attrs:
631
725
  raise AvrProcessingError(
632
726
  f"Some attributes of zone {self._device.zone} not found on update:"
633
727
  f" {update_attrs}"
634
728
  )
635
- if update_attrs and ignore_missing_response:
636
- _LOGGER.debug(
637
- "Some attributes of zone %s not found on update: %s",
638
- self._device.zone,
639
- update_attrs,
640
- )
641
729
 
642
730
  async def async_update_attrs_status_xml(
643
731
  self,
644
732
  update_attrs: Dict[str, str],
645
733
  urls: List[str],
646
734
  cache_id: Optional[Hashable] = None,
647
- ignore_missing_response: bool = False,
648
735
  ):
649
736
  """
650
737
  Update attributes from status xml.
@@ -664,7 +751,7 @@ class DenonAVRFoundation:
664
751
  xml = await self._device.api.async_get_xml(url, cache_id=cache_id)
665
752
  except AvrRequestError as err:
666
753
  _LOGGER.debug(
667
- "Error when getting status update from url %s", url, exc_info=err
754
+ "Error when getting status update from url %s: %s", url, err
668
755
  )
669
756
  continue
670
757
  attrs = deepcopy(update_attrs)
@@ -683,10 +770,10 @@ class DenonAVRFoundation:
683
770
 
684
771
  except (AttributeError, IndexError) as err:
685
772
  _LOGGER.debug(
686
- "Failed updating attribute %s for zone %s",
773
+ "Failed updating attribute %s for zone %s: %s",
687
774
  name,
688
775
  self._device.zone,
689
- exc_info=err,
776
+ err,
690
777
  )
691
778
 
692
779
  # All done, no need for continuing
@@ -694,7 +781,7 @@ class DenonAVRFoundation:
694
781
  break
695
782
 
696
783
  # Check if each attribute was updated
697
- if update_attrs and not ignore_missing_response:
784
+ if update_attrs:
698
785
  raise AvrProcessingError(
699
786
  f"Some attributes of zone {self._device.zone} not found on update:"
700
787
  f" {update_attrs}"
denonavr/input.py CHANGED
@@ -272,7 +272,8 @@ class DenonAVRInput(DenonAVRFoundation):
272
272
 
273
273
  def _update_netaudio(self) -> None:
274
274
  """Update netaudio information."""
275
- if self._device.telnet_api.send_commands("NSE"):
275
+ if self._device.telnet_available:
276
+ self._device.telnet_api.send_commands("NSE", skip_confirmation=True)
276
277
  self._schedule_netaudio_update()
277
278
  else:
278
279
  self._stop_media_update()
@@ -314,7 +315,10 @@ class DenonAVRInput(DenonAVRFoundation):
314
315
 
315
316
  def _update_tuner(self) -> None:
316
317
  """Update tuner information."""
317
- if self._device.telnet_api.send_commands("TFAN?", "TFANNAME?"):
318
+ if self._device.telnet_available:
319
+ self._device.telnet_api.send_commands(
320
+ "TFAN?", "TFANNAME?", skip_confirmation=True
321
+ )
318
322
  self._schedule_tuner_update()
319
323
  else:
320
324
  self._stop_media_update()
@@ -357,7 +361,8 @@ class DenonAVRInput(DenonAVRFoundation):
357
361
 
358
362
  def _update_hdtuner(self) -> None:
359
363
  """Update HD tuner information."""
360
- if self._device.telnet_api.send_commands("HD?"):
364
+ if self._device.telnet_available:
365
+ self._device.telnet_api.send_commands("HD?", skip_confirmation=True)
361
366
  self._schedule_hdtuner_update()
362
367
  else:
363
368
  self._stop_media_update()
@@ -402,18 +407,23 @@ class DenonAVRInput(DenonAVRFoundation):
402
407
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
403
408
  ) -> None:
404
409
  """Update input functions asynchronously."""
410
+ _LOGGER.debug("Starting input update")
405
411
  # Ensure instance is setup before updating
406
412
  if not self._is_setup:
407
413
  self.setup()
408
414
 
409
415
  # Update input functions
416
+ _LOGGER.debug("Updating input functions")
410
417
  await self.async_update_inputfuncs(
411
418
  global_update=global_update, cache_id=cache_id
412
419
  )
413
420
  # Update state
421
+ _LOGGER.debug("Updating input state")
414
422
  await self.async_update_state(global_update=global_update, cache_id=cache_id)
415
423
  # Update media state
424
+ _LOGGER.debug("Updating media state")
416
425
  await self.async_update_media_state(cache_id=cache_id)
426
+ _LOGGER.debug("Finished input update")
417
427
 
418
428
  async def async_get_sources_deviceinfo(self) -> Dict[str, str]:
419
429
  """Get sources from Deviceinfo.xml."""
@@ -423,7 +433,7 @@ class DenonAVRInput(DenonAVRFoundation):
423
433
  self._device.urls.deviceinfo, cache_id=id(self._device)
424
434
  )
425
435
  except AvrRequestError as err:
426
- _LOGGER.debug("Error when getting sources", exc_info=err)
436
+ _LOGGER.debug("Error when getting sources: %s", err)
427
437
  raise
428
438
 
429
439
  receiver_sources = {}
@@ -481,7 +491,7 @@ class DenonAVRInput(DenonAVRFoundation):
481
491
  self._device.urls.appcommand, tags, cache_id=cache_id
482
492
  )
483
493
  except AvrRequestError as err:
484
- _LOGGER.debug("Error when getting changed sources", exc_info=err)
494
+ _LOGGER.debug("Error when getting changed sources: %s", err)
485
495
  raise
486
496
 
487
497
  for child in xml.findall(
@@ -544,7 +554,7 @@ class DenonAVRInput(DenonAVRFoundation):
544
554
  f" {self._device.receiver.type}"
545
555
  )
546
556
  except AvrRequestError as err:
547
- _LOGGER.debug("Error when getting changed sources", exc_info=err)
557
+ _LOGGER.debug("Error when getting changed sources: %s", err)
548
558
  raise
549
559
 
550
560
  # Get the relevant tags from XML structure
denonavr/soundmode.py CHANGED
@@ -16,14 +16,8 @@ from typing import Dict, List, Optional
16
16
  import attr
17
17
 
18
18
  from .appcommand import AppCommands
19
- from .const import (
20
- ALL_ZONE_STEREO,
21
- AVR_X,
22
- AVR_X_2016,
23
- DENON_ATTR_SETATTR,
24
- SOUND_MODE_MAPPING,
25
- )
26
- from .exceptions import AvrCommandError, AvrProcessingError
19
+ from .const import ALL_ZONE_STEREO, DENON_ATTR_SETATTR, SOUND_MODE_MAPPING
20
+ from .exceptions import AvrCommandError, AvrIncompleteResponseError, AvrProcessingError
27
21
  from .foundation import DenonAVRFoundation
28
22
 
29
23
  _LOGGER = logging.getLogger(__name__)
@@ -94,6 +88,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
94
88
  init=False,
95
89
  )
96
90
  _setup_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))
91
+ _appcommand_active: bool = attr.ib(converter=bool, default=True, init=False)
97
92
 
98
93
  # Update tags for attributes
99
94
  # AppCommand.xml interface
@@ -105,22 +100,22 @@ class DenonAVRSoundMode(DenonAVRFoundation):
105
100
  async def async_setup(self) -> None:
106
101
  """Ensure that the instance is initialized."""
107
102
  async with self._setup_lock:
108
- # Add tags for a potential AppCommand.xml update
109
- for tag in self.appcommand_attrs:
110
- self._device.api.add_appcommand_update_tag(tag)
111
-
112
- # Soundmode is always available for AVR-X and AVR-X-2016 receivers
113
- # For AVR receiver it will be tested during the first update
114
- if self._device.receiver in [AVR_X, AVR_X_2016]:
115
- self._support_sound_mode = True
116
- else:
117
- await self.async_update_sound_mode()
103
+ _LOGGER.debug("Starting sound mode setup")
104
+
105
+ # The first update determines if sound mode is supported
106
+ await self.async_update_sound_mode()
107
+
108
+ if self._support_sound_mode and self._appcommand_active:
109
+ # Add tags for a potential AppCommand.xml update
110
+ for tag in self.appcommand_attrs:
111
+ self._device.api.add_appcommand_update_tag(tag)
118
112
 
119
113
  self._device.telnet_api.register_callback(
120
114
  "MS", self._async_soundmode_callback
121
115
  )
122
116
 
123
117
  self._is_setup = True
118
+ _LOGGER.debug("Finished sound mode setup")
124
119
 
125
120
  async def _async_soundmode_callback(
126
121
  self, zone: str, event: str, parameter: str
@@ -135,6 +130,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
135
130
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
136
131
  ) -> None:
137
132
  """Update sound mode asynchronously."""
133
+ _LOGGER.debug("Starting sound mode update")
138
134
  # Ensure instance is setup before updating
139
135
  if not self._is_setup:
140
136
  await self.async_setup()
@@ -143,6 +139,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
143
139
  await self.async_update_sound_mode(
144
140
  global_update=global_update, cache_id=cache_id
145
141
  )
142
+ _LOGGER.debug("Finished sound mode update")
146
143
 
147
144
  async def async_update_sound_mode(
148
145
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
@@ -153,29 +150,47 @@ class DenonAVRSoundMode(DenonAVRFoundation):
153
150
  "Device is not setup correctly, update method not set"
154
151
  )
155
152
 
156
- if self._device.use_avr_2016_update:
157
- await self.async_update_attrs_appcommand(
158
- self.appcommand_attrs, global_update=global_update, cache_id=cache_id
159
- )
160
- else:
161
- urls = [self._device.urls.status, self._device.urls.mainzone]
162
- if self._is_setup and not self._support_sound_mode:
153
+ if self._is_setup and not self._support_sound_mode:
154
+ return
155
+
156
+ if self._device.use_avr_2016_update and self._appcommand_active:
157
+ try:
158
+ await self.async_update_attrs_appcommand(
159
+ self.appcommand_attrs,
160
+ global_update=global_update,
161
+ cache_id=cache_id,
162
+ )
163
+ except (AvrProcessingError, AvrIncompleteResponseError):
164
+ self._appcommand_active = False
165
+ _LOGGER.debug(
166
+ "Appcommand.xml does not support Sound mode. "
167
+ "Testing status.xml interface next"
168
+ )
169
+ else:
170
+ if not self._is_setup:
171
+ self._support_sound_mode = True
172
+ _LOGGER.info("Sound mode supported")
163
173
  return
164
- # There are two different options of sound mode tags
174
+
175
+ urls = [self._device.urls.status, self._device.urls.mainzone]
176
+ # There are two different options of sound mode tags
177
+ try:
178
+ await self.async_update_attrs_status_xml(
179
+ self.status_xml_attrs_01, urls, cache_id=cache_id
180
+ )
181
+ except AvrProcessingError:
165
182
  try:
166
183
  await self.async_update_attrs_status_xml(
167
- self.status_xml_attrs_01, urls, cache_id=cache_id
184
+ self.status_xml_attrs_02, urls, cache_id=cache_id
168
185
  )
169
186
  except AvrProcessingError:
170
- try:
171
- await self.async_update_attrs_status_xml(
172
- self.status_xml_attrs_02, urls, cache_id=cache_id
173
- )
174
- except AvrProcessingError:
175
- _LOGGER.info("Sound mode not supported")
176
- self._support_sound_mode = False
177
- return
187
+ self._support_sound_mode = False
188
+ _LOGGER.info("Sound mode not supported")
189
+ return
190
+
191
+ if not self._is_setup:
178
192
  self._support_sound_mode = True
193
+ _LOGGER.info("Sound mode supported")
179
194
 
180
195
  def match_sound_mode(self) -> Optional[str]:
181
196
  """Match the raw_sound_mode to its corresponding sound_mode."""
@@ -248,7 +263,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
248
263
  ##############
249
264
  @property
250
265
  def support_sound_mode(self) -> Optional[bool]:
251
- """Return True if sound mode supported."""
266
+ """Return True if sound mode is supported."""
252
267
  return self._support_sound_mode
253
268
 
254
269
  @property