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/foundation.py CHANGED
@@ -12,40 +12,64 @@ import logging
12
12
  import xml.etree.ElementTree as ET
13
13
  from collections.abc import Hashable
14
14
  from copy import deepcopy
15
- from typing import Dict, List, Optional, Union
15
+ from typing import Dict, List, Literal, Optional, Union, get_args
16
16
 
17
17
  import attr
18
- import httpx
19
18
 
20
19
  from .api import DenonAVRApi, DenonAVRTelnetApi
21
20
  from .appcommand import AppCommandCmd, AppCommands
22
21
  from .const import (
23
22
  APPCOMMAND_CMD_TEXT,
24
23
  APPCOMMAND_NAME,
24
+ AUDIO_RESTORER_MAP,
25
+ AUDIO_RESTORER_MAP_LABELS,
25
26
  AVR,
26
27
  AVR_X,
27
28
  AVR_X_2016,
29
+ BLUETOOTH_OUTPUT_MAP_LABELS,
30
+ BLUETOOTH_OUTPUT_MODES_MAP,
31
+ CHANNEL_VOLUME_MAP,
28
32
  DENON_ATTR_SETATTR,
29
33
  DENONAVR_TELNET_COMMANDS,
30
34
  DENONAVR_URLS,
31
35
  DESCRIPTION_TYPES,
32
36
  DEVICEINFO_AVR_X_PATTERN,
33
37
  DEVICEINFO_COMMAPI_PATTERN,
38
+ DIMMER_MODE_MAP,
39
+ DIMMER_MODE_MAP_LABELS,
40
+ ECO_MODE_MAP,
41
+ ECO_MODE_MAP_LABELS,
42
+ HDMI_OUTPUT_MAP_LABELS,
34
43
  MAIN_ZONE,
35
44
  POWER_STATES,
45
+ SETTINGS_MENU_STATES,
36
46
  VALID_RECEIVER_TYPES,
37
47
  VALID_ZONES,
48
+ VIDEO_PROCESSING_MODES_MAP,
49
+ VIDEO_PROCESSING_MODES_MAP_LABELS,
38
50
  ZONE2,
39
51
  ZONE2_TELNET_COMMANDS,
40
52
  ZONE2_URLS,
41
53
  ZONE3,
42
54
  ZONE3_TELNET_COMMANDS,
43
55
  ZONE3_URLS,
56
+ AudioRestorers,
57
+ AutoStandbys,
58
+ BluetoothOutputModes,
59
+ DimmerModes,
60
+ EcoModes,
61
+ HDMIAudioDecodes,
62
+ HDMIOutputs,
63
+ PanelLocks,
44
64
  ReceiverType,
45
65
  ReceiverURLs,
66
+ RoomSizes,
46
67
  TelnetCommands,
68
+ TransducerLPFs,
69
+ VideoProcessingModes,
47
70
  )
48
71
  from .exceptions import (
72
+ AvrCommandError,
49
73
  AvrForbiddenError,
50
74
  AvrIncompleteResponseError,
51
75
  AvrNetworkError,
@@ -58,6 +82,26 @@ from .ssdp import evaluate_scpd_xml
58
82
  _LOGGER = logging.getLogger(__name__)
59
83
 
60
84
 
85
+ def convert_on_off_bool(value: str) -> Optional[bool]:
86
+ """Convert a ON/OFF string to bool."""
87
+ if value is None:
88
+ return None
89
+ if value.lower() == "on":
90
+ return True
91
+ if value.lower() == "off":
92
+ return False
93
+ return None
94
+
95
+
96
+ def convert_on_off_bool_str(value: str) -> Optional[Union[bool, str]]:
97
+ """Convert a ON/OFF string to bool with fallback to raw value."""
98
+ val = convert_on_off_bool(value)
99
+ if val is not None:
100
+ return val
101
+
102
+ return value
103
+
104
+
61
105
  @attr.s(auto_attribs=True, on_setattr=DENON_ATTR_SETATTR)
62
106
  class DenonAVRDeviceInfo:
63
107
  """Implements a class with device information of the receiver."""
@@ -103,6 +147,75 @@ class DenonAVRDeviceInfo:
103
147
  _power: Optional[str] = attr.ib(
104
148
  converter=attr.converters.optional(str), default=None
105
149
  )
150
+ _settings_menu: Optional[bool] = attr.ib(
151
+ converter=attr.converters.optional(convert_on_off_bool), default=None
152
+ )
153
+ _dimmer: Optional[str] = attr.ib(
154
+ converter=attr.converters.optional(str), default=None
155
+ )
156
+ _auto_standby: Optional[str] = attr.ib(
157
+ converter=attr.converters.optional(str), default=None
158
+ )
159
+ _auto_standbys = get_args(AutoStandbys)
160
+ _sleep: Optional[Union[str, int]] = attr.ib(
161
+ converter=attr.converters.optional(str), default=None
162
+ )
163
+ _delay: Optional[int] = attr.ib(
164
+ converter=attr.converters.optional(int), default=None
165
+ )
166
+ _eco_mode: Optional[str] = attr.ib(
167
+ converter=attr.converters.optional(str), default=None
168
+ )
169
+ _hdmi_output: Optional[str] = attr.ib(
170
+ converter=attr.converters.optional(str), default=None
171
+ )
172
+ _hdmi_audio_decode: Optional[str] = attr.ib(
173
+ converter=attr.converters.optional(str), default=None
174
+ )
175
+ _hdmi_audio_decodes = get_args(HDMIAudioDecodes)
176
+ _video_processing_mode: Optional[str] = attr.ib(
177
+ converter=attr.converters.optional(str), default=None
178
+ )
179
+ _video_processing_modes = get_args(VideoProcessingModes)
180
+ _tactile_transducer: Optional[str] = attr.ib(
181
+ converter=attr.converters.optional(str), default=None
182
+ )
183
+ _tactile_transducer_level: Optional[float] = attr.ib(
184
+ converter=attr.converters.optional(float), default=None
185
+ )
186
+ _tactile_transducer_lpf: Optional[str] = attr.ib(
187
+ converter=attr.converters.optional(str), default=None
188
+ )
189
+ _tactile_transducer_lpfs = get_args(TransducerLPFs)
190
+ _room_size: Optional[str] = attr.ib(
191
+ converter=attr.converters.optional(str), default=None
192
+ )
193
+ _room_sizes = get_args(RoomSizes)
194
+ _triggers: Optional[Dict[int, str]] = attr.ib(default=None)
195
+ _speaker_preset: Optional[int] = attr.ib(
196
+ converter=attr.converters.optional(str), default=None
197
+ )
198
+ _bt_transmitter: Optional[bool] = attr.ib(
199
+ converter=attr.converters.optional(convert_on_off_bool), default=None
200
+ )
201
+ _bt_output_mode: Optional[str] = attr.ib(
202
+ converter=attr.converters.optional(str), default=None
203
+ )
204
+ _bt_output_modes = get_args(BluetoothOutputModes)
205
+ _delay_time: Optional[int] = attr.ib(
206
+ converter=attr.converters.optional(int), default=None
207
+ )
208
+ _audio_restorer: Optional[str] = attr.ib(
209
+ converter=attr.converters.optional(str), default=None
210
+ )
211
+ _audio_restorers = get_args(AudioRestorers)
212
+ _panel_locks = get_args(PanelLocks)
213
+ _graphic_eq: Optional[bool] = attr.ib(
214
+ converter=attr.converters.optional(convert_on_off_bool), default=None
215
+ )
216
+ _headphone_eq: Optional[bool] = attr.ib(
217
+ converter=attr.converters.optional(convert_on_off_bool), default=None
218
+ )
106
219
  _is_setup: bool = attr.ib(converter=bool, default=False, init=False)
107
220
  _allow_recovery: bool = attr.ib(converter=bool, default=True, init=True)
108
221
  _setup_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))
