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/decorators.py CHANGED
@@ -7,13 +7,12 @@ This module implements the REST API to Denon AVR receivers.
7
7
  :license: MIT, see LICENSE for more details.
8
8
  """
9
9
 
10
- import asyncio
11
10
  import inspect
12
11
  import logging
13
12
  import time
14
13
  import xml.etree.ElementTree as ET
15
14
  from functools import wraps
16
- from typing import Callable, Coroutine, TypeVar
15
+ from typing import Callable, TypeVar
17
16
 
18
17
  import httpx
19
18
  from asyncstdlib import lru_cache
@@ -46,26 +45,21 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
46
45
  try:
47
46
  return await func(*args, **kwargs)
48
47
  except httpx.HTTPStatusError as err:
49
- _LOGGER.debug("HTTP status error on request %s", err.request, exc_info=True)
48
+ _LOGGER.debug("HTTP status error on request %s: %s", err.request, err)
50
49
  # Separate handling of 403 errors
51
50
  if err.response.status_code == 403:
52
51
  raise AvrForbiddenError(f"HTTPStatusError: {err}", err.request) from err
53
52
  raise AvrRequestError(f"HTTPStatusError: {err}", err.request) from err
54
53
  except httpx.TimeoutException as err:
55
- _LOGGER.debug(
56
- "HTTP timeout exception on request %s", err.request, exc_info=True
57
- )
54
+ _LOGGER.debug("HTTP timeout exception on request %s: %s", err.request, err)
58
55
  raise AvrTimoutError(f"TimeoutException: {err}", err.request) from err
59
56
  except httpx.NetworkError as err:
60
- _LOGGER.debug(
61
- "Network error exception on request %s", err.request, exc_info=True
62
- )
57
+ _LOGGER.debug("Network error exception on request %s: %s", err.request, err)
63
58
  raise AvrNetworkError(f"NetworkError: {err}", err.request) from err
64
59
  except httpx.RemoteProtocolError as err:
65
60
  _LOGGER.debug(
66
61
  "Remote protocol error exception on request %s",
67
62
  err.request,
68
- exc_info=True,
69
63
  )
70
64
  raise AvrInvalidResponseError(
71
65
  f"RemoteProtocolError: {err}", err.request
@@ -77,7 +71,7 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
77
71
  UnicodeDecodeError,
78
72
  ) as err:
79
73
  _LOGGER.debug(
80
- "Defusedxml parse error on request %s", (args, kwargs), exc_info=True
74
+ "Defusedxml parse error on request %s: %s", (args, kwargs), err
81
75
  )
82
76
  raise AvrInvalidResponseError(
83
77
  f"XMLParseError: {err}", (args, kwargs)
@@ -110,42 +104,8 @@ def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
110
104
  try:
111
105
  return await cached_func(*args, **kwargs)
112
106
  except Exception as err:
113
- _LOGGER.debug("Exception %s raised, clearing cache", err)
107
+ _LOGGER.debug("Exception raised, clearing cache: %s", err)
114
108
  cached_func.cache_clear()
115
109
  raise
116
110
 
117
111
  return wrapper
118
-
119
-
120
- def run_async_synchronously(async_func: Coroutine) -> Callable:
121
- """
122
- Decorate to run the configured asynchronous function synchronously instead.
123
-
124
- If available the corresponding function with async_ prefix is called in an
125
- own event loop. This is not efficient but it ensures backwards
126
- compatibility of this library.
127
- """
128
-
129
- def decorator(func: Callable):
130
- # Check if function is a coroutine
131
- if not inspect.iscoroutinefunction(async_func):
132
- raise AttributeError(f"Function {async_func} is not a coroutine function")
133
- # Check if the signature of both functions is equal
134
- if inspect.signature(func) != inspect.signature(async_func):
135
- raise AttributeError(
136
- f"Functions {func} and {async_func} have different signatures"
137
- )
138
-
139
- @wraps(func)
140
- def wrapper(*args, **kwargs):
141
- # Run async function in own event loop
142
- loop = asyncio.new_event_loop()
143
-
144
- try:
145
- return loop.run_until_complete(async_func(*args, **kwargs))
146
- finally:
147
- loop.close()
148
-
149
- return wrapper
150
-
151
- return decorator
denonavr/denonavr.py CHANGED
@@ -17,7 +17,6 @@ import httpx
17
17
 
18
18
  from .audyssey import DenonAVRAudyssey, audyssey_factory
19
19
  from .const import DENON_ATTR_SETATTR, MAIN_ZONE, VALID_ZONES
20
- from .decorators import run_async_synchronously
21
20
  from .exceptions import AvrCommandError
22
21
  from .foundation import DenonAVRFoundation, set_api_host, set_api_timeout
23
22
  from .input import DenonAVRInput, input_factory
@@ -138,6 +137,7 @@ class DenonAVR(DenonAVRFoundation):
138
137
  async def async_setup(self) -> None:
139
138
  """Ensure that configuration is loaded from receiver asynchronously."""
140
139
  async with self._setup_lock:
140
+ _LOGGER.debug("Starting denonavr setup")
141
141
  # Device setup
142
142
  await self._device.async_setup()
143
143
  if self._name is None:
@@ -146,7 +146,7 @@ class DenonAVR(DenonAVRFoundation):
146
146
  # Setup other functions
147
147
  self.input.setup()
148
148
  await self.soundmode.async_setup()
149
- self.tonecontrol.setup()
149
+ await self.tonecontrol.async_setup()
150
150
  self.vol.setup()
151
151
  self.audyssey.setup()
152
152
 
@@ -155,10 +155,7 @@ class DenonAVR(DenonAVRFoundation):
155
155
  await zone_item.async_setup()
156
156
 
157
157
  self._is_setup = True
158
-
159
- @run_async_synchronously(async_func=async_setup)
160
- def setup(self) -> None:
161
- """Ensure that configuration is loaded from receiver."""
158
+ _LOGGER.debug("Finished denonavr setup")
162
159
 
163
160
  async def async_update(self):
164
161
  """
