denonavr 1.0.0__py3-none-any.whl → 1.1.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
@@ -10,14 +10,11 @@ This module implements the REST API to Denon AVR receivers.
10
10
  import inspect
11
11
  import logging
12
12
  import time
13
- import xml.etree.ElementTree as ET
14
13
  from functools import wraps
15
14
  from typing import Callable, TypeVar
16
15
 
17
16
  import httpx
18
17
  from asyncstdlib import lru_cache
19
- from defusedxml import DefusedXmlException
20
- from defusedxml.ElementTree import ParseError
21
18
 
22
19
  from .exceptions import (
23
20
  AvrForbiddenError,
@@ -33,12 +30,7 @@ AnyT = TypeVar("AnyT")
33
30
 
34
31
 
35
32
  def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
36
- """
37
- Handle exceptions raised when calling a Denon AVR endpoint asynchronously.
38
-
39
- The decorated function must either have a string variable as second
40
- argument or as "request" keyword argument.
41
- """
33
+ """Handle exceptions raised when calling a Denon AVR endpoint asynchronously."""
42
34
 
43
35
  @wraps(func)
44
36
  async def wrapper(*args, **kwargs):
@@ -64,48 +56,29 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
64
56
  raise AvrInvalidResponseError(
65
57
  f"RemoteProtocolError: {err}", err.request
66
58
  ) from err
67
- except (
68
- ET.ParseError,
69
- DefusedXmlException,
70
- ParseError,
71
- UnicodeDecodeError,
72
- ) as err:
73
- _LOGGER.debug(
74
- "Defusedxml parse error on request %s: %s", (args, kwargs), err
75
- )
76
- raise AvrInvalidResponseError(
77
- f"XMLParseError: {err}", (args, kwargs)
78
- ) from err
79
59
 
80
60
  return wrapper
81
61
 
82
62
 
83
63
  def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
84
64
  """
85
- Decorate a function to cache its results with an lru_cache of maxsize 16.
65
+ Decorate a function to cache its results with an lru_cache of maxsize 32.
86
66
 
87
67
  This decorator also sets an "cache_id" keyword argument if it is not set yet.
88
- When an exception occurs it clears lru_cache to prevent memory leaks in
89
- home-assistant when receiver instances are created and deleted right
90
- away in case the device is offline on setup.
91
68
  """
92
69
  if inspect.signature(func).parameters.get("cache_id") is None:
93
70
  raise AttributeError(
94
71
  f"Function {func} does not have a 'cache_id' keyword parameter"
95
72
  )
96
73
 
97
- lru_decorator = lru_cache(maxsize=16)
74
+ lru_decorator = lru_cache(maxsize=32)
98
75
  cached_func = lru_decorator(func)
99
76
 
100
77
  @wraps(func)
101
78
  async def wrapper(*args, **kwargs):
102
79
  if kwargs.get("cache_id") is None:
103
80
  kwargs["cache_id"] = time.time()
104
- try:
105
- return await cached_func(*args, **kwargs)
106
- except Exception as err:
107
- _LOGGER.debug("Exception raised, clearing cache: %s", err)
108
- cached_func.cache_clear()
109
- raise
81
+
82
+ return await cached_func(*args, **kwargs)
110
83
 
111
84
  return wrapper
denonavr/denonavr.py CHANGED
@@ -10,13 +10,29 @@ This module implements the interface to Denon AVR receivers.
10
10
  import asyncio
11
11
  import logging
12
12
  import time
13
- from typing import Awaitable, Callable, Dict, List, Optional
13
+ from typing import Awaitable, Callable, Dict, List, Literal, Optional, Union
14
14
 
15
15
  import attr
16
16
  import httpx
17
17
 
18
18
  from .audyssey import DenonAVRAudyssey, audyssey_factory
19
- from .const import DENON_ATTR_SETATTR, MAIN_ZONE, VALID_ZONES
19
+ from .const import (
20
+ DENON_ATTR_SETATTR,
21
+ MAIN_ZONE,
22
+ VALID_ZONES,
23
+ AudioRestorers,
24
+ AutoStandbys,
25
+ BluetoothOutputModes,
26
+ DimmerModes,
27
+ EcoModes,
28
+ HDMIAudioDecodes,
29
+ HDMIOutputs,
30
+ PanelLocks,
31
+ RoomSizes,
32
+ TransducerLPFs,
33
+ VideoProcessingModes,
34
+ )
35
+ from .dirac import DenonAVRDirac, dirac_factory
20
36
  from .exceptions import AvrCommandError
21
37
  from .foundation import DenonAVRFoundation, set_api_host, set_api_timeout
22
38
  from .input import DenonAVRInput, input_factory
@@ -83,6 +99,11 @@ class DenonAVR(DenonAVRFoundation):
83
99
  default=attr.Factory(audyssey_factory, takes_self=True),
84
100
  init=False,
85
101
  )