@@ -129,6 +242,181 @@ class DenonAVRDeviceInfo:
129
242
  if self.zone == zone and parameter in POWER_STATES:
130
243
  self._power = parameter
131
244
 
245
+ async def _async_settings_menu_callback(
246
+ self, zone: str, event: str, parameter: str
247
+ ) -> None:
248
+ """Handle a settings menu event."""
249
+ if (
250
+ event == "MN"
251
+ and parameter[0:3] == "MEN"
252
+ and parameter[4:] in SETTINGS_MENU_STATES
253
+ ):
254
+ self._settings_menu = parameter[4:]
255
+
256
+ async def _async_dimmer_callback(
257
+ self, zone: str, event: str, parameter: str
258
+ ) -> None:
259
+ """Handle a dimmer change event."""
260
+ if event == "DIM" and parameter[1:] in DIMMER_MODE_MAP_LABELS:
261
+ self._dimmer = DIMMER_MODE_MAP_LABELS[parameter[1:]]
262
+
263
+ async def _async_auto_standby_callback(
264
+ self, zone: str, event: str, parameter: str
265
+ ) -> None:
266
+ """Handle a auto standby change event."""
267
+ if zone == "Main" and event == "STBY":
268
+ self._auto_standby = parameter
269
+
270
+ async def _async_auto_sleep_callback(
271
+ self, zone: str, event: str, parameter: str
272
+ ) -> None:
273
+ """Handle a sleep change event."""
274
+ if event != "SLP":
275
+ return
276
+
277
+ if parameter == "OFF":
278
+ self._sleep = parameter
279
+ else:
280
+ self._sleep = int(parameter)
281
+
282
+ async def _async_room_size_callback(
283
+ self, zone: str, event: str, parameter: str
284
+ ) -> None:
285
+ """Handle a room size change event."""
286
+ if parameter[:3] != "RSZ":
287
+ return
288
+
289
+ self._room_size = parameter[4:]
290
+
291
+ async def _async_trigger_callback(
292
+ self, zone: str, event: str, parameter: str
293
+ ) -> None:
294
+ """Handle a trigger change event."""
295
+ if event != "TR":
296
+ return
297
+
298
+ values = parameter.split()
299
+ if len(values) != 2:
300
+ return
301
+
302
+ if self._triggers is None:
303
+ self._triggers = {}
304
+
305
+ self._triggers[int(values[0])] = values[1]
306
+
307
+ async def _async_delay_callback(
308
+ self, zone: str, event: str, parameter: str
309
+ ) -> None:
310
+ """Handle a delay change event."""
311
+ if event == "PS" and parameter[0:3] == "DEL":
312
+ self._delay = int(parameter[4:])
313
+
314
+ async def _async_eco_mode_callback(
315
+ self, zone: str, event: str, parameter: str
316
+ ) -> None:
317
+ """Handle an Eco-mode change event."""
318
+ if event == "ECO" and parameter in ECO_MODE_MAP_LABELS:
319
+ self._eco_mode = ECO_MODE_MAP_LABELS[parameter]
320
+
321
+ async def _async_hdmi_output_callback(
322
+ self, zone: str, event: str, parameter: str
323
+ ) -> None:
324
+ """Handle a HDMI output change event."""
325
+ if event == "VS" and parameter[0:4] == "MONI":
326
+ self._hdmi_output = HDMI_OUTPUT_MAP_LABELS[parameter]
327
+
328
+ async def _async_hdmi_audio_decode_callback(
329
+ self, zone: str, event: str, parameter: str
330
+ ) -> None:
331
+ """Handle a HDMI Audio Decode mode change event."""
332
+ if event == "VS" and parameter[0:5] == "AUDIO":
333
+ self._hdmi_audio_decode = parameter[6:]
334
+
335
+ async def _async_video_processing_mode_callback(
336
+ self, zone: str, event: str, parameter: str
337
+ ) -> None:
338
+ """Handle a Video Processing Mode change event."""
339
+ if event == "VS" and parameter[0:3] == "VPM":
340
+ self._video_processing_mode = VIDEO_PROCESSING_MODES_MAP_LABELS[
341
+ parameter[3:]
342
+ ]
343
+
344
+ async def _async_tactile_transducer_callback(
345
+ self, zone: str, event: str, parameter: str
346
+ ) -> None:
347
+ """Handle a tactile transducer change event."""
348
+ key_value = parameter.split()
349
+ if len(key_value) != 2 or parameter[0:3] != "TTR":
350
+ return
351
+
352
+ key = key_value[0]
353
+ value = key_value[1]
354
+ if value == "END":
355
+ return
356
+
357
+ if key == "TTR":
358
+ self._tactile_transducer = value
359
+ elif key == "TTRLEV":
360
+ self._tactile_transducer_level = CHANNEL_VOLUME_MAP[value]
361
+ elif key == "TTRLPF":
362
+ self._tactile_transducer_lpf = f"{int(value)} Hz"
363
+
364
+ async def _async_speaker_preset_callback(
365
+ self, zone: str, event: str, parameter: str
366
+ ) -> None:
367
+ """Handle a speaker preset change event."""
368
+ if event != "SP":
369
+ return
370
+
371
+ if parameter[0:2] == "PR":
372
+ self._speaker_preset = int(parameter[3:])
373
+
374
+ async def _async_bt_callback(self, zone: str, event: str, parameter: str) -> None:
375
+ """Handle a Bluetooth change event."""
376
+ if event != "BT" or parameter[0:2] != "TX":
377
+ return
378
+
379
+ if parameter[3:] in ("ON", "OFF"):
380
+ self._bt_transmitter = parameter[3:]
381
+ else:
382
+ self._bt_output_mode = BLUETOOTH_OUTPUT_MAP_LABELS[parameter[3:]]
383
+
384
+ async def _async_delay_time_callback(
385
+ self, zone: str, event: str, parameter: str
386
+ ) -> None:
387
+ """Handle a delay time change event."""
388
+ if event != "PS" or parameter[0:3] != "DEL":
389
+ return
390
+
391
+ self._delay_time = int(parameter[4:])
392
+
393
+ async def _async_audio_restorer_callback(
394
+ self, zone: str, event: str, parameter: str
395
+ ) -> None:
396
+ """Handle an audio restorer change event."""
397
+ if event != "PS" or parameter[0:4] != "RSTR":
398
+ return
399
+
400
+ self._audio_restorer = AUDIO_RESTORER_MAP_LABELS[parameter[5:]]
401
+
402
+ async def _async_graphic_eq_callback(
403
+ self, zone: str, event: str, parameter: str
404
+ ) -> None:
405
+ """Handle a Graphic EQ change event."""
406
+ if parameter[0:3] != "GEQ":
407
+ return
408
+
409
+ self._graphic_eq = parameter[4:]
410
+
411
+ async def _async_headphone_eq_callback(
412
+ self, zone: str, event: str, parameter: str
413
+ ) -> None:
414
+ """Handle a Headphone EQ change event."""
415
+ if parameter[0:3] != "HEQ":
416
+ return
417
+
418
+ self._headphone_eq = parameter[4:]
419
+
132
420
  def get_own_zone(self) -> str:
133
421
  """
134
422
  Get zone from actual instance.
@@ -146,15 +434,15 @@ class DenonAVRDeviceInfo:
146
434
  _LOGGER.debug("Starting device setup")
147
435
  # Reduce read timeout during receiver identification
148
436
  # deviceinfo endpoint takes very long to return 404
149
- timeout = self.api.timeout
150
- self.api.timeout = httpx.Timeout(self.api.timeout.connect)
437
+ read_timeout = self.api.read_timeout
438
+ self.api.read_timeout = self.api.timeout
151
439
  try:
152
440
  _LOGGER.debug("Identifying receiver")
153
441
  await self.async_identify_receiver()
154
442
  _LOGGER.debug("Getting device info")
155
443
  await self.async_get_device_info()
156
444
  finally:
157
- self.api.timeout = timeout
445
+ self.api.read_timeout = read_timeout
158
446
  _LOGGER.debug("Identifying update method")
159
447
  await self.async_identify_update_method()
160
448
 
@@ -168,6 +456,31 @@ class DenonAVRDeviceInfo:
168
456
  power_event = "Z3"
169
457
  self.telnet_api.register_callback(power_event, self._async_power_callback)
170
458
 
459
+ self.telnet_api.register_callback("MN", self._async_settings_menu_callback)
460
+ self.telnet_api.register_callback("DIM", self._async_dimmer_callback)
461
+ self.telnet_api.register_callback("PS", self._async_delay_callback)
462
+ self.telnet_api.register_callback("ECO", self._async_eco_mode_callback)
463
+ self.telnet_api.register_callback("VS", self._async_hdmi_output_callback)
464
+ self.telnet_api.register_callback(
465
+ "VS", self._async_hdmi_audio_decode_callback
466
+ )
467
+ self.telnet_api.register_callback(
468
+ "VS", self._async_video_processing_mode_callback
469
+ )
470
+ self.telnet_api.register_callback(
471
+ "SS", self._async_tactile_transducer_callback
472
+ )
473
+ self.telnet_api.register_callback("STBY", self._async_auto_standby_callback)
474
+ self.telnet_api.register_callback("SLP", self._async_auto_sleep_callback)
475
+ self.telnet_api.register_callback("PS", self._async_room_size_callback)
476
+ self.telnet_api.register_callback("TR", self._async_trigger_callback)
477
+ self.telnet_api.register_callback("SP", self._async_speaker_preset_callback)
478
+ self.telnet_api.register_callback("BT", self._async_bt_callback)
479
+ self.telnet_api.register_callback("PS", self._async_delay_time_callback)
480
+ self.telnet_api.register_callback("PS", self._async_audio_restorer_callback)
481
+ self.telnet_api.register_callback("PS", self._async_graphic_eq_callback)
482
+ self.telnet_api.register_callback("PS", self._async_headphone_eq_callback)
483
+
171
484
  self._is_setup = True
172
485
  _LOGGER.debug("Finished device setup")
173
486
 
@@ -323,7 +636,7 @@ class DenonAVRDeviceInfo:
323
636
  self._set_friendly_name(xml)
324
637
 
325
638
  async def async_verify_avr_2016_update_method(
326
- self, cache_id: Hashable = None
639
+ self, *, cache_id: Hashable = None
327
640
  ) -> None:
328
641
  """Verify if avr 2016 update method is working."""
329
642
  # Nothing to do if Appcommand.xml interface is not supported
@@ -522,11 +835,241 @@ class DenonAVRDeviceInfo:
522
835
  """
523
836
  return self._power
524
837
 
838
+ @property
839
+ def settings_menu(self) -> Optional[bool]:
840
+ """
841
+ Returns the settings menu state of the device.
842
+
843
+ Only available if using Telnet.
844
+ """
845
+ return self._settings_menu
846
+
847
+ @property
848
+ def dimmer(self) -> Optional[str]:
849
+ """
850
+ Returns the dimmer state of the device.
851
+
852
+ Only available if using Telnet.
853
+
854
+ Possible values are: "Off", "Dark", "Dim" and "Bright"
855
+ """
856
+ return self._dimmer
857
+
858
+ @property
859
+ def auto_standby(self) -> Optional[str]:
860
+ """
861
+ Return the auto-standby state of the device.
862
+
863
+ Only available if using Telnet.
864
+
865
+ Possible values are: "OFF", "15M", "30M", "60M"
866
+ """
867
+ return self._auto_standby
868
+
869
+ @property
870
+ def sleep(self) -> Optional[Union[str, int]]:
871
+ """
872
+ Return the sleep timer for the device.
873
+
874
+ Only available if using Telnet.
875
+
876
+ Possible values are: "OFF" and 1-120 (in minutes)
877
+ """
878
+ return self._sleep
879
+
880
+ @property
881
+ def delay(self) -> Optional[int]:
882
+ """
883
+ Return the audio delay for the device in ms.
884
+
885
+ Only available if using Telnet.
886
+ """
887
+ return self._delay
888
+
889
+ @property
890
+ def eco_mode(self) -> Optional[str]:
891
+ """
892
+ Returns the eco-mode for the device.
893
+
894
+ Only available if using Telnet.
895
+
896
+ Possible values are: "Off", "On", "Auto"
897
+ """
898
+ return self._eco_mode
899
+
900
+ @property
901
+ def hdmi_output(self) -> Optional[str]:
902
+ """
903
+ Returns the HDMI-output for the device.
904
+
905
+ Only available if using Telnet.
906
+
907
+ Possible values are: "Auto", "HDMI1", "HDMI2"
908
+ """
909
+ return self._hdmi_output
910
+
911
+ @property
912
+ def hdmi_audio_decode(self) -> Optional[str]:
913
+ """
914
+ Returns the HDMI Audio Decode for the device.
915
+
916
+ Only available if using Telnet.
917
+
918
+ Possible values are: "AMP", "TV"
919
+ """
920
+ return self._hdmi_audio_decode
921
+
922
+ @property
923
+ def video_processing_mode(self) -> Optional[str]:
924
+ """
925
+ Return the video processing mode for the device.
926
+
927
+ Only available if using Telnet.
928
+
929
+ Possible values are: "Auto", "Game", "Movie", "Bypass"
930
+ """
931
+ return self._video_processing_mode
932
+
933
+ @property
934
+ def tactile_transducer(self) -> Optional[str]:
935
+ """
936
+ Return the tactile transducer state of the device.
937
+
938
+ Only available if using Telnet.
939
+ """
940
+ return self._tactile_transducer
941
+
942
+ @property
943
+ def tactile_transducer_level(self) -> Optional[float]:
944
+ """
945
+ Return the tactile transducer level in dB.
946
+
947
+ Only available if using Telnet.
948
+ """
949
+ return self._tactile_transducer_level
950
+
951
+ @property
952
+ def tactile_transducer_lpf(self) -> Optional[str]:
953
+ """
954
+ Return the tactile transducer low pass filter frequency.
955
+
956
+ Only available if using Telnet.
957
+ """
958
+ return self._tactile_transducer_lpf
959
+
960
+ @property
961
+ def room_size(self) -> Optional[str]:
962
+ """
963
+ Return the room size for the device.
964
+
965
+ Only available if using Telnet.
966
+
967
+ Possible values are: "S", "MS", "M", "ML", "L"
968
+ """
969
+ return self._room_size
970
+
971
+ @property
972
+ def triggers(self) -> Dict[int, str]:
973
+ """
974
+ Return the triggers and their statuses for the device.
975
+
976
+ Only available if using Telnet.
977
+ """
978
+ return self._triggers
979
+
980
+ @property
981
+ def speaker_preset(self) -> Optional[int]:
982
+ """
983
+ Return the speaker preset for the device.
984
+
985
+ Only available if using Telnet.
986
+
987
+ Possible values are: "1", "2"
988
+ """
989
+ return self._speaker_preset
990
+
991
+ @property
992
+ def bt_transmitter(self) -> Optional[bool]:
993
+ """
994
+ Return the Bluetooth transmitter state for the device.
995
+
996
+ Only available if using Telnet.
997
+ """
998
+ return self._bt_transmitter
999
+
1000
+ @property
1001
+ def bt_output_mode(self) -> Optional[str]:
1002
+ """
1003
+ Return the Bluetooth output mode for the device.
1004
+
1005
+ Only available if using Telnet.
1006
+
1007
+ Possible values are: "Bluetooth + Speakers", "Bluetooth Only"
1008
+ """
1009
+ return self._bt_output_mode
1010
+
1011
+ @property
1012
+ def delay_time(self) -> Optional[int]:
1013
+ """
1014
+ Return the delay time for the device in ms.
1015
+
1016
+ Only available if using Telnet.
1017
+ """
1018
+ return self._delay_time
1019
+
1020
+ @property
1021
+ def audio_restorer(self) -> Optional[str]:
1022
+ """
1023
+ Return the audio restorer for the device.
1024
+
1025
+ Only available if using Telnet.
1026
+
1027
+ Possible values are: "Off", "Low", "Medium", "High"
1028
+ """
1029
+ return self._audio_restorer
1030
+
1031
+ @property
1032
+ def graphic_eq(self) -> Optional[bool]:
1033
+ """
1034
+ Return the Graphic EQ status for the device.
1035
+
1036
+ Only available if using Telnet.
1037
+ """
1038
+ return self._graphic_eq
1039
+
1040
+ @property
1041
+ def headphone_eq(self) -> Optional[bool]:
1042
+ """
1043
+ Return the Headphone EQ status for the device.
1044
+
1045
+ Only available if using Telnet.
1046
+ """
1047
+ return self._headphone_eq
1048
+
525
1049
  @property