@@ -166,6 +163,7 @@ class DenonAVR(DenonAVRFoundation):
166
163
 
167
164
  Method executes the update method for the current receiver type.
168
165
  """
166
+ _LOGGER.debug("Starting denonavr update")
169
167
  # Ensure that the device is setup
170
168
  if not self._is_setup:
171
169
  await self.async_setup()
@@ -174,6 +172,7 @@ class DenonAVR(DenonAVRFoundation):
174
172
  cache_id = time.time()
175
173
 
176
174
  # Verify update method
175
+ _LOGGER.debug("Verifying update method")
177
176
  await self._device.async_verify_avr_2016_update_method(cache_id=cache_id)
178
177
 
179
178
  # Update device
@@ -189,43 +188,20 @@ class DenonAVR(DenonAVRFoundation):
189
188
  # into main update
190
189
  # await self.audyssey.async_update(
191
190
  # global_update=True, cache_id=cache_id)
192
-
193
- @run_async_synchronously(async_func=async_update)
194
- def update(self):
195
- """
196
- Get the latest status information from device.
197
-
198
- Method executes the update method for the current receiver type.
199
- """
191
+ _LOGGER.debug("Finished denonavr update")
200
192
 
201
193
  async def async_update_tonecontrol(self):
202
194
  """Get Tonecontrol settings."""
203
195
  await self.tonecontrol.async_update()
204
196
 
205
- @run_async_synchronously(async_func=async_update_tonecontrol)
206
- def update_tonecontrol(self):
207
- """Get Tonecontrol settings."""
208
-
209
197
  async def async_update_audyssey(self):
210
198
  """Get Audyssey settings."""
211
199
  await self.audyssey.async_update()
212
200
 
213
- @run_async_synchronously(async_func=async_update_audyssey)
214
- def update_audyssey(self):
215
- """Get Audyssey settings."""
216
-
217
201
  async def async_get_command(self, request: str) -> str:
218
202
  """Send HTTP GET command to Denon AVR receiver asynchronously."""
219
203
  return await self._device.api.async_get_command(request)
220
204
 
221
- @run_async_synchronously(async_func=async_get_command)
222
- def get_command(self, request: str) -> str:
223
- """Send HTTP GET command to Denon AVR receiver."""
224
-
225
- @run_async_synchronously(async_func=async_get_command)
226
- def send_get_command(self, request: str) -> str:
227
- """Send HTTP GET command to Denon AVR receiver...for compatibility."""
228
-
229
205
  async def async_send_telnet_commands(self, *commands: str) -> None:
230
206
  """Send telnet commands to the receiver."""
231
207
  await self._device.telnet_api.async_send_commands(*commands)
@@ -344,7 +320,7 @@ class DenonAVR(DenonAVRFoundation):
344
320
 
345
321
  @property
346
322
  def support_sound_mode(self) -> Optional[bool]:
347
- """Return True if sound mode supported."""
323
+ """Return True if sound mode is supported."""
348
324
  return self.soundmode.support_sound_mode
349
325
 
350
326
  @property
@@ -459,6 +435,11 @@ class DenonAVR(DenonAVRFoundation):
459
435
  """Indicate if all inputs are shown or just active one."""
460
436
  return self._show_all_inputs
461
437
 
438
+ @property
439
+ def support_tone_control(self) -> Optional[bool]:
440
+ """Return True if tone control is supported."""
441
+ return self.tonecontrol.support_tone_control
442
+
462
443
  @property
463
444
  def tone_control_status(self) -> Optional[bool]:
464
445
  """Return value of tone control status."""
@@ -544,50 +525,26 @@ class DenonAVR(DenonAVRFoundation):
544
525
  """Turn DynamicEQ off."""
545
526
  await self.audyssey.async_dynamiceq_off()
546
527
 
547
- @run_async_synchronously(async_func=async_dynamic_eq_off)
548
- def dynamic_eq_off(self) -> None:
549
- """Turn DynamicEQ off."""
550
-
551
528
  async def async_dynamic_eq_on(self) -> None:
552
529
  """Turn DynamicEQ on."""
553
530
  await self.audyssey.async_dynamiceq_on()
554
531
 
555
- @run_async_synchronously(async_func=async_dynamic_eq_on)
556
- def dynamic_eq_on(self) -> None:
557
- """Turn DynamicEQ on."""
558
-
559
532
  async def async_toggle_dynamic_eq(self) -> None:
560
533
  """Toggle DynamicEQ."""
561
534
  await self.audyssey.async_toggle_dynamic_eq()
562
535
 
563
- @run_async_synchronously(async_func=async_toggle_dynamic_eq)
564
- def toggle_dynamic_eq(self) -> None:
565
- """Toggle DynamicEQ."""
566
-
567
536
  async def async_set_multieq(self, value: str) -> None:
568
537
  """Set MultiEQ mode."""
569
538
  await self.audyssey.async_set_multieq(value)
570
539
 
571
- @run_async_synchronously(async_func=async_set_multieq)
572
- def set_multieq(self, value: str) -> None:
573
- """Set MultiEQ mode."""
574
-
575
540
  async def async_set_reflevoffset(self, value: str) -> None:
576
541
  """Set Reference Level Offset."""
577
542
  await self.audyssey.async_set_reflevoffset(value)
578
543
 
579
- @run_async_synchronously(async_func=async_set_reflevoffset)
580
- def set_reflevoffset(self, value: str) -> None:
581
- """Set Reference Level Offset."""
582
-
583
544
  async def async_set_dynamicvol(self, value: str) -> None:
584
545
  """Set Dynamic Volume."""
585
546
  await self.audyssey.async_set_dynamicvol(value)
586
547
 
587
- @run_async_synchronously(async_func=async_set_dynamicvol)
588
- def set_dynamicvol(self, value: str) -> None:
589
- """Set Dynamic Volume."""
590
-
591
548
  async def async_set_input_func(self, input_func: str) -> None:
592
549
  """