102
+ dirac: DenonAVRDirac = attr.ib(
103
+ validator=attr.validators.instance_of(DenonAVRDirac),
104
+ default=attr.Factory(dirac_factory, takes_self=True),
105
+ init=False,
106
+ )
86
107
  input: DenonAVRInput = attr.ib(
87
108
  validator=attr.validators.instance_of(DenonAVRInput),
88
109
  default=attr.Factory(input_factory, takes_self=True),
@@ -149,6 +170,7 @@ class DenonAVR(DenonAVRFoundation):
149
170
  await self.tonecontrol.async_setup()
150
171
  self.vol.setup()
151
172
  self.audyssey.setup()
173
+ self.dirac.setup()
152
174
 
153
175
  for zone_name, zone_item in self._zones.items():
154
176
  if zone_name != self.zone:
@@ -278,6 +300,15 @@ class DenonAVR(DenonAVRFoundation):
278
300
  """
279
301
  return self._device.power
280
302
 
303
+ @property
304
+ def settings_menu(self) -> Optional[bool]:
305
+ """
306
+ Return the settings menu state of the device.
307
+
308
+ Only available if using Telnet.
309
+ """
310
+ return self._device.settings_menu
311
+
281
312
  @property
282
313
  def state(self) -> Optional[str]:
283
314
  """
@@ -505,6 +536,222 @@ class DenonAVR(DenonAVRFoundation):
505
536
  """Return a list of available MultiEQ settings."""
506
537
  return self.audyssey.multi_eq_setting_list
507
538
 
539
+ @property
540
+ def dimmer(self) -> Optional[str]:
541
+ """
542
+ Returns the dimmer state of the device.
543
+
544
+ Only available if using Telnet.
545
+
546
+ Possible values are: "Off", "Dark", "Dim" and "Bright"
547
+ """
548
+ return self._device.dimmer
549
+
550
+ @property
551
+ def auto_standby(self) -> Optional[str]:
552
+ """
553
+ Return the auto-standby state of the device.
554
+
555
+ Only available if using Telnet.
556
+
557
+ Possible values are: "OFF", "15M", "30M", "60M"
558
+ """
559
+ return self._device.auto_standby
560
+
561
+ @property
562
+ def sleep(self) -> Optional[Union[str, int]]:
563
+ """
564
+ Return the sleep timer for the device.
565
+
566
+ Only available if using Telnet.
567
+
568
+ Possible values are: "OFF" and 1-120 (in minutes)
569
+ """
570
+ return self._device.sleep
571
+
572
+ @property
573
+ def delay(self) -> Optional[int]:
574
+ """
575
+ Return the audio delay for the device in ms.
576
+
577
+ Only available if using Telnet.
578
+ """
579
+ return self._device.delay
580
+
581
+ @property
582
+ def eco_mode(self) -> Optional[str]:
583
+ """
584
+ Returns the eco-mode for the device.
585
+
586
+ Only available if using Telnet.
587
+
588
+ Possible values are: "Off", "On", "Auto"
589
+ """
590
+ return self._device.eco_mode
591
+
592
+ @property
593
+ def hdmi_output(self) -> Optional[str]:
594
+ """
595
+ Returns the HDMI-output for the device.
596
+
597
+ Only available if using Telnet.
598
+
599
+ Possible values are: "Auto", "HDMI1", "HDMI2"
600
+ """
601
+ return self._device.hdmi_output
602
+
603
+ @property
604
+ def hdmi_audio_decode(self) -> Optional[str]:
605
+ """
606
+ Returns the HDMI Audio Decode mode for the device.
607
+
608
+ Only available if using Telnet.
609
+
610
+ Possible values are: "AMP", "TV"
611
+ """
612
+ return self._device.hdmi_audio_decode
613
+
614
+ @property
615
+ def video_processing_mode(self) -> Optional[str]:
616
+ """
617
+ Return the video processing mode for the device.
618
+
619
+ Only available if using Telnet.
620
+
621
+ Possible values are: "Auto", "Game", "Movie", "Bypass"
622
+ """
623
+ return self._device.video_processing_mode
624
+
625
+ @property
626
+ def tactile_transducer(self) -> Optional[bool]:
627
+ """
628
+ Return the tactile transducer state of the device.
629
+
630
+ Only available if using Telnet.
631
+ """
632
+ return self._device.tactile_transducer
633
+
634
+ @property
635
+ def tactile_transducer_level(self) -> Optional[float]:
636
+ """
637
+ Return the tactile transducer level in dB.
638
+
639
+ Only available if using Telnet.
640
+ """
641
+ return self._device.tactile_transducer_level
642
+
643
+ @property
644
+ def tactile_transducer_lpf(self) -> Optional[str]:
645
+ """
646
+ Return the tactile transducer low pass filter frequency.
647
+
648
+ Only available if using Telnet.
649
+ """
650
+ return self._device.tactile_transducer_lpf
651
+
652
+ @property
653
+ def room_size(self) -> Optional[str]:
654
+ """
655
+ Return the room size for the device.
656
+
657
+ Only available if using Telnet.
658
+
659
+ Possible values are: "S", "MS", "M", "ML", "L"
660
+ """
661
+ return self._device.room_size
662
+
663
+ @property
664
+ def triggers(self) -> Dict[int, str]:
665
+ """
666
+ Return the triggers and their statuses for the device.
667
+
668
+ Only available if using Telnet.
669
+ """
670
+ return self._device.triggers
671
+
672
+ @property
673
+ def speaker_preset(self) -> Optional[int]:
674
+ """
675
+ Return the speaker preset for the device.
676
+
677
+ Only available if using Telnet.
678
+
679
+ Possible values are: "1", "2"
680
+ """
681
+ return self._device.speaker_preset
682
+
683
+ @property
684
+ def bt_transmitter(self) -> Optional[bool]:
685
+ """
686
+ Return the Bluetooth transmitter state for the device.
687
+
688
+ Only available if using Telnet.
689
+ """
690
+ return self._device.bt_transmitter
691
+
692
+ @property
693
+ def bt_output_mode(self) -> Optional[str]:
694
+ """
695
+ Return the Bluetooth output mode for the device.
696
+
697
+ Only available if using Telnet.
698
+
699
+ Possible values are: "Bluetooth + Speakers", "Bluetooth Only"
700
+ """
701
+ return self._device.bt_output_mode
702
+
703
+ @property
704
+ def delay_time(self) -> Optional[int]:
705
+ """
706
+ Return the delay time for the device in ms.
707
+
708
+ Only available if using Telnet.
709
+ """
710
+ return self._device.delay_time
711
+
712
+ @property
713
+ def audio_restorer(self) -> Optional[str]:
714
+ """
715
+ Return the audio restorer for the device.
716
+
717
+ Only available if using Telnet.
718
+
719
+ Possible values are: "Off", "Low", "Medium", "High"
720
+ """
721
+ return self._device.audio_restorer
722
+
723
+ @property
724
+ def graphic_eq(self) -> Optional[bool]:
725
+ """
726
+ Return the Graphic EQ status for the device.
727
+
728
+ Only available if using Telnet.
729
+ """
730
+ return self._device.graphic_eq
731
+
732
+ @property
733
+ def headphone_eq(self) -> Optional[bool]:
734
+ """
735
+ Return the Headphone EQ status for the device.
736
+
737
+ Only available if using Telnet.
738
+ """
739
+ return self._device.headphone_eq
740
+
741
+ ##########
742
+ # Getter #
743
+ ##########
744
+
745
+ def get_trigger(self, trigger: int) -> Optional[str]:
746
+ """
747
+ Return the status of a specific trigger.
748
+
749
+ Only available if using Telnet.
750
+
751
+ Valid trigger values are 1-3.
752
+ """
753
+ return self._device.get_trigger(trigger)
754
+
508
755
  ##########
509
756
  # Setter #
510
757
  ##########
@@ -519,7 +766,7 @@ class DenonAVR(DenonAVRFoundation):
519
766
  """
520
767
  if not callable(async_client_getter):
521
768
  raise AvrCommandError("Provided object is not callable")
522
- self._device.api.async_client_getter = async_client_getter
769
+ self._device.api.httpx_async_client.client_getter = async_client_getter
523
770
 
524
771
  async def async_dynamic_eq_off(self) -> None:
525
772
  """Turn DynamicEQ off."""
@@ -713,3 +960,253 @@ class DenonAVR(DenonAVRFoundation):
713
960
  async def async_settings_menu(self) -> None:
714
961
  """Raise settings menu to receiver via HTTP get command."""
715
962
  await self._device.async_settings_menu()
963
+
964
+ async def async_channel_level_adjust(self) -> None:
965
+ """Toggle the channel level adjust menu on receiver via HTTP get command."""
966
+ await self._device.async_channel_level_adjust()
967
+
968
+ async def async_dimmer_toggle(self) -> None:
969
+ """Toggle dimmer on receiver via HTTP get command."""
970
+ await self._device.async_dimmer_toggle()
971
+
972
+ async def async_dimmer(self, mode: DimmerModes) -> None:
973
+ """Set dimmer mode on receiver via HTTP get command."""
974
+ await self._device.async_dimmer(mode)
975
+
976
+ async def async_auto_standby(self, auto_standby: AutoStandbys) -> None:
977
+ """Set auto standby on receiver via HTTP get command."""
978
+ await self._device.async_auto_standby(auto_standby)
979
+
980
+ async def async_sleep(self, sleep: Union[Literal["OFF"], int]) -> None:
981
+ """
982
+ Set auto standby on receiver via HTTP get command.
983
+
984
+ Valid sleep values are "OFF" and 1-120 (in minutes)
985
+ """
986
+ await self._device.async_sleep(sleep)
987
+
988
+ async def async_delay_up(self) -> None:
989
+ """Increase delay of the audio."""
990
+ await self._device.async_delay_up()
991
+
992
+ async def async_delay_down(self) -> None:
993
+ """Decrease delay of the audio."""
994
+ await self._device.async_delay_down()
995
+
996
+ async def async_eco_mode(self, mode: EcoModes) -> None:
997
+ """Set Eco mode."""
998
+ await self._device.async_eco_mode(mode)
999
+
1000
+ async def async_hdmi_output(self, output: HDMIOutputs) -> None:
1001
+ """Set HDMI output."""
1002
+ await self._device.async_hdmi_output(output)
1003
+
1004
+ async def async_hdmi_audio_decode(self, mode: HDMIAudioDecodes) -> None:
1005
+ """Set HDMI Audio Decode mode on receiver via HTTP get command."""
1006
+ await self._device.async_hdmi_audio_decode(mode)
1007
+
1008
+ async def async_video_processing_mode(self, mode: VideoProcessingModes) -> None:
1009
+ """Set video processing mode on receiver via HTTP get command."""
1010
+ await self._device.async_video_processing_mode(mode)
1011
+
1012
+ async def async_status(self) -> str:
1013
+ """
1014
+ Toggles the display of status on the device.
1015
+
1016
+ Only supported on Denon models.
1017
+ """
1018
+ return await self._device.async_status()
1019
+
1020
+ async def async_system_reset(self) -> None:
1021
+ """DANGER! Reset the receiver via HTTP get command."""
1022
+ await self._device.async_system_reset()
1023
+
1024
+ async def async_network_restart(self) -> None:
1025
+ """Restart the network on the receiver via HTTP get command."""
1026
+ await self._device.async_network_restart()
1027
+
1028
+ async def async_speaker_preset(self, preset: int) -> None:
1029
+ """
1030
+ Set speaker preset on receiver via HTTP get command.
1031
+
1032
+ Valid preset values are 1-2.
1033
+ """
1034
+ await self._device.async_speaker_preset(preset)
1035
+
1036
+ async def async_speaker_preset_toggle(self) -> None:
1037
+ """
1038
+ Toggle speaker preset on receiver via HTTP get command.
1039
+
1040
+ Only available if using Telnet.
1041
+ """
1042
+ await self._device.async_speaker_preset_toggle()
1043
+
1044
+ async def async_bt_transmitter_on(self) -> None:
1045
+ """Turn on Bluetooth transmitter on receiver via HTTP get command."""
1046
+ await self._device.async_bt_transmitter_on()
1047
+
1048
+ async def async_bt_transmitter_off(self) -> None:
1049
+ """Turn off Bluetooth transmitter on receiver via HTTP get command."""
1050
+ await self._device.async_bt_transmitter_off()
1051
+
1052
+ async def async_bt_transmitter_toggle(self) -> None:
1053
+ """
1054
+ Toggle Bluetooth transmitter mode on receiver via HTTP get command.
1055
+
1056
+ Only available if using Telnet.
1057
+ """
1058
+ await self._device.async_bt_transmitter_toggle()
1059
+
1060
+ async def async_bt_output_mode(self, mode: BluetoothOutputModes) -> None:
1061
+ """Set Bluetooth transmitter mode on receiver via HTTP get command."""
1062
+ await self._device.async_bt_output_mode(mode)
1063
+
1064
+ async def async_bt_output_mode_toggle(self) -> None:
1065
+ """
1066
+ Toggle Bluetooth output mode on receiver via HTTP get command.
1067
+
1068
+ Only available if using Telnet.
1069
+ """
1070
+ await self._device.async_bt_output_mode_toggle()
1071
+
1072
+ async def async_delay_time_up(self) -> None:
1073
+ """Delay time up on receiver via HTTP get command."""
1074
+ await self._device.async_delay_time_up()
1075
+
1076
+ async def async_delay_time_down(self) -> None:
1077
+ """Delay time up on receiver via HTTP get command."""
1078
+ await self._device.async_delay_time_down()
1079
+
1080
+ async def async_delay_time(self, delay_time: int) -> None:
1081
+ """
1082
+ Set delay time on receiver via HTTP get command.
1083
+
1084
+ :param delay_time: Delay time in ms. Valid values are 0-999.
1085
+ """
1086
+ await self._device.async_delay_time(delay_time)
1087
+
1088
+ async def async_audio_restorer(self, mode: AudioRestorers):
1089
+ """Set audio restorer on receiver via HTTP get command."""
1090
+ await self._device.async_audio_restorer(mode)
1091
+
1092
+ async def async_remote_control_lock(self):
1093
+ """Set remote control lock on receiver via HTTP get command."""
1094
+ await self._device.async_remote_control_lock()
1095
+
1096
+ async def async_remote_control_unlock(self):
1097
+ """Set remote control unlock on receiver via HTTP get command."""
1098
+ await self._device.async_remote_control_unlock()
1099
+
1100
+ async def async_panel_lock(self, panel_lock_mode: PanelLocks):
1101
+ """Set panel lock on receiver via HTTP get command."""
1102
+ await self._device.async_panel_lock(panel_lock_mode)
1103
+
1104
+ async def async_panel_unlock(self):
1105
+ """Set panel unlock on receiver via HTTP get command."""
1106
+ await self._device.async_panel_unlock()
1107
+
1108
+ async def async_graphic_eq_on(self) -> None:
1109
+ """Turn on Graphic EQ on receiver via HTTP get command."""
1110
+ await self._device.async_graphic_eq_on()
1111
+
1112
+ async def async_graphic_eq_off(self) -> None:
1113
+ """Turn off Graphic EQ on receiver via HTTP get command."""
1114
+ await self._device.async_graphic_eq_off()
1115
+
1116
+ async def async_graphic_eq_toggle(self) -> None:
1117
+ """
1118
+ Toggle Graphic EQ on receiver via HTTP get command.
1119
+
1120
+ Only available if using Telnet.
1121
+ """
1122
+ await self._device.async_graphic_eq_toggle()
1123
+
1124
+ async def async_headphone_eq_on(self) -> None:
1125
+ """Turn on Headphone EQ on receiver via HTTP get command."""
1126
+ await self._device.async_headphone_eq_on()
1127
+
1128
+ async def async_headphone_eq_off(self) -> None:
1129
+ """Turn off Headphone EQ on receiver via HTTP get command."""
1130
+ await self._device.async_headphone_eq_off()
1131
+
1132
+ async def async_headphone_eq_toggle(self) -> None:
1133
+ """
1134
+ Toggle Headphone EQ on receiver via HTTP get command.
1135
+
1136
+ Only available if using Telnet.
1137
+ """
1138
+ await self._device.async_headphone_eq_toggle()
1139
+
1140
+ async def async_tactile_transducer_on(self) -> None:
1141
+ """Turn on tactile transducer on receiver via HTTP get command."""
1142
+ await self._device.async_tactile_transducer_on()
1143
+
1144
+ async def async_tactile_transducer_off(self) -> None:
1145
+ """Turn on tactile transducer on receiver via HTTP get command."""
1146
+ await self._device.async_tactile_transducer_off()
1147
+
1148
+ async def async_tactile_transducer_toggle(self) -> None:
1149
+ """
1150
+ Turn on tactile transducer on receiver via HTTP get command.
1151
+
1152
+ Only available if using Telnet.
1153
+ """
1154
+ await self._device.async_tactile_transducer_toggle()
1155
+
1156
+ async def async_tactile_transducer_level_up(self) -> None:
1157
+ """Increase the transducer level on receiver via HTTP get command."""
1158
+ await self._device.async_tactile_transducer_level_up()
1159
+
1160
+ async def async_tactile_transducer_level_down(self) -> None:
1161
+ """Decrease the transducer on receiver via HTTP get command."""
1162
+ await self._device.async_tactile_transducer_level_down()
1163
+
1164
+ async def async_transducer_lpf(self, lpf: TransducerLPFs) -> None:
1165
+ """Set transducer low pass filter on receiver via HTTP get command."""
1166
+ await self._device.async_transducer_lpf(lpf)
1167
+
1168
+ async def async_room_size(self, room_size: RoomSizes) -> None:
1169
+ """Set room size on receiver via HTTP get command."""
1170
+ await self._device.async_room_size(room_size)
1171
+
1172
+ async def async_trigger_on(self, trigger: int) -> None:
1173
+ """
1174
+ Set trigger to ON on receiver via HTTP get command.
1175
+
1176
+ :param trigger: Trigger number to set to ON. Valid values are 1-3.
1177
+ """
1178
+ await self._device.async_trigger_on(trigger)
1179
+
1180
+ async def async_trigger_off(self, trigger: int) -> None:
1181
+ """
1182
+ Set trigger to OFF on receiver via HTTP get command.
1183
+
1184
+ :param trigger: Trigger number to set to OFF. Valid values are 1-3.
1185
+ """
1186
+ await self._device.async_trigger_off(trigger)
1187
+
1188
+ async def async_trigger_toggle(self, trigger: int) -> None:
1189
+ """
1190
+ Toggle trigger on receiver via HTTP get command.
1191
+
1192
+ Only available if using Telnet.
1193
+
1194
+ :param trigger: Trigger number to toggle. Valid values are 1-3.
1195
+ """
1196
+ await self._device.async_trigger_toggle(trigger)
1197
+
1198
+ async def async_quick_select_mode(self, quick_select_number: int) -> None:
1199
+ """
1200
+ Set quick select mode on receiver via HTTP get command.
1201
+
1202
+ :param quick_select_number: Quick select number to set. Valid values are 1-5.
1203
+ """
1204
+ await self._device.async_quick_select_mode(quick_select_number)
1205
+
1206
+ async def async_quick_select_memory(self, quick_select_number: int) -> None:
1207
+ """
1208
+ Set quick select memory on receiver via HTTP get command.
1209
+
1210
+ :param quick_select_number: Quick select number to set. Valid values are 1-5.
1211
+ """
1212
+ await self._device.async_quick_select_memory(quick_select_number)