526
1050
  def telnet_available(self) -> bool:
527
1051
  """Return true if telnet is connected and healthy."""
528
1052
  return self.telnet_api.connected and self.telnet_api.healthy
529
1053
 
1054
+ ##########
1055
+ # Getter #
1056
+ ##########
1057
+
1058
+ def get_trigger(self, trigger: int) -> Optional[str]:
1059
+ """
1060
+ Return the status of a specific trigger.
1061
+
1062
+ Only available if using Telnet.
1063
+
1064
+ Valid trigger values are 1-3.
1065
+ """
1066
+ if trigger < 1 or trigger > 3:
1067
+ raise AvrCommandError(f"Invalid trigger {trigger}, must be between 1 and 3")
1068
+
1069
+ if self._triggers is None:
1070
+ return None
1071
+ return self._triggers.get(trigger)
1072
+
530
1073
  ##########
531
1074
  # Setter #
532
1075
  ##########
@@ -553,7 +1096,7 @@ class DenonAVRDeviceInfo:
553
1096
  """Cursor Up on receiver via HTTP get command."""
554
1097
  if self.telnet_available:
555
1098
  await self.telnet_api.async_send_commands(
556
- self.telnet_commands.command_cusor_up
1099
+ self.telnet_commands.command_cusor_up, skip_confirmation=True
557
1100
  )
558
1101
  else:
559
1102
  await self.api.async_get_command(self.urls.command_cusor_up)
@@ -562,7 +1105,7 @@ class DenonAVRDeviceInfo:
562
1105
  """Cursor Down on receiver via HTTP get command."""
563
1106
  if self.telnet_available:
564
1107
  await self.telnet_api.async_send_commands(
565
- self.telnet_commands.command_cusor_down
1108
+ self.telnet_commands.command_cusor_down, skip_confirmation=True
566
1109
  )
567
1110
  else:
568
1111
  await self.api.async_get_command(self.urls.command_cusor_down)
@@ -571,7 +1114,7 @@ class DenonAVRDeviceInfo:
571
1114
  """Cursor Left on receiver via HTTP get command."""
572
1115
  if self.telnet_available:
573
1116
  await self.telnet_api.async_send_commands(
574
- self.telnet_commands.command_cusor_left
1117
+ self.telnet_commands.command_cusor_left, skip_confirmation=True
575
1118
  )
576
1119
  else:
577
1120
  await self.api.async_get_command(self.urls.command_cusor_left)
@@ -580,7 +1123,7 @@ class DenonAVRDeviceInfo:
580
1123
  """Cursor Right on receiver via HTTP get command."""
581
1124
  if self.telnet_available:
582
1125
  await self.telnet_api.async_send_commands(
583
- self.telnet_commands.command_cusor_right
1126
+ self.telnet_commands.command_cusor_right, skip_confirmation=True
584
1127
  )
585
1128
  else:
586
1129
  await self.api.async_get_command(self.urls.command_cusor_right)
@@ -589,7 +1132,7 @@ class DenonAVRDeviceInfo:
589
1132
  """Cursor Enter on receiver via HTTP get command."""
590
1133
  if self.telnet_available:
591
1134
  await self.telnet_api.async_send_commands(
592
- self.telnet_commands.command_cusor_enter
1135
+ self.telnet_commands.command_cusor_enter, skip_confirmation=True
593
1136
  )
594
1137
  else:
595
1138
  await self.api.async_get_command(self.urls.command_cusor_enter)
@@ -597,38 +1140,664 @@ class DenonAVRDeviceInfo:
597
1140
  async def async_back(self) -> None:
598
1141
  """Back command on receiver via HTTP get command."""
599
1142
  if self.telnet_available:
600
- await self.telnet_api.async_send_commands(self.telnet_commands.command_back)
1143
+ await self.telnet_api.async_send_commands(
1144
+ self.telnet_commands.command_back, skip_confirmation=True
1145
+ )
601
1146
  else:
602
1147
  await self.api.async_get_command(self.urls.command_back)
603
1148
 
604
1149
  async def async_info(self) -> None:
605
1150
  """Info OSD on receiver via HTTP get command."""
606
1151
  if self.telnet_available:
607
- await self.telnet_api.async_send_commands(self.telnet_commands.command_info)
1152
+ await self.telnet_api.async_send_commands(
1153
+ self.telnet_commands.command_info, skip_confirmation=True
1154
+ )
608
1155
  else:
609
1156
  await self.api.async_get_command(self.urls.command_info)