593
550
  Set input_func of device.
@@ -597,15 +554,6 @@ class DenonAVR(DenonAVRFoundation):
597
554
  """
598
555
  await self.input.async_set_input_func(input_func)
599
556
 
600
- @run_async_synchronously(async_func=async_set_input_func)
601
- def set_input_func(self, input_func: str) -> None:
602
- """
603
- Set input_func of device.
604
-
605
- Valid values depend on the device and should be taken from
606
- "input_func_list".
607
- """
608
-
609
557
  async def async_set_sound_mode(self, sound_mode: str) -> None:
610
558
  """
611
559
  Set sound_mode of device.
@@ -615,87 +563,42 @@ class DenonAVR(DenonAVRFoundation):
615
563
  """
616
564
  await self.soundmode.async_set_sound_mode(sound_mode)
617
565
 
618
- @run_async_synchronously(async_func=async_set_sound_mode)
619
- def set_sound_mode(self, sound_mode: str) -> None:
620
- """
621
- Set sound_mode of device.
622
-
623
- Valid values depend on the device and should be taken from
624
- "sound_mode_list".
625
- """
626
-
627
566
  async def async_toggle_play_pause(self) -> None:
628
567
  """Toggle play pause media player."""
629
568
  await self.input.async_toggle_play_pause()
630
569
 
631
- @run_async_synchronously(async_func=async_toggle_play_pause)
632
- def toggle_play_pause(self) -> None:
633
- """Toggle play pause media player."""
634
-
635
570
  async def async_play(self) -> None:
636
571
  """Send play command to receiver command via HTTP post."""
637
572
  await self.input.async_play()
638
573
 
639
- @run_async_synchronously(async_func=async_play)
640
- def play(self) -> None:
641
- """Send play command to receiver command via HTTP post."""
642
-
643
574
  async def async_pause(self) -> None:
644
575
  """Send pause command to receiver command via HTTP post."""
645
576
  await self.input.async_pause()
646
577
 
647
- @run_async_synchronously(async_func=async_pause)
648
- def pause(self) -> None:
649
- """Send pause command to receiver command via HTTP post."""
650
-
651
578
  async def async_previous_track(self) -> None:
652
579
  """Send previous track command to receiver command via HTTP post."""
653
580
  await self.input.async_previous_track()
654
581
 
655
- @run_async_synchronously(async_func=async_previous_track)
656
- def previous_track(self) -> None:
657
- """Send previous track command to receiver command via HTTP post."""
658
-
659
582
  async def async_next_track(self) -> None:
660
583
  """Send next track command to receiver command via HTTP post."""
661
584
  await self.input.async_next_track()
662
585
 
663
- @run_async_synchronously(async_func=async_next_track)
664
- def next_track(self) -> None:
665
- """Send next track command to receiver command via HTTP post."""
666
-
667
586
  async def async_power_on(self) -> None:
668
587
  """Turn on receiver via HTTP get command."""
669
588
  await self._device.async_power_on()
670
589
 
671
- @run_async_synchronously(async_func=async_power_on)
672
- def power_on(self) -> None:
673
- """Turn on receiver via HTTP get command."""
674
-
675
590
  async def async_power_off(self) -> None:
676
591
  """Turn off receiver via HTTP get command."""
677
592
  await self._device.async_power_off()
678
593
 
679
- @run_async_synchronously(async_func=async_power_off)
680
- def power_off(self) -> None:
681
- """Turn off receiver via HTTP get command."""
682
-
683
594
  async def async_volume_up(self) -> None:
684
595
  """Volume up receiver via HTTP get command."""
685
596
  await self.vol.async_volume_up()
686
597
 
687
- @run_async_synchronously(async_func=async_volume_up)
688
- def volume_up(self) -> None:
689
- """Volume up receiver via HTTP get command."""
690
-
691
598
  async def async_volume_down(self) -> None:
692
599
  """Volume down receiver via HTTP get command."""
693
600
  await self.vol.async_volume_down()
694
601
 
695
- @run_async_synchronously(async_func=async_volume_down)
696
- def volume_down(self) -> None:
697
- """Volume down receiver via HTTP get command."""
698
-
699
602
  async def async_set_volume(self, volume: float) -> None:
700
603
  """
