denonavr 0.11.2__py3-none-any.whl → 0.11.6__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/__init__.py +1 -1
- denonavr/api.py +194 -59
- denonavr/audyssey.py +69 -32
- denonavr/const.py +201 -12
- denonavr/decorators.py +27 -41
- denonavr/denonavr.py +50 -7
- denonavr/foundation.py +87 -54
- denonavr/input.py +119 -72
- denonavr/soundmode.py +32 -16
- denonavr/ssdp.py +13 -13
- denonavr/tonecontrol.py +91 -36
- denonavr/volume.py +53 -17
- {denonavr-0.11.2.dist-info → denonavr-0.11.6.dist-info}/METADATA +13 -11
- denonavr-0.11.6.dist-info/RECORD +19 -0
- {denonavr-0.11.2.dist-info → denonavr-0.11.6.dist-info}/WHEEL +1 -1
- denonavr-0.11.2.dist-info/RECORD +0 -19
- {denonavr-0.11.2.dist-info → denonavr-0.11.6.dist-info}/LICENSE +0 -0
- {denonavr-0.11.2.dist-info → denonavr-0.11.6.dist-info}/top_level.txt +0 -0
denonavr/const.py
CHANGED
|
@@ -45,6 +45,31 @@ ReceiverURLs = namedtuple(
|
|
|
45
45
|
"command_play",
|
|
46
46
|
],
|
|
47
47
|
)
|
|
48
|
+
TelnetCommands = namedtuple(
|
|
49
|
+
"TelnetCommands",
|
|
50
|
+
[
|
|
51
|
+
"command_sel_src",
|
|
52
|
+
"command_fav_src",
|
|
53
|
+
"command_power_on",
|
|
54
|
+
"command_power_standby",
|
|
55
|
+
"command_volume_up",
|
|
56
|
+
"command_volume_down",
|
|
57
|
+
"command_set_volume",
|
|
58
|
+
"command_mute_on",
|
|
59
|
+
"command_mute_off",
|
|
60
|
+
"command_sel_sound_mode",
|
|
61
|
+
"command_set_all_zone_stereo",
|
|
62
|
+
"command_pause",
|
|
63
|
+
"command_play",
|
|
64
|
+
"command_multieq",
|
|
65
|
+
"command_dynamiceq",
|
|
66
|
+
"command_reflevoffset",
|
|
67
|
+
"command_dynamicvol",
|
|
68
|
+
"command_tonecontrol",
|
|
69
|
+
"command_bass",
|
|
70
|
+
"command_treble",
|
|
71
|
+
],
|
|
72
|
+
)
|
|
48
73
|
|
|
49
74
|
# AVR-X search patterns
|
|
50
75
|
DEVICEINFO_AVR_X_PATTERN = re.compile(
|
|
@@ -95,7 +120,7 @@ CHANGE_INPUT_MAPPING = {
|
|
|
95
120
|
"Spotify": "SPOTIFY",
|
|
96
121
|
}
|
|
97
122
|
|
|
98
|
-
TELNET_SOURCES =
|
|
123
|
+
TELNET_SOURCES = {
|
|
99
124
|
"CD",
|
|
100
125
|
"PHONO",
|
|
101
126
|
"TUNER",
|
|
@@ -109,6 +134,7 @@ TELNET_SOURCES = [
|
|
|
109
134
|
"NET",
|
|
110
135
|
"PANDORA",
|
|
111
136
|
"SIRIUSXM",
|
|
137
|
+
"SOURCE",
|
|
112
138
|
"LASTFM",
|
|
113
139
|
"FLICKR",
|
|
114
140
|
"IRADIO",
|
|
@@ -126,7 +152,7 @@ TELNET_SOURCES = [
|
|
|
126
152
|
"USB/IPOD",
|
|
127
153
|
"USB DIRECT",
|
|
128
154
|
"IPOD DIRECT",
|
|
129
|
-
|
|
155
|
+
}
|
|
130
156
|
|
|
131
157
|
TELNET_MAPPING = {
|
|
132
158
|
"FAVORITES": "Favorites",
|
|
@@ -167,6 +193,7 @@ SOUND_MODE_MAPPING = {
|
|
|
167
193
|
"DOLBY PL2 CINEMA",
|
|
168
194
|
"DOLBY PL2 C",
|
|
169
195
|
"DOLBY PL2 X MOVIE",
|
|
196
|
+
"DOLBY PL2 MOVIE",
|
|
170
197
|
],
|
|
171
198
|
"GAME": [
|
|
172
199
|
"PLII GAME",
|
|
@@ -174,6 +201,7 @@ SOUND_MODE_MAPPING = {
|
|
|
174
201
|
"DOLBY PL2 GAME",
|
|
175
202
|
"DOLBY PL2 G",
|
|
176
203
|
"DOLBY PL2 X GAME",
|
|
204
|
+
"DOLBY PLII GAME",
|
|
177
205
|
],
|
|
178
206
|
"AUTO": ["None"],
|
|
179
207
|
"STANDARD": ["None2"],
|
|
@@ -188,11 +216,14 @@ SOUND_MODE_MAPPING = {
|
|
|
188
216
|
"DOLBY DIGITAL": [
|
|
189
217
|
"DOLBY DIGITAL",
|
|
190
218
|
"DOLBY D + DOLBY SURROUND",
|
|
219
|
+
"DOLBY D+DS",
|
|
220
|
+
"DOLBY D+ +DS",
|
|
191
221
|
"DOLBY DIGITAL +",
|
|
192
222
|
"STANDARD(DOLBY)",
|
|
193
223
|
"DOLBY SURROUND",
|
|
194
224
|
"DOLBY D + +DOLBY SURROUND",
|
|
195
225
|
"NEURAL",
|
|
226
|
+
"NEURAL:X",
|
|
196
227
|
"DOLBY HD",
|
|
197
228
|
"DOLBY HD + DOLBY SURROUND",
|
|
198
229
|
"MULTI IN + DSUR",
|
|
@@ -208,11 +239,15 @@ SOUND_MODE_MAPPING = {
|
|
|
208
239
|
"DOLBY AUDIO - TRUEHD + DSUR",
|
|
209
240
|
"DOLBY AUDIO - DOLBY TRUEHD",
|
|
210
241
|
"DOLBY AUDIO - TRUEHD + NEURAL:X",
|
|
242
|
+
"DOLBY AUDIO - DD + NEURAL:X",
|
|
211
243
|
"DOLBY AUDIO - DD + DSUR",
|
|
212
244
|
"DOLBY AUDIO - DD+ + NEURAL:X",
|
|
213
245
|
"DOLBY AUDIO - DD+ + DSUR",
|
|
246
|
+
"DOLBY AUDIO-DD+ +DSUR",
|
|
214
247
|
"DOLBY AUDIO - DOLBY DIGITAL",
|
|
215
248
|
"DOLBY AUDIO-DSUR",
|
|
249
|
+
"DOLBY AUDIO-DD+DSUR",
|
|
250
|
+
"DOLBY PRO LOGIC",
|
|
216
251
|
],
|
|
217
252
|
"DTS SURROUND": [
|
|
218
253
|
"DTS SURROUND",
|
|
@@ -230,7 +265,8 @@ SOUND_MODE_MAPPING = {
|
|
|
230
265
|
"DTS-HD + DSUR",
|
|
231
266
|
"DTS:X MSTR",
|
|
232
267
|
],
|
|
233
|
-
"AURO3D": ["AURO-3D"
|
|
268
|
+
"AURO3D": ["AURO-3D"],
|
|
269
|
+
"AURO2DSURR": ["AURO-2D SURROUND"],
|
|
234
270
|
"MCH STEREO": [
|
|
235
271
|
"MULTI CH STEREO",
|
|
236
272
|
"MULTI_CH_STEREO",
|
|
@@ -391,23 +427,146 @@ ZONE3_URLS = ReceiverURLs(
|
|
|
391
427
|
command_play=COMMAND_PLAY,
|
|
392
428
|
)
|
|
393
429
|
|
|
394
|
-
# Telnet
|
|
395
|
-
|
|
430
|
+
# Telnet Events
|
|
431
|
+
ALL_TELNET_EVENTS = "ALL"
|
|
432
|
+
TELNET_EVENTS = {
|
|
433
|
+
"CV",
|
|
434
|
+
"DC",
|
|
435
|
+
"DIM",
|
|
436
|
+
"ECO",
|
|
437
|
+
"HD",
|
|
438
|
+
"MN",
|
|
439
|
+
"MS",
|
|
440
|
+
"MU",
|
|
441
|
+
"MV",
|
|
442
|
+
"NS",
|
|
443
|
+
"NSA",
|
|
444
|
+
"NSE",
|
|
445
|
+
"OP",
|
|
446
|
+
"PS",
|
|
447
|
+
"PV",
|
|
448
|
+
"PW",
|
|
449
|
+
"RM",
|
|
450
|
+
"SD",
|
|
451
|
+
"SI",
|
|
452
|
+
"SLP",
|
|
453
|
+
"SR",
|
|
454
|
+
"SS",
|
|
455
|
+
"STBY",
|
|
456
|
+
"SV",
|
|
457
|
+
"SY",
|
|
458
|
+
"TF",
|
|
459
|
+
"TM",
|
|
460
|
+
"TP",
|
|
461
|
+
"TR",
|
|
462
|
+
"UG",
|
|
463
|
+
"VS",
|
|
464
|
+
"ZM",
|
|
465
|
+
"Z2",
|
|
466
|
+
"Z3",
|
|
467
|
+
}
|
|
468
|
+
ALL_ZONE_TELNET_EVENTS = {
|
|
469
|
+
"DIM",
|
|
470
|
+
"HD",
|
|
471
|
+
"NS",
|
|
472
|
+
"NSA",
|
|
473
|
+
"NSE",
|
|
474
|
+
"MN",
|
|
475
|
+
"PW",
|
|
476
|
+
"RM",
|
|
477
|
+
"SY",
|
|
478
|
+
"TF",
|
|
479
|
+
"TM",
|
|
480
|
+
"TP",
|
|
481
|
+
"TR",
|
|
482
|
+
"UG",
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
DENONAVR_TELNET_COMMANDS = TelnetCommands(
|
|
486
|
+
command_sel_src="SI",
|
|
487
|
+
command_fav_src="ZM",
|
|
488
|
+
command_power_on="ZMON",
|
|
489
|
+
command_power_standby="ZMOFF",
|
|
490
|
+
command_volume_up="MVUP",
|
|
491
|
+
command_volume_down="MVDOWN",
|
|
492
|
+
command_set_volume="MV{volume:02d}",
|
|
493
|
+
command_mute_on="MUON",
|
|
494
|
+
command_mute_off="MUOFF",
|
|
495
|
+
command_sel_sound_mode="MS",
|
|
496
|
+
command_set_all_zone_stereo="MN",
|
|
497
|
+
command_pause="NS9B",
|
|
498
|
+
command_play="NS9A",
|
|
499
|
+
command_multieq="PSMULTEQ:",
|
|
500
|
+
command_dynamiceq="PSDYNEQ ",
|
|
501
|
+
command_reflevoffset="PSREFLEV ",
|
|
502
|
+
command_dynamicvol="PSDYNVOL ",
|
|
503
|
+
command_tonecontrol="PSTONE CTRL ",
|
|
504
|
+
command_bass="PSBAS ",
|
|
505
|
+
command_treble="PSTRE ",
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
ZONE2_TELNET_COMMANDS = TelnetCommands(
|
|
509
|
+
command_sel_src="Z2",
|
|
510
|
+
command_fav_src="Z2",
|
|
511
|
+
command_power_on="Z2ON",
|
|
512
|
+
command_power_standby="Z2OFF",
|
|
513
|
+
command_volume_up="Z2UP",
|
|
514
|
+
command_volume_down="Z2DOWN",
|
|
515
|
+
command_set_volume="Z2{volume:02d}",
|
|
516
|
+
command_mute_on="Z2MUON",
|
|
517
|
+
command_mute_off="Z2MUOFF",
|
|
518
|
+
command_sel_sound_mode="MS",
|
|
519
|
+
command_set_all_zone_stereo="MN",
|
|
520
|
+
command_pause="NS9B",
|
|
521
|
+
command_play="NS9A",
|
|
522
|
+
command_multieq="PSMULTEQ:",
|
|
523
|
+
command_dynamiceq="PSDYNEQ ",
|
|
524
|
+
command_reflevoffset="PSREFLEV ",
|
|
525
|
+
command_dynamicvol="PSDYNVOL ",
|
|
526
|
+
command_tonecontrol="PSTONE CTRL ",
|
|
527
|
+
command_bass="PSBAS ",
|
|
528
|
+
command_treble="PSTRE ",
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
ZONE3_TELNET_COMMANDS = TelnetCommands(
|
|
532
|
+
command_sel_src="Z3",
|
|
533
|
+
command_fav_src="Z3",
|
|
534
|
+
command_power_on="Z3ON",
|
|
535
|
+
command_power_standby="Z3OFF",
|
|
536
|
+
command_volume_up="Z3UP",
|
|
537
|
+
command_volume_down="Z3DOWN",
|
|
538
|
+
command_set_volume="Z3{volume:02d}",
|
|
539
|
+
command_mute_on="Z3MUON",
|
|
540
|
+
command_mute_off="Z3MUOFF",
|
|
541
|
+
command_sel_sound_mode="MS",
|
|
542
|
+
command_set_all_zone_stereo="MN",
|
|
543
|
+
command_pause="NS9B",
|
|
544
|
+
command_play="NS9A",
|
|
545
|
+
command_multieq="PSMULTEQ:",
|
|
546
|
+
command_dynamiceq="PSDYNEQ ",
|
|
547
|
+
command_reflevoffset="PSREFLEV ",
|
|
548
|
+
command_dynamicvol="PSDYNVOL ",
|
|
549
|
+
command_tonecontrol="PSTONE CTRL ",
|
|
550
|
+
command_bass="PSBAS ",
|
|
551
|
+
command_treble="PSTRE ",
|
|
552
|
+
)
|
|
396
553
|
|
|
397
554
|
# States
|
|
398
555
|
POWER_ON = "ON"
|
|
399
556
|
POWER_OFF = "OFF"
|
|
400
557
|
POWER_STANDBY = "STANDBY"
|
|
558
|
+
POWER_STATES = {POWER_ON, POWER_OFF, POWER_STANDBY}
|
|
401
559
|
STATE_ON = "on"
|
|
402
560
|
STATE_OFF = "off"
|
|
403
561
|
STATE_PLAYING = "playing"
|
|
404
562
|
STATE_PAUSED = "paused"
|
|
405
563
|
|
|
406
564
|
# Zones
|
|
565
|
+
ALL_ZONES = "All"
|
|
407
566
|
MAIN_ZONE = "Main"
|
|
408
567
|
ZONE2 = "Zone2"
|
|
409
568
|
ZONE3 = "Zone3"
|
|
410
|
-
VALID_ZONES =
|
|
569
|
+
VALID_ZONES = {MAIN_ZONE, ZONE2, ZONE3}
|
|
411
570
|
|
|
412
571
|
# Setup additional zones
|
|
413
572
|
NO_ZONES = None
|
|
@@ -420,11 +579,41 @@ APPCOMMAND_CMD_TEXT = "cmd_text"
|
|
|
420
579
|
APPCOMMAND_NAME = "name"
|
|
421
580
|
|
|
422
581
|
# Audyssey parameter
|
|
423
|
-
|
|
424
|
-
|
|
582
|
+
MULTI_EQ_MAP_APPCOMMAND = {"0": "Off", "1": "Flat", "2": "L/R Bypass", "3": "Reference"}
|
|
583
|
+
MULTI_EQ_MAP_TELNET = {
|
|
584
|
+
"OFF": "Off",
|
|
585
|
+
"FLAT": "Flat",
|
|
586
|
+
"BYP.LR": "L/R Bypass",
|
|
587
|
+
"AUDYSSEY": "Reference",
|
|
588
|
+
"MANUAL": "Manual",
|
|
589
|
+
}
|
|
590
|
+
MULTI_EQ_MAP = {**MULTI_EQ_MAP_APPCOMMAND, **MULTI_EQ_MAP_TELNET}
|
|
591
|
+
MULTI_EQ_MAP_LABELS_APPCOMMAND = {
|
|
592
|
+
value: key for key, value in MULTI_EQ_MAP_APPCOMMAND.items()
|
|
593
|
+
}
|
|
594
|
+
MULTI_EQ_MAP_LABELS_TELNET = {value: key for key, value in MULTI_EQ_MAP_TELNET.items()}
|
|
425
595
|
|
|
426
|
-
|
|
427
|
-
|
|
596
|
+
REF_LVL_OFFSET_MAP_APPCOMMAND = {"0": "0dB", "1": "+5dB", "2": "+10dB", "3": "+15dB"}
|
|
597
|
+
REF_LVL_OFFSET_MAP_TELNET = {"0": "0dB", "5": "+5dB", "10": "+10dB", "15": "+15dB"}
|
|
598
|
+
REF_LVL_OFFSET_MAP = {**REF_LVL_OFFSET_MAP_APPCOMMAND, **REF_LVL_OFFSET_MAP_TELNET}
|
|
599
|
+
REF_LVL_OFFSET_MAP_LABELS_APPCOMMAND = {
|
|
600
|
+
value: key for key, value in REF_LVL_OFFSET_MAP_APPCOMMAND.items()
|
|
601
|
+
}
|
|
602
|
+
REF_LVL_OFFSET_MAP_LABELS_TELNET = {
|
|
603
|
+
value: key for key, value in REF_LVL_OFFSET_MAP_TELNET.items()
|
|
604
|
+
}
|
|
428
605
|
|
|
429
|
-
|
|
430
|
-
|
|
606
|
+
DYNAMIC_VOLUME_MAP_APPCOMMAND = {"0": "Off", "1": "Light", "2": "Medium", "3": "Heavy"}
|
|
607
|
+
DYNAMIC_VOLUME_MAP_TELNET = {
|
|
608
|
+
"OFF": "Off",
|
|
609
|
+
"LIT": "Light",
|
|
610
|
+
"MED": "Medium",
|
|
611
|
+
"HEV": "Heavy",
|
|
612
|
+
}
|
|
613
|
+
DYNAMIC_VOLUME_MAP = {**DYNAMIC_VOLUME_MAP_APPCOMMAND, **DYNAMIC_VOLUME_MAP_TELNET}
|
|
614
|
+
DYNAMIC_VOLUME_MAP_LABELS_APPCOMMAND = {
|
|
615
|
+
value: key for key, value in DYNAMIC_VOLUME_MAP_APPCOMMAND.items()
|
|
616
|
+
}
|
|
617
|
+
DYNAMIC_VOLUME_MAP_LABELS_TELNET = {
|
|
618
|
+
value: key for key, value in DYNAMIC_VOLUME_MAP_TELNET.items()
|
|
619
|
+
}
|
denonavr/decorators.py
CHANGED
|
@@ -16,6 +16,7 @@ from functools import wraps
|
|
|
16
16
|
from typing import Callable, Coroutine, TypeVar
|
|
17
17
|
|
|
18
18
|
import httpx
|
|
19
|
+
from asyncstdlib import lru_cache
|
|
19
20
|
from defusedxml import DefusedXmlException
|
|
20
21
|
from defusedxml.ElementTree import ParseError
|
|
21
22
|
|
|
@@ -34,7 +35,7 @@ AnyT = TypeVar("AnyT")
|
|
|
34
35
|
|
|
35
36
|
def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
36
37
|
"""
|
|
37
|
-
Handle exceptions raised when calling
|
|
38
|
+
Handle exceptions raised when calling a Denon AVR endpoint asynchronously.
|
|
38
39
|
|
|
39
40
|
The decorated function must either have a string variable as second
|
|
40
41
|
argument or as "request" keyword argument.
|
|
@@ -48,24 +49,18 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
|
|
|
48
49
|
_LOGGER.debug("HTTP status error on request %s", err.request, exc_info=True)
|
|
49
50
|
# Separate handling of 403 errors
|
|
50
51
|
if err.response.status_code == 403:
|
|
51
|
-
raise AvrForbiddenError(
|
|
52
|
-
|
|
53
|
-
) from err
|
|
54
|
-
raise AvrRequestError(
|
|
55
|
-
"HTTPStatusError: {}".format(err), err.request
|
|
56
|
-
) from err
|
|
52
|
+
raise AvrForbiddenError(f"HTTPStatusError: {err}", err.request) from err
|
|
53
|
+
raise AvrRequestError(f"HTTPStatusError: {err}", err.request) from err
|
|
57
54
|
except httpx.TimeoutException as err:
|
|
58
55
|
_LOGGER.debug(
|
|
59
56
|
"HTTP timeout exception on request %s", err.request, exc_info=True
|
|
60
57
|
)
|
|
61
|
-
raise AvrTimoutError(
|
|
62
|
-
"TimeoutException: {}".format(err), err.request
|
|
63
|
-
) from err
|
|
58
|
+
raise AvrTimoutError(f"TimeoutException: {err}", err.request) from err
|
|
64
59
|
except httpx.NetworkError as err:
|
|
65
60
|
_LOGGER.debug(
|
|
66
61
|
"Network error exception on request %s", err.request, exc_info=True
|
|
67
62
|
)
|
|
68
|
-
raise AvrNetworkError("NetworkError: {}"
|
|
63
|
+
raise AvrNetworkError(f"NetworkError: {err}", err.request) from err
|
|
69
64
|
except httpx.RemoteProtocolError as err:
|
|
70
65
|
_LOGGER.debug(
|
|
71
66
|
"Remote protocol error exception on request %s",
|
|
@@ -73,7 +68,7 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
|
|
|
73
68
|
exc_info=True,
|
|
74
69
|
)
|
|
75
70
|
raise AvrInvalidResponseError(
|
|
76
|
-
"RemoteProtocolError: {}"
|
|
71
|
+
f"RemoteProtocolError: {err}", err.request
|
|
77
72
|
) from err
|
|
78
73
|
except (
|
|
79
74
|
ET.ParseError,
|
|
@@ -85,50 +80,43 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
|
|
|
85
80
|
"Defusedxml parse error on request %s", (args, kwargs), exc_info=True
|
|
86
81
|
)
|
|
87
82
|
raise AvrInvalidResponseError(
|
|
88
|
-
"XMLParseError: {}"
|
|
83
|
+
f"XMLParseError: {err}", (args, kwargs)
|
|
89
84
|
) from err
|
|
90
85
|
|
|
91
86
|
return wrapper
|
|
92
87
|
|
|
93
88
|
|
|
94
|
-
def
|
|
89
|
+
def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
95
90
|
"""
|
|
96
|
-
Decorate a function to
|
|
91
|
+
Decorate a function to cache its results with an lru_cache of maxsize 16.
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
93
|
+
This decorator also sets an "cache_id" keyword argument if it is not set yet.
|
|
94
|
+
When an exception occurs it clears lru_cache to prevent memory leaks in
|
|
95
|
+
home-assistant when receiver instances are created and deleted right
|
|
96
|
+
away in case the device is offline on setup.
|
|
101
97
|
"""
|
|
98
|
+
if inspect.signature(func).parameters.get("cache_id") is None:
|
|
99
|
+
raise AttributeError(
|
|
100
|
+
f"Function {func} does not have a 'cache_id' keyword parameter"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
lru_decorator = lru_cache(maxsize=16)
|
|
104
|
+
cached_func = lru_decorator(func)
|
|
102
105
|
|
|
103
106
|
@wraps(func)
|
|
104
107
|
async def wrapper(*args, **kwargs):
|
|
108
|
+
if kwargs.get("cache_id") is None:
|
|
109
|
+
kwargs["cache_id"] = time.time()
|
|
105
110
|
try:
|
|
106
|
-
return await
|
|
111
|
+
return await cached_func(*args, **kwargs)
|
|
107
112
|
except Exception as err:
|
|
108
113
|
_LOGGER.debug("Exception %s raised, clearing cache", err)
|
|
109
|
-
|
|
114
|
+
cached_func.cache_clear()
|
|
110
115
|
raise
|
|
111
116
|
|
|
112
117
|
return wrapper
|
|
113
118
|
|
|
114
119
|
|
|
115
|
-
def set_cache_id(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
116
|
-
"""
|
|
117
|
-
Decorate a function to add cache_id keyword argument if it is not present.
|
|
118
|
-
|
|
119
|
-
The function must be called with a fix cache_id keyword argument to be able
|
|
120
|
-
to get cached data. This prevents accidential caching of a function result.
|
|
121
|
-
"""
|
|
122
|
-
|
|
123
|
-
@wraps(func)
|
|
124
|
-
def wrapper(*args, **kwargs):
|
|
125
|
-
if kwargs.get("cache_id") is None:
|
|
126
|
-
kwargs["cache_id"] = time.time()
|
|
127
|
-
return func(*args, **kwargs)
|
|
128
|
-
|
|
129
|
-
return wrapper
|
|
130
|
-
|
|
131
|
-
|
|
132
120
|
def run_async_synchronously(async_func: Coroutine) -> Callable:
|
|
133
121
|
"""
|
|
134
122
|
Decorate to run the configured asynchronous function synchronously instead.
|
|
@@ -141,13 +129,11 @@ def run_async_synchronously(async_func: Coroutine) -> Callable:
|
|
|
141
129
|
def decorator(func: Callable):
|
|
142
130
|
# Check if function is a coroutine
|
|
143
131
|
if not inspect.iscoroutinefunction(async_func):
|
|
144
|
-
raise AttributeError(
|
|
145
|
-
"Function {} is not a coroutine function".format(async_func)
|
|
146
|
-
)
|
|
132
|
+
raise AttributeError(f"Function {async_func} is not a coroutine function")
|
|
147
133
|
# Check if the signature of both functions is equal
|
|
148
134
|
if inspect.signature(func) != inspect.signature(async_func):
|
|
149
135
|
raise AttributeError(
|
|
150
|
-
"Functions {} and {} have different signatures"
|
|
136
|
+
f"Functions {func} and {async_func} have different signatures"
|
|
151
137
|
)
|
|
152
138
|
|
|
153
139
|
@wraps(func)
|
denonavr/denonavr.py
CHANGED
|
@@ -124,7 +124,7 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
124
124
|
# Name either set explicitly or name of Main Zone with suffix
|
|
125
125
|
zonename = None
|
|
126
126
|
if zname is None and self._name is not None:
|
|
127
|
-
zonename = "{} {}"
|
|
127
|
+
zonename = f"{self._name} {zone}"
|
|
128
128
|
zone_device = attr.evolve(self._device, zone=zone)
|
|
129
129
|
zone_inst = DenonAVR(
|
|
130
130
|
host=self._host,
|
|
@@ -167,7 +167,7 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
167
167
|
Method executes the update method for the current receiver type.
|
|
168
168
|
"""
|
|
169
169
|
# Ensure that the device is setup
|
|
170
|
-
if self._is_setup
|
|
170
|
+
if not self._is_setup:
|
|
171
171
|
await self.async_setup()
|
|
172
172
|
|
|
173
173
|
# Create a cache id for this global update
|
|
@@ -226,6 +226,10 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
226
226
|
def send_get_command(self, request: str) -> str:
|
|
227
227
|
"""Send HTTP GET command to Denon AVR receiver...for compatibility."""
|
|
228
228
|
|
|
229
|
+
async def async_send_telnet_commands(self, *commands: str) -> None:
|
|
230
|
+
"""Send telnet commands to the receiver."""
|
|
231
|
+
await self._device.telnet_api.async_send_commands(*commands)
|
|
232
|
+
|
|
229
233
|
def send_telnet_commands(self, *commands: str) -> None:
|
|
230
234
|
"""Send telnet commands to the receiver."""
|
|
231
235
|
self._device.telnet_api.send_commands(*commands)
|
|
@@ -435,13 +439,18 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
435
439
|
return None
|
|
436
440
|
return self._device.receiver.type
|
|
437
441
|
|
|
442
|
+
@property
|
|
443
|
+
def telnet_available(self) -> bool:
|
|
444
|
+
"""Return True if telnet is connected and healthy."""
|
|
445
|
+
return self._device.telnet_available
|
|
446
|
+
|
|
438
447
|
@property
|
|
439
448
|
def telnet_connected(self) -> bool:
|
|
440
449
|
"""Return True if telnet is connected."""
|
|
441
450
|
return self._device.telnet_api.connected
|
|
442
451
|
|
|
443
452
|
@property
|
|
444
|
-
def telnet_healthy(self) ->
|
|
453
|
+
def telnet_healthy(self) -> bool:
|
|
445
454
|
"""Return True if telnet connection is healthy."""
|
|
446
455
|
return self._device.telnet_api.healthy
|
|
447
456
|
|
|
@@ -450,6 +459,16 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
450
459
|
"""Indicate if all inputs are shown or just active one."""
|
|
451
460
|
return self._show_all_inputs
|
|
452
461
|
|
|
462
|
+
@property
|
|
463
|
+
def tone_control_status(self) -> Optional[bool]:
|
|
464
|
+
"""Return value of tone control status."""
|
|
465
|
+
return self.tonecontrol.tone_control_status
|
|
466
|
+
|
|
467
|
+
@property
|
|
468
|
+
def tone_control_adjust(self) -> Optional[bool]:
|
|
469
|
+
"""Return value of tone control adjust."""
|
|
470
|
+
return self.tonecontrol.tone_control_adjust
|
|
471
|
+
|
|
453
472
|
@property
|
|
454
473
|
def bass(self) -> Optional[int]:
|
|
455
474
|
"""Return value of bass."""
|
|
@@ -505,10 +524,6 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
505
524
|
"""Return a list of available MultiEQ settings."""
|
|
506
525
|
return self.audyssey.multi_eq_setting_list
|
|
507
526
|
|
|
508
|
-
async def async_dynamic_eq_off(self) -> None:
|
|
509
|
-
"""Turn DynamicEQ off."""
|
|
510
|
-
await self.audyssey.async_dynamiceq_off()
|
|
511
|
-
|
|
512
527
|
##########
|
|
513
528
|
# Setter #
|
|
514
529
|
##########
|
|
@@ -525,6 +540,10 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
525
540
|
raise AvrCommandError("Provided object is not callable")
|
|
526
541
|
self._device.api.async_client_getter = async_client_getter
|
|
527
542
|
|
|
543
|
+
async def async_dynamic_eq_off(self) -> None:
|
|
544
|
+
"""Turn DynamicEQ off."""
|
|
545
|
+
await self.audyssey.async_dynamiceq_off()
|
|
546
|
+
|
|
528
547
|
@run_async_synchronously(async_func=async_dynamic_eq_off)
|
|
529
548
|
def dynamic_eq_off(self) -> None:
|
|
530
549
|
"""Turn DynamicEQ off."""
|
|
@@ -545,6 +564,30 @@ class DenonAVR(DenonAVRFoundation):
|
|
|
545
564
|
def toggle_dynamic_eq(self) -> None:
|
|
546
565
|
"""Toggle DynamicEQ."""
|
|
547
566
|
|
|
567
|
+
async def async_set_multieq(self, value: str) -> None:
|
|
568
|
+
"""Set MultiEQ mode."""
|
|
569
|
+
await self.audyssey.async_set_multieq(value)
|
|
570
|
+
|
|
571
|
+
@run_async_synchronously(async_func=async_set_multieq)
|
|
572
|
+
def set_multieq(self, value: str) -> None:
|
|
573
|
+
"""Set MultiEQ mode."""
|
|
574
|
+
|
|
575
|
+
async def async_set_reflevoffset(self, value: str) -> None:
|
|
576
|
+
"""Set Reference Level Offset."""
|
|
577
|
+
await self.audyssey.async_set_reflevoffset(value)
|
|
578
|
+
|
|
579
|
+
@run_async_synchronously(async_func=async_set_reflevoffset)
|
|
580
|
+
def set_reflevoffset(self, value: str) -> None:
|
|
581
|
+
"""Set Reference Level Offset."""
|
|
582
|
+
|
|
583
|
+
async def async_set_dynamicvol(self, value: str) -> None:
|
|
584
|
+
"""Set Dynamic Volume."""
|
|
585
|
+
await self.audyssey.async_set_dynamicvol(value)
|
|
586
|
+
|
|
587
|
+
@run_async_synchronously(async_func=async_set_dynamicvol)
|
|
588
|
+
def set_dynamicvol(self, value: str) -> None:
|
|
589
|
+
"""Set Dynamic Volume."""
|
|
590
|
+
|
|
548
591
|
async def async_set_input_func(self, input_func: str) -> None:
|
|
549
592
|
"""
|
|
550
593
|
Set input_func of device.
|