610
1157
 
611
1158
  async def async_options(self) -> None:
612
1159
  """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
1160
  if self.telnet_available:
619
- if res is not None and res == "MNMEN ON":
1161
+ await self.telnet_api.async_send_commands(
1162
+ self.telnet_commands.command_options, skip_confirmation=True
1163
+ )
1164
+ else:
1165
+ await self.api.async_get_command(self.urls.command_options)
1166
+
1167
+ async def async_settings_menu(self) -> None:
1168
+ """
1169
+ Options menu on receiver via HTTP get command.
1170
+
1171
+ Only available if using Telnet.
1172
+ """
1173
+ if self._settings_menu:
1174
+ await self.telnet_api.async_send_commands(
1175
+ self.telnet_commands.command_setup_close
1176
+ )
1177
+ else:
1178
+ await self.telnet_api.async_send_commands(
1179
+ self.telnet_commands.command_setup_open
1180
+ )
1181
+
1182
+ async def async_channel_level_adjust(self) -> None:
1183
+ """Toggle the channel level adjust menu on receiver via HTTP get command."""
1184
+ if self.telnet_available:
1185
+ await self.telnet_api.async_send_commands(
1186
+ self.telnet_commands.command_channel_level_adjust
1187
+ )
1188
+ else:
1189
+ await self.api.async_get_command(self.urls.command_channel_level_adjust)
1190
+
1191
+ async def async_dimmer_toggle(self) -> None:
1192
+ """Toggle dimmer on receiver via HTTP get command."""
1193
+ if self.telnet_available:
1194
+ await self.telnet_api.async_send_commands(
1195
+ self.telnet_commands.command_dimmer_toggle
1196
+ )
1197
+ else:
1198
+ await self.api.async_get_command(self.urls.command_dimmer_toggle)
1199
+
1200
+ async def async_dimmer(self, mode: DimmerModes) -> None:
1201
+ """Set dimmer mode on receiver via HTTP get command."""
1202
+ if mode not in DimmerModes:
1203
+ raise AvrCommandError("Invalid dimmer mode")
1204
+
1205
+ mapped_mode = DIMMER_MODE_MAP[mode]
1206
+ if self.telnet_available:
1207
+ await self.telnet_api.async_send_commands(
1208
+ self.telnet_commands.command_dimmer_set.format(mode=mapped_mode)
1209
+ )
1210
+ else:
1211
+ await self.api.async_get_command(
1212
+ self.urls.command_dimmer_set.format(mode=mapped_mode)
1213
+ )
1214
+
1215
+ async def async_tactile_transducer_on(self) -> None:
1216
+ """Turn on tactile transducer on receiver via HTTP get command."""
1217
+ if self.telnet_available:
1218
+ await self.telnet_api.async_send_commands(
1219
+ self.telnet_commands.command_tactile_transducer.format(mode="ON")
1220
+ )
1221
+ else:
1222
+ await self.api.async_get_command(
1223
+ self.urls.command_tactile_transducer.format(mode="ON")
1224
+ )
1225
+
1226
+ async def async_auto_standby(self, auto_standby: AutoStandbys) -> None:
1227
+ """Set auto standby on receiver via HTTP get command."""
1228
+ if auto_standby not in self._auto_standbys:
1229
+ raise AvrCommandError("Invalid Auto Standby mode")
1230
+ if self.telnet_available:
1231
+ await self.telnet_api.async_send_commands(
1232
+ self.telnet_commands.command_auto_standby.format(mode=auto_standby)
1233
+ )
1234
+ else:
1235
+ await self.api.async_get_command(
1236
+ self.urls.command_auto_standby.format(mode=auto_standby)
1237
+ )
1238
+
1239
+ async def async_sleep(self, sleep: Union[Literal["OFF"], int]) -> None:
1240
+ """
1241
+ Set auto standby on receiver via HTTP get command.
1242
+
1243
+ Valid sleep values are "OFF" and 1-120 (in minutes)
1244
+ """
1245
+ if sleep != "OFF" and sleep not in range(1, 120):
1246
+ raise AvrCommandError("Invalid sleep value")
1247
+
1248
+ local_sleep = f"{sleep:03}" if isinstance(sleep, int) else sleep
1249
+ if self.telnet_available:
1250
+ await self.telnet_api.async_send_commands(
1251
+ self.telnet_commands.command_sleep.format(value=local_sleep)
1252
+ )
1253
+ else:
1254
+ await self.api.async_get_command(
1255
+ self.urls.command_sleep.format(value=local_sleep)
1256
+ )
1257
+
1258
+ async def async_tactile_transducer_off(self) -> None:
1259
+ """Turn on tactile transducer on receiver via HTTP get command."""
1260
+ if self.telnet_available:
1261
+ await self.telnet_api.async_send_commands(
1262
+ self.telnet_commands.command_tactile_transducer.format(mode="OFF")
1263
+ )
1264
+ else:
1265
+ await self.api.async_get_command(
1266
+ self.urls.command_tactile_transducer.format(mode="OFF")
1267
+ )
1268
+
1269
+ async def async_tactile_transducer_toggle(self) -> None:
1270
+ """
1271
+ Turn on tactile transducer on receiver via HTTP get command.
1272
+
1273
+ Only available if using Telnet.
1274
+ """
1275
+ if self._tactile_transducer != "OFF":
1276
+ await self.async_tactile_transducer_off()
1277
+ else:
1278
+ await self.async_tactile_transducer_on()
1279
+
1280
+ async def async_tactile_transducer_level_up(self) -> None:
1281
+ """Increase the transducer level on receiver via HTTP get command."""
1282
+ if self.telnet_available:
1283
+ await self.telnet_api.async_send_commands(
1284
+ self.telnet_commands.command_tactile_transducer_level.format(mode="UP")
1285
+ )
1286
+ else:
1287
+ await self.api.async_get_command(
1288
+ self.urls.command_tactile_transducer_level.format(mode="UP")
1289
+ )
1290
+
1291
+ async def async_tactile_transducer_level_down(self) -> None:
1292
+ """Decrease the transducer level on receiver via HTTP get command."""
1293
+ if self.telnet_available:
1294
+ await self.telnet_api.async_send_commands(
1295
+ self.telnet_commands.command_tactile_transducer_level.format(
1296
+ mode="DOWN"
1297
+ )
1298
+ )
1299
+ else:
1300
+ await self.api.async_get_command(
1301
+ self.urls.command_tactile_transducer_level.format(mode="DOWN")
1302
+ )
1303
+
1304
+ async def async_transducer_lpf(self, lpf: TransducerLPFs):
1305
+ """Set transducer low pass filter on receiver via HTTP get command."""
1306
+ if lpf not in self._tactile_transducer_lpfs:
1307
+ raise AvrCommandError("Invalid tactile transducer low pass filter")
1308
+
1309
+ frequency = lpf.split()[0]
1310
+ if len(frequency) == 2:
1311
+ frequency = f"0{frequency}"
1312
+ if self.telnet_available:
1313
+ await self.telnet_api.async_send_commands(
1314
+ self.telnet_commands.command_tactile_transducer_lpf.format(
1315
+ frequency=frequency
1316
+ )
1317
+ )
1318
+ else:
1319
+ await self.api.async_get_command(
1320
+ self.urls.command_tactile_transducer_lpf.format(frequency=frequency)
1321
+ )
1322
+
1323
+ async def async_room_size(self, room_size: RoomSizes) -> None:
1324
+ """Set room size on receiver via HTTP get command."""
1325
+ if room_size not in self._room_sizes:
1326
+ raise AvrCommandError("Invalid room size")
1327
+
1328
+ if self.telnet_available:
1329
+ await self.telnet_api.async_send_commands(
1330
+ self.telnet_commands.command_room_size.format(size=room_size)
1331
+ )
1332
+ else:
1333
+ await self.api.async_get_command(
1334
+ self.urls.command_room_size.format(size=room_size)
1335
+ )
1336
+
1337
+ async def async_trigger_on(self, trigger: int) -> None:
1338
+ """
1339
+ Set trigger to ON on receiver via HTTP get command.
1340
+
1341
+ :param trigger: Trigger number to set to ON. Valid values are 1-3.
1342
+ """
1343
+ if trigger < 1 or trigger > 3:
1344
+ raise AvrCommandError("Trigger number must be between 1 and 3")
1345
+
1346
+ if self.telnet_available:
1347
+ await self.telnet_api.async_send_commands(
1348
+ self.telnet_commands.command_trigger.format(number=trigger, mode="ON")
1349
+ )
1350
+ else:
1351
+ await self.api.async_get_command(
1352
+ self.urls.command_trigger.format(number=trigger, mode="ON")
1353
+ )
1354
+
1355
+ async def async_trigger_off(self, trigger: int) -> None:
1356
+ """
1357
+ Set trigger to OFF on receiver via HTTP get command.
1358
+
1359
+ :param trigger: Trigger number to set to OFF. Valid values are 1-3.
1360
+ """
1361
+ if trigger < 1 or trigger > 3:
1362
+ raise AvrCommandError("Trigger number must be between 1 and 3")
1363
+
1364
+ if self.telnet_available:
1365
+ await self.telnet_api.async_send_commands(
1366
+ self.telnet_commands.command_trigger.format(number=trigger, mode="OFF")
1367
+ )
1368
+ else:
1369
+ await self.api.async_get_command(
1370
+ self.urls.command_trigger.format(number=trigger, mode="OFF")
1371
+ )
1372
+
1373
+ async def async_trigger_toggle(self, trigger: int) -> None:
1374
+ """
1375
+ Toggle trigger on receiver via HTTP get command.
1376
+
1377
+ Only available if using Telnet.
1378
+
1379
+ :param trigger: Trigger number to toggle. Valid values are 1-3.
1380
+ """
1381
+ if trigger < 1 or trigger > 3:
1382
+ raise AvrCommandError("Trigger number must be between 1 and 3")
1383
+
1384
+ trigger_status = self._triggers.get(trigger)
1385
+ if trigger_status == "ON":
1386
+ await self.async_trigger_off(trigger)
1387
+ else:
1388
+ await self.async_trigger_on(trigger)
1389
+
1390
+ async def async_quick_select_mode(self, quick_select_number: int) -> None:
1391
+ """
1392
+ Set quick select mode on receiver via HTTP get command.
1393
+
1394
+ :param quick_select_number: Quick select number to set. Valid values are 1-5.
1395
+ """
1396
+ if quick_select_number not in range(1, 5):
1397
+ raise AvrCommandError("Quick select number must be between 1 and 5")
1398
+
1399
+ if self.telnet_available:
1400
+ await self.telnet_api.async_send_commands(
1401
+ self.telnet_commands.command_quick_select_mode.format(
1402
+ number=quick_select_number
1403
+ )
1404
+ )
1405
+ else:
1406
+ await self.api.async_get_command(
1407
+ self.urls.command_quick_select_mode.format(number=quick_select_number)
1408
+ )
1409
+
1410
+ async def async_quick_select_memory(self, quick_select_number: int) -> None:
1411
+ """
1412
+ Set quick select memory on receiver via HTTP get command.
1413
+
1414
+ :param quick_select_number: Quick select number to set. Valid values are 1-5.
1415
+ """
1416
+ if quick_select_number not in range(1, 5):
1417
+ raise AvrCommandError("Quick select number must be between 1 and 5")
1418
+
1419
+ if self.telnet_available:
1420
+ await self.telnet_api.async_send_commands(
1421
+ self.telnet_commands.command_quick_select_memory.format(
1422
+ number=quick_select_number
1423
+ )
1424
+ )
1425
+ else:
1426
+ await self.api.async_get_command(
1427
+ self.urls.command_quick_select_memory.format(number=quick_select_number)
1428
+ )
1429
+
1430
+ async def async_delay_up(self) -> None:
1431
+ """Delay up on receiver via HTTP get command."""
1432
+ if self.telnet_available:
1433
+ await self.telnet_api.async_send_commands(
1434
+ self.telnet_commands.command_delay_up
1435
+ )
1436
+ else:
1437
+ await self.api.async_get_command(self.urls.command_delay_up)
1438
+
1439
+ async def async_delay_down(self) -> None:
1440
+ """Delay down on receiver via HTTP get command."""
1441
+ if self.telnet_available:
1442
+ await self.telnet_api.async_send_commands(
1443
+ self.telnet_commands.command_delay_down
1444
+ )
1445
+ else:
1446
+ await self.api.async_get_command(self.urls.command_delay_down)
1447
+
1448
+ async def async_eco_mode(self, mode: EcoModes) -> None:
1449
+ """Set Eco mode."""
1450
+ if mode not in EcoModes:
1451
+ raise AvrCommandError("Invalid Eco mode")
1452
+
1453
+ mapped_mode = ECO_MODE_MAP[mode]
1454
+ if self.telnet_available:
1455
+ await self.telnet_api.async_send_commands(
1456
+ self.telnet_commands.command_eco_mode.format(mode=mapped_mode)
1457
+ )
1458
+ else:
1459
+ await self.api.async_get_command(
1460
+ self.urls.command_eco_mode.format(mode=mapped_mode)
1461
+ )
1462
+
1463
+ async def async_hdmi_output(self, output: HDMIOutputs) -> None:
1464
+ """Set HDMI output."""
1465
+ if output not in HDMIOutputs:
1466
+ raise AvrCommandError("Invalid HDMI output mode")
1467
+
1468
+ mapped_output = HDMIOutputs[output]
1469
+ if self.telnet_available:
1470
+ await self.telnet_api.async_send_commands(
1471
+ self.telnet_commands.command_hdmi_output.format(output=mapped_output)
1472
+ )
1473
+ else:
1474
+ await self.api.async_get_command(
1475
+ self.urls.command_hdmi_output.format(output=mapped_output)
1476
+ )
1477
+
1478
+ async def async_hdmi_audio_decode(self, mode: HDMIAudioDecodes) -> None:
1479
+ """Set HDMI Audio Decode mode on receiver via HTTP get command."""
1480
+ if mode not in self._hdmi_audio_decodes:
1481
+ raise AvrCommandError("Invalid HDMI Audio Decode mode")
1482
+
1483
+ if self.telnet_available:
1484
+ await self.telnet_api.async_send_commands(
1485
+ self.telnet_commands.command_hdmi_audio_decode.format(mode=mode)
1486
+ )
1487
+ else:
1488
+ await self.api.async_get_command(
1489
+ self.urls.command_hdmi_audio_decode.format(mode=mode)
1490
+ )
1491
+
1492
+ async def async_video_processing_mode(self, mode: VideoProcessingModes) -> None:
1493
+ """Set video processing mode on receiver via HTTP get command."""
1494
+ if mode not in self._video_processing_modes:
1495
+ raise AvrCommandError("Invalid video processing mode")
1496
+ processing_mode = VIDEO_PROCESSING_MODES_MAP[mode]
1497
+ if self.telnet_available:
1498
+ await self.telnet_api.async_send_commands(
1499
+ self.telnet_commands.command_video_processing_mode.format(
1500
+ mode=processing_mode
1501
+ )
1502
+ )
1503
+ else:
1504
+ await self.api.async_get_command(
1505
+ self.urls.command_video_processing_mode.format(mode=processing_mode)
1506
+ )
1507
+
1508
+ async def async_status(self) -> str:
1509
+ """Get status of receiver via HTTP get command."""
1510
+ if "denon" not in self.manufacturer.lower():
1511
+ raise AvrCommandError("Status command is only supported for Denon devices")
1512
+ return await self.api.async_get_command(self.urls.command_status)
1513
+
1514
+ async def async_system_reset(self) -> None:
1515
+ """DANGER! Reset the receiver via HTTP get command."""
1516
+ if self.telnet_available:
1517
+ await self.telnet_api.async_send_commands(
1518
+ self.telnet_commands.command_system_reset
1519
+ )
1520
+ else:
1521
+ await self.api.async_get_command(self.urls.command_system_reset)
1522
+
1523
+ async def async_network_restart(self) -> None:
1524
+ """Restart the network on the receiver via HTTP get command."""
1525
+ if self.telnet_available:
1526
+ await self.telnet_api.async_send_commands(
1527
+ self.telnet_commands.command_network_restart
1528
+ )
1529
+ else:
1530
+ await self.api.async_get_command(self.urls.command_network_restart)
1531
+
1532
+ async def async_speaker_preset(self, preset: int) -> None:
1533
+ """
1534
+ Set speaker preset on receiver via HTTP get command.
1535
+
1536
+ Valid preset values are 1-2.
1537
+ """
1538
+ if preset < 1 or preset > 2:
1539
+ raise AvrCommandError("Speaker preset number must be 1 or 2")
1540
+
1541
+ if self.telnet_available:
1542
+ await self.telnet_api.async_send_commands(
1543
+ self.telnet_commands.command_speaker_preset.format(number=preset)
1544
+ )
1545
+ else:
1546
+ await self.api.async_get_command(
1547
+ self.urls.command_speaker_preset.format(number=preset)
1548
+ )
1549
+
1550
+ async def async_speaker_preset_toggle(self) -> None:
1551
+ """
1552
+ Toggle speaker preset on receiver via HTTP get command.
1553
+
1554
+ Only available if using Telnet.
1555
+ """
1556
+ speaker_preset = 1 if self._speaker_preset == 2 else 2
1557
+ await self.async_speaker_preset(speaker_preset)
1558
+
1559
+ async def async_bt_transmitter_on(
1560
+ self,
1561
+ ) -> None:
1562
+ """Turn on Bluetooth transmitter on receiver via HTTP get command."""
1563
+ if self.telnet_available:
1564
+ await self.telnet_api.async_send_commands(
1565
+ self.telnet_commands.command_bluetooth_transmitter.format(mode="ON")
1566
+ )
1567
+ else:
1568
+ await self.api.async_get_command(
1569
+ self.urls.command_bluetooth_transmitter.format(mode="ON")
1570
+ )
1571
+
1572
+ async def async_bt_transmitter_off(
1573
+ self,
1574
+ ) -> None:
1575
+ """Turn off Bluetooth transmitter on receiver via HTTP get command."""
1576
+ if self.telnet_available:
1577
+ await self.telnet_api.async_send_commands(
1578
+ self.telnet_commands.command_bluetooth_transmitter.format(mode="OFF")
1579
+ )
1580
+ else:
1581
+ await self.api.async_get_command(
1582
+ self.urls.command_bluetooth_transmitter.format(mode="OFF")
1583
+ )
1584
+
1585
+ async def async_bt_transmitter_toggle(self) -> None:
1586
+ """
1587
+ Toggle Bluetooth transmitter mode on receiver via HTTP get command.
1588
+
1589
+ Only available if using Telnet.
1590
+ """
1591
+ if self.bt_transmitter:
1592
+ await self.async_bt_transmitter_off()
1593
+ else:
1594
+ await self.async_bt_transmitter_on()
1595
+
1596
+ async def async_bt_output_mode(self, mode: BluetoothOutputModes) -> None:
1597
+ """Set Bluetooth transmitter mode on receiver via HTTP get command."""
1598
+ if mode not in self._bt_output_modes:
1599
+ raise AvrCommandError("Invalid Bluetooth output mode")
1600
+
1601
+ mapped_mode = BLUETOOTH_OUTPUT_MODES_MAP[mode]
1602
+ if self.telnet_available:
1603
+ await self.telnet_api.async_send_commands(
1604
+ self.telnet_commands.command_bluetooth_transmitter.format(
1605
+ mode=mapped_mode
1606
+ )
1607
+ )
1608
+ else:
1609
+ await self.api.async_get_command(
1610
+ self.urls.command_bluetooth_transmitter.format(mode=mapped_mode)
1611
+ )
1612
+
1613
+ async def async_bt_output_mode_toggle(self) -> None:
1614
+ """
1615
+ Toggle Bluetooth output mode on receiver via HTTP get command.
1616
+
1617
+ Only available if using Telnet.
1618
+ """
1619
+ if self.bt_output_mode == "Bluetooth + Speakers":
1620
+ await self.async_bt_output_mode("Bluetooth Only")
1621
+ else:
1622
+ await self.async_bt_output_mode("Bluetooth + Speakers")
1623
+
1624
+ async def async_delay_time_up(self) -> None:
1625
+ """Delay time up on receiver via HTTP get command."""
1626
+ if self.telnet_available:
1627
+ await self.telnet_api.async_send_commands(
1628
+ self.telnet_commands.command_delay_time.format(value="UP")
1629
+ )
1630
+ else:
1631
+ await self.api.async_get_command(
1632
+ self.urls.command_delay_time.format(value="UP")
1633
+ )
1634
+
1635
+ async def async_delay_time_down(self) -> None:
1636
+ """Delay time up on receiver via HTTP get command."""
1637
+ if self.telnet_available:
1638
+ await self.telnet_api.async_send_commands(
1639
+ self.telnet_commands.command_delay_time.format(value="DOWN")
1640
+ )
1641
+ else:
1642
+ await self.api.async_get_command(
1643
+ self.urls.command_delay_time.format(value="DOWN")
1644
+ )
1645
+
1646
+ async def async_delay_time(self, delay_time: int) -> None:
1647
+ """
1648
+ Set delay time on receiver via HTTP get command.
1649
+
1650
+ :param delay_time: Delay time in ms. Valid values are 0-999.
1651
+ """
1652
+ if delay_time < 0 or delay_time > 999:
1653
+ raise AvrCommandError("Invalid delay time value")
1654
+
1655
+ if self.telnet_available:
1656
+ await self.telnet_api.async_send_commands(
1657
+ self.telnet_commands.command_delay_time.format(value=delay_time)
1658
+ )
1659
+ else:
1660
+ await self.api.async_get_command(
1661
+ self.urls.command_delay_time.format(value=delay_time)
1662
+ )
1663
+
1664
+ async def async_audio_restorer(self, mode: AudioRestorers):
1665
+ """Set audio restorer on receiver via HTTP get command."""
1666
+ if mode not in self._audio_restorers:
1667
+ raise AvrCommandError("Invalid audio restorer mode")
1668
+
1669
+ mapped_mode = AUDIO_RESTORER_MAP[mode]
1670
+ if self.telnet_available:
1671
+ await self.telnet_api.async_send_commands(
1672
+ self.telnet_commands.command_audio_restorer.format(mode=mapped_mode)
1673
+ )
1674
+ else:
1675
+ await self.api.async_get_command(
1676
+ self.urls.command_audio_restorer.format(mode=mapped_mode)
1677
+ )
1678
+
1679
+ async def async_remote_control_lock(self):
1680
+ """Set remote control lock on receiver via HTTP get command."""
1681
+ if self.telnet_available:
1682
+ await self.telnet_api.async_send_commands(
1683
+ self.telnet_commands.command_remote_control_lock.format(mode="ON")
1684
+ )
1685
+ else:
1686
+ await self.api.async_get_command(
1687
+ self.urls.command_remote_control_lock.format(mode="ON")
1688
+ )
1689
+
1690
+ async def async_remote_control_unlock(self):
1691
+ """Set remote control unlock on receiver via HTTP get command."""
1692
+ if self.telnet_available:
1693
+ await self.telnet_api.async_send_commands(
1694
+ self.telnet_commands.command_remote_control_lock.format(mode="OFF")
1695
+ )
1696
+ else:
1697
+ await self.api.async_get_command(
1698
+ self.urls.command_remote_control_lock.format(mode="OFF")
1699
+ )
1700
+
1701
+ async def async_panel_lock(self, panel_lock_mode: PanelLocks):
1702
+ """Set panel lock on receiver via HTTP get command."""
1703
+ if panel_lock_mode not in self._panel_locks:
1704
+ raise AvrCommandError("Invalid panel lock mode")
1705
+
1706
+ if self.telnet_available:
1707
+ if panel_lock_mode == "Panel":
620
1708
  await self.telnet_api.async_send_commands(
621
- self.telnet_commands.command_setup_close
1709
+ self.telnet_commands.command_panel_lock.format(mode="ON")
622
1710
  )
623
1711
  else:
624
1712
  await self.telnet_api.async_send_commands(
625
- self.telnet_commands.command_setup_open
1713
+ self.telnet_commands.command_panel_and_volume_lock
626
1714
  )
627
1715
  else:
628
- if res is not None and res == "MNMEN ON":
629
- await self.api.async_get_command(self.urls.command_setup_close)
1716
+ if panel_lock_mode == "Panel":
1717
+ await self.api.async_get_command(
1718
+ self.urls.command_panel_lock.format(mode="ON")
1719
+ )
630
1720
  else:
631
- await self.api.async_get_command(self.urls.command_setup_open)
1721
+ await self.api.async_get_command(
1722
+ self.urls.command_panel_and_volume_lock
1723
+ )
1724
+
1725
+ async def async_panel_unlock(self):
1726
+ """Set panel unlock on receiver via HTTP get command."""
1727
+ if self.telnet_available:
1728
+ await self.telnet_api.async_send_commands(
1729
+ self.telnet_commands.command_panel_lock.format(mode="OFF")
1730
+ )
1731
+ else:
1732
+ await self.api.async_get_command(
1733
+ self.urls.command_panel_lock.format(mode="OFF")
1734
+ )
1735
+
1736
+ async def async_graphic_eq_on(self) -> None:
1737
+ """Turn on Graphic EQ on receiver via HTTP get command."""
1738
+ if self.telnet_available:
1739
+ await self.telnet_api.async_send_commands(
1740
+ self.telnet_commands.command_graphic_eq.format(mode="ON")
1741
+ )
1742
+ else:
1743
+ await self.api.async_get_command(
1744
+ self.urls.command_graphic_eq.format(mode="ON")
1745
+ )
1746
+
1747
+ async def async_graphic_eq_off(self) -> None:
1748
+ """Turn off Graphic EQ on receiver via HTTP get command."""
1749
+ if self.telnet_available:
1750
+ await self.telnet_api.async_send_commands(
1751
+ self.telnet_commands.command_graphic_eq.format(mode="OFF")
1752
+ )
1753
+ else:
1754
+ await self.api.async_get_command(
1755
+ self.urls.command_graphic_eq.format(mode="OFF")
1756
+ )
1757
+
1758
+ async def async_graphic_eq_toggle(self) -> None:
1759
+ """
1760
+ Toggle Graphic EQ on receiver via HTTP get command.
1761
+
1762
+ Only available if using Telnet.
1763
+ """
1764
+ if self._graphic_eq:
1765
+ await self.async_graphic_eq_off()
1766
+ else:
1767
+ await self.async_graphic_eq_on()
1768
+
1769
+ async def async_headphone_eq_on(self) -> None:
1770
+ """Turn on Headphone EQ on receiver via HTTP get command."""
1771
+ if self.telnet_available:
1772
+ await self.telnet_api.async_send_commands(
1773
+ self.telnet_commands.command_headphone_eq.format(mode="ON")
1774
+ )
1775
+ else:
1776
+ await self.api.async_get_command(
1777
+ self.urls.command_headphone_eq.format(mode="ON")
1778
+ )
1779
+
1780
+ async def async_headphone_eq_off(self) -> None:
1781
+ """Turn off Headphone EQ on receiver via HTTP get command."""
1782
+ if self.telnet_available:
1783
+ await self.telnet_api.async_send_commands(
1784
+ self.telnet_commands.command_headphone_eq.format(mode="OFF")
1785
+ )
1786
+ else:
1787
+ await self.api.async_get_command(
1788
+ self.urls.command_headphone_eq.format(mode="OFF")
1789
+ )
1790
+
1791
+ async def async_headphone_eq_toggle(self) -> None:
1792
+ """
1793
+ Toggle Headphone EQ on receiver via HTTP get command.
1794
+
1795
+ Only available if using Telnet.
1796
+ """
1797
+ if self._headphone_eq:
1798
+ await self.async_headphone_eq_off()
1799
+ else:
1800
+ await self.async_headphone_eq_on()
632
1801
 
633
1802
 
634
1803
  @attr.s(auto_attribs=True, on_setattr=DENON_ATTR_SETATTR)
@@ -833,10 +2002,11 @@ def set_api_timeout(
833
2002
  ) -> float:
834
2003
  """Change API timeout on timeout changes too."""
835
2004
  # First change _device.api.host then return value
836
- timeout = httpx.Timeout(value, read=max(value, 15.0))
837
2005
  # pylint: disable=protected-access
838
- instance._device.api.timeout = timeout
2006
+ instance._device.api.timeout = value
2007
+ instance._device.api.read_timeout = max(value, 15.0)
839
2008
  instance._device.telnet_api.timeout = value
2009
+ instance._device.telnet_api._send_confirmation_timeout = value
840
2010
  return value
841
2011
 
842
2012