701
604
  Set receiver volume via HTTP get command.
@@ -705,39 +608,18 @@ class DenonAVR(DenonAVRFoundation):
705
608
  """
706
609
  await self.vol.async_set_volume(volume)
707
610
 
708
- @run_async_synchronously(async_func=async_set_volume)
709
- def set_volume(self, volume: float) -> None:
710
- """
711
- Set receiver volume via HTTP get command.
712
-
713
- Volume is send in a format like -50.0.
714
- Minimum is -80.0, maximum at 18.0
715
- """
716
-
717
611
  async def async_mute(self, mute: bool) -> None:
718
612
  """Mute receiver via HTTP get command."""
719
613
  await self.vol.async_mute(mute)
720
614
 
721
- @run_async_synchronously(async_func=async_mute)
722
- def mute(self, mute: bool) -> None:
723
- """Mute receiver via HTTP get command."""
724
-
725
615
  async def async_enable_tone_control(self) -> None:
726
616
  """Enable tone control to change settings like bass or treble."""
727
617
  await self.tonecontrol.async_enable_tone_control()
728
618
 
729
- @run_async_synchronously(async_func=async_enable_tone_control)
730
- def enable_tone_control(self) -> None:
731
- """Enable tone control to change settings like bass or treble."""
732
-
733
619
  async def async_disable_tone_control(self) -> None:
734
620
  """Disable tone control to change settings like bass or treble."""
735
621
  await self.tonecontrol.async_disable_tone_control()
736
622
 
737
- @run_async_synchronously(async_func=async_disable_tone_control)
738
- def disable_tone_control(self) -> None:
739
- """Disable tone control to change settings like bass or treble."""
740
-
741
623
  async def async_set_bass(self, value: int) -> None:
742
624
  """
743
625
  Set receiver bass.
@@ -749,17 +631,6 @@ class DenonAVR(DenonAVRFoundation):
749
631
  """
750
632
  await self.tonecontrol.async_set_bass(value)
751
633
 
752
- @run_async_synchronously(async_func=async_set_bass)
753
- def set_bass(self, value: int) -> None:
754
- """
755
- Set receiver bass.
756
-
757
- Minimum is 0, maximum at 12
758
-
759
- Note:
760
- Doesn't work, if Dynamic Equalizer is active.
761
- """
762
-
763
634
  async def async_bass_up(self) -> None:
764
635
  """
765
636
  Increase level of Bass.
@@ -769,15 +640,6 @@ class DenonAVR(DenonAVRFoundation):
769
640
  """
770
641
  await self.tonecontrol.async_bass_up()
771
642
 
772
- @run_async_synchronously(async_func=async_bass_up)
773
- def bass_up(self) -> None:
774
- """
775
- Increase level of Bass.
776
-
777
- Note:
778
- Doesn't work, if Dynamic Equalizer is active
779
- """
780
-
781
643
  async def async_bass_down(self) -> None:
782
644
  """
783
645
  Decrease level of Bass.
@@ -787,15 +649,6 @@ class DenonAVR(DenonAVRFoundation):
787
649
  """
788
650
  await self.tonecontrol.async_bass_down()
789
651
 
790
- @run_async_synchronously(async_func=async_bass_down)
791
- def bass_down(self) -> None:
792
- """
793
- Decrease level of Bass.
794
-
795
- Note:
796
- Doesn't work, if Dynamic Equalizer is active
797
- """
798
-
799
652
  async def async_set_treble(self, value: int) -> None:
800
653
  """
801
654
  Set receiver treble.
@@ -807,17 +660,6 @@ class DenonAVR(DenonAVRFoundation):
807
660
  """
808
661
  await self.tonecontrol.async_set_treble(value)
809
662
 
810
- @run_async_synchronously(async_func=async_set_treble)
811
- def set_treble(self, value: int) -> None:
812
- """
813
- Set receiver treble.
814
-
815
- Minimum is 0, maximum at 12
816
-
817
- Note:
818
- Doesn't work, if Dynamic Equalizer is active.
819
- """
820
-
821
663
  async def async_treble_up(self) -> None:
822
664
  """
823
665
  Increase level of Treble.
@@ -827,15 +669,6 @@ class DenonAVR(DenonAVRFoundation):
827
669
  """
828
670
  await self.tonecontrol.async_treble_up()
829
671
 
830
- @run_async_synchronously(async_func=async_treble_up)
831
- def treble_up(self) -> None:
832
- """
833
- Increase level of Treble.
834
-
835
- Note:
836
- Doesn't work, if Dynamic Equalizer is active
837
- """
838
-
839
672
  async def async_treble_down(self) -> None:
840
673
  """
841
674
  Decrease level of Treble.
@@ -845,11 +678,38 @@ class DenonAVR(DenonAVRFoundation):
845
678
  """
846
679
  await self.tonecontrol.async_treble_down()
847
680
 
848
- @run_async_synchronously(async_func=async_treble_down)
849
- def treble_down(self) -> None:
850
- """
851
- Decrease level of Treble.
681
+ async def async_cursor_up(self) -> None:
682
+ """Send cursor up to receiver via HTTP get command."""
683
+ await self._device.async_cursor_up()
852
684
 
853
- Note:
854
- Doesn't work, if Dynamic Equalizer is active
855
- """
685
+ async def async_cursor_down(self) -> None:
686
+ """Send cursor down to receiver via HTTP get command."""
687
+ await self._device.async_cursor_down()
688
+
689
+ async def async_cursor_left(self) -> None:
690
+ """Send cursor left to receiver via HTTP get command."""
691
+ await self._device.async_cursor_left()
692
+
693
+ async def async_cursor_right(self) -> None:
694
+ """Send cursor right to receiver via HTTP get command."""
695
+ await self._device.async_cursor_right()
696
+
697
+ async def async_cursor_enter(self) -> None:
698
+ """Send cursor enter to receiver via HTTP get command."""
699
+ await self._device.async_cursor_enter()
700
+
701
+ async def async_back(self) -> None:
702
+ """Send back to receiver via HTTP get command."""
703
+ await self._device.async_back()
704
+
705
+ async def async_info(self) -> None:
706
+ """Send info to receiver via HTTP get command."""
707
+ await self._device.async_info()
708
+
709
+ async def async_options(self) -> None:
710
+ """Raise options menu to receiver via HTTP get command."""
711
+ await self._device.async_options()
712
+
713
+ async def async_settings_menu(self) -> None:
714
+ """Raise settings menu to receiver via HTTP get command."""
715
+ await self._device.async_settings_menu()