denonavr 0.11.6__py3-none-any.whl → 1.0.1__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/const.py CHANGED
@@ -43,6 +43,17 @@ ReceiverURLs = namedtuple(
43
43
  "command_set_all_zone_stereo",
44
44
  "command_pause",
45
45
  "command_play",
46
+ "command_cusor_up",
47
+ "command_cusor_down",
48
+ "command_cusor_left",
49
+ "command_cusor_right",
50
+ "command_cusor_enter",
51
+ "command_back",
52
+ "command_info",
53
+ "command_options",
54
+ "command_setup_open",
55
+ "command_setup_close",
56
+ "command_setup_query",
46
57
  ],
47
58
  )
48
59
  TelnetCommands = namedtuple(
@@ -68,6 +79,17 @@ TelnetCommands = namedtuple(
68
79
  "command_tonecontrol",
69
80
  "command_bass",
70
81
  "command_treble",
82
+ "command_cusor_up",
83
+ "command_cusor_down",
84
+ "command_cusor_left",
85
+ "command_cusor_right",
86
+ "command_cusor_enter",
87
+ "command_back",
88
+ "command_info",
89
+ "command_options",
90
+ "command_setup_open",
91
+ "command_setup_close",
92
+ "command_setup_query",
71
93
  ],
72
94
  )
73
95
 
@@ -168,40 +190,40 @@ ALL_ZONE_STEREO = "ALL ZONE STEREO"
168
190
 
169
191
  SOUND_MODE_MAPPING = {
170
192
  "MUSIC": [
171
- "PLII MUSIC",
172
- "DTS NEO:6 MUSIC",
193
+ "DOLBY D +NEO:X M",
194
+ "DOLBY PL2 M",
195
+ "DOLBY PL2 MUSIC",
196
+ "DOLBY PL2 X MUSIC",
173
197
  "DTS NEO:6 M",
198
+ "DTS NEO:6 MUSIC",
174
199
  "DTS NEO:X M",
175
- "DOLBY D +NEO:X M",
176
200
  "DTS NEO:X MUSIC",
177
- "DOLBY PL2 MUSIC",
178
- "DOLBY PL2 M",
201
+ "PLII MUSIC",
179
202
  "PLIIX MUSIC",
180
- "DOLBY PL2 X MUSIC",
181
203
  ],
182
204
  "MOVIE": [
183
- "PLII MOVIE",
184
- "PLII CINEMA",
185
- "DTS NEO:X CINEMA",
186
- "DTS NEO:X C",
187
- "DTS NEO:6 CINEMA",
188
- "DTS NEO:6 C",
189
205
  "DOLBY D +NEO:X C",
190
- "PLIIX CINEMA",
191
- "DOLBY PLII MOVIE",
192
- "MULTI IN + VIRTUAL:X",
193
- "DOLBY PL2 CINEMA",
194
206
  "DOLBY PL2 C",
195
- "DOLBY PL2 X MOVIE",
207
+ "DOLBY PL2 CINEMA",
196
208
  "DOLBY PL2 MOVIE",
209
+ "DOLBY PL2 X MOVIE",
210
+ "DOLBY PLII MOVIE",
211
+ "DTS NEO:6 C",
212
+ "DTS NEO:6 CINEMA",
213
+ "DTS NEO:X C",
214
+ "DTS NEO:X CINEMA",
215
+ "MULTI IN + VIRTUAL:X",
216
+ "PLII CINEMA",
217
+ "PLII MOVIE",
218
+ "PLIIX CINEMA",
197
219
  ],
198
220
  "GAME": [
199
- "PLII GAME",
200
221
  "DOLBY D +NEO:X G",
201
- "DOLBY PL2 GAME",
202
222
  "DOLBY PL2 G",
223
+ "DOLBY PL2 GAME",
203
224
  "DOLBY PL2 X GAME",
204
225
  "DOLBY PLII GAME",
226
+ "PLII GAME",
205
227
  ],
206
228
  "AUTO": ["None"],
207
229
  "STANDARD": ["None2"],
@@ -214,64 +236,74 @@ SOUND_MODE_MAPPING = {
214
236
  "DIRECT": ["DIRECT"],
215
237
  "PURE DIRECT": ["PURE_DIRECT", "PURE DIRECT"],
216
238
  "DOLBY DIGITAL": [
217
- "DOLBY DIGITAL",
218
- "DOLBY D + DOLBY SURROUND",
219
- "DOLBY D+DS",
220
- "DOLBY D+ +DS",
221
- "DOLBY DIGITAL +",
222
- "STANDARD(DOLBY)",
223
- "DOLBY SURROUND",
224
- "DOLBY D + +DOLBY SURROUND",
225
- "NEURAL",
226
- "NEURAL:X",
227
- "DOLBY HD",
228
- "DOLBY HD + DOLBY SURROUND",
229
- "MULTI IN + DSUR",
230
- "MULTI IN + NEURAL:X",
231
- "MULTI IN + DOLBY SURROUND",
232
- "DOLBY D + NEURAL:X",
233
- "DOLBY DIGITAL + NEURAL:X",
234
- "DOLBY DIGITAL + + NEURAL:X",
235
239
  "DOLBY ATMOS",
236
- "DOLBY AUDIO - DOLBY SURROUND",
237
- "DOLBY TRUEHD",
240
+ "DOLBY AUDIO - DD + DSUR",
241
+ "DOLBY AUDIO - DD + NEURAL:X",
242
+ "DOLBY AUDIO - DD+ + DSUR",
243
+ "DOLBY AUDIO - DD+ + NEURAL:X",
238
244
  "DOLBY AUDIO - DOLBY DIGITAL PLUS",
239
- "DOLBY AUDIO - TRUEHD + DSUR",
245
+ "DOLBY AUDIO - DOLBY DIGITAL",
246
+ "DOLBY AUDIO - DOLBY SURROUND",
240
247
  "DOLBY AUDIO - DOLBY TRUEHD",
248
+ "DOLBY AUDIO - TRUEHD + DSUR",
241
249
  "DOLBY AUDIO - TRUEHD + NEURAL:X",
242
- "DOLBY AUDIO - DD + NEURAL:X",
243
- "DOLBY AUDIO - DD + DSUR",
244
- "DOLBY AUDIO - DD+ + NEURAL:X",
245
- "DOLBY AUDIO - DD+ + DSUR",
250
+ "DOLBY AUDIO-DD",
246
251
  "DOLBY AUDIO-DD+ +DSUR",
247
- "DOLBY AUDIO - DOLBY DIGITAL",
248
- "DOLBY AUDIO-DSUR",
252
+ "DOLBY AUDIO-DD+ +NEURAL:X",
253
+ "DOLBY AUDIO-DD+",
249
254
  "DOLBY AUDIO-DD+DSUR",
255
+ "DOLBY AUDIO-DSUR",
256
+ "DOLBY AUDIO-TRUEHD",
257
+ "DOLBY AUDIO-TRUEHD+DSUR",
258
+ "DOLBY AUDIO-TRUEHD+NEURAL:X",
259
+ "DOLBY D + +DOLBY SURROUND",
260
+ "DOLBY D + DOLBY SURROUND",
261
+ "DOLBY D + NEURAL:X",
262
+ "DOLBY D+ +DS",
263
+ "DOLBY D+",
264
+ "DOLBY D+DS",
265
+ "DOLBY DIGITAL + + NEURAL:X",
266
+ "DOLBY DIGITAL + NEURAL:X",
267
+ "DOLBY DIGITAL +",
268
+ "DOLBY DIGITAL",
269
+ "DOLBY HD + DOLBY SURROUND",
270
+ "DOLBY HD",
250
271
  "DOLBY PRO LOGIC",
272
+ "DOLBY SURROUND",
273
+ "DOLBY TRUEHD",
274
+ "MULTI IN + DOLBY SURROUND",
275
+ "MULTI IN + DSUR",
276
+ "MULTI IN + NEURAL:X",
277
+ "NEURAL",
278
+ "STANDARD(DOLBY)",
251
279
  ],
252
280
  "DTS SURROUND": [
253
- "DTS SURROUND",
254
- "DTS NEURAL:X",
255
- "STANDARD(DTS)",
281
+ "DTS + DOLBY SURROUND",
256
282
  "DTS + NEURAL:X",
257
- "MULTI CH IN",
258
- "DTS-HD MSTR",
259
- "DTS VIRTUAL:X",
260
- "DTS-HD + NEURAL:X",
261
- "DTS-HD",
262
283
  "DTS + VIRTUAL:X",
263
- "DTS + DOLBY SURROUND",
284
+ "DTS NEURAL:X",
285
+ "DTS SURROUND",
286
+ "DTS VIRTUAL:X",
264
287
  "DTS-HD + DOLBY SURROUND",
265
288
  "DTS-HD + DSUR",
289
+ "DTS-HD + NEURAL:X",
290
+ "DTS-HD MSTR",
291
+ "DTS-HD",
266
292
  "DTS:X MSTR",
293
+ "DTS:X",
294
+ "M CH IN+DSUR",
295
+ "MULTI CH IN",
296
+ "NEURAL:X",
297
+ "STANDARD(DTS)",
298
+ "VIRTUAL:X",
267
299
  ],
268
- "AURO3D": ["AURO-3D"],
269
- "AURO2DSURR": ["AURO-2D SURROUND"],
300
+ "AURO3D": ["AURO-3D", "AURO3D"],
301
+ "AURO2DSURR": ["AURO-2D SURROUND", "AURO2DSURR"],
270
302
  "MCH STEREO": [
271
- "MULTI CH STEREO",
272
- "MULTI_CH_STEREO",
273
303
  "MCH STEREO",
274
304
  "MULTI CH IN 7.1",
305
+ "MULTI CH STEREO",
306
+ "MULTI_CH_STEREO",
275
307
  ],
276
308
  "STEREO": ["STEREO"],
277
309
  ALL_ZONE_STEREO: ["ALL ZONE STEREO"],
@@ -327,6 +359,17 @@ COMMAND_MUTE_ON_URL = "/goform/formiPhoneAppMute.xml?1+MuteOn"
327
359
  COMMAND_MUTE_OFF_URL = "/goform/formiPhoneAppMute.xml?1+MuteOff"
328
360
  COMMAND_SEL_SM_URL = "/goform/formiPhoneAppDirect.xml?MS"
329
361
  COMMAND_SET_ZST_URL = "/goform/formiPhoneAppDirect.xml?MN"
362
+ COMMAND_CURSOR_UP = "/goform/formiPhoneAppDirect.xml?MNCUP"
363
+ COMMAND_CURSOR_DOWN = "/goform/formiPhoneAppDirect.xml?MNCDN"
364
+ COMMAND_CURSOR_LEFT = "/goform/formiPhoneAppDirect.xml?MNCLT"
365
+ COMMAND_CURSOR_RIGHT = "/goform/formiPhoneAppDirect.xml?MNCRT"
366
+ COMMAND_CURSOR_ENTER = "/goform/formiPhoneAppDirect.xml?MNENT"
367
+ COMMAND_BACK = "/goform/formiPhoneAppDirect.xml?MNRTN"
368
+ COMMAND_INFO = "/goform/formiPhoneAppDirect.xml?MNINF"
369
+ COMMAND_OPTIONS = "/goform/formiPhoneAppDirect.xml?MNOPT"
370
+ COMMAND_SETUP_OPEN = "/goform/formiPhoneAppDirect.xml?MNMEN%20ON"
371
+ COMMAND_SETUP_CLOSE = "/goform/formiPhoneAppDirect.xml?MNMEN%20OFF"
372
+ COMMAND_SETUP_QUERY = "/goform/formiPhoneAppDirect.xml?MNMEN?"
330
373
 
331
374
  # Zone 2 URLs
332
375
  STATUS_Z2_URL = "/goform/formZone2_Zone2XmlStatus.xml"
@@ -375,6 +418,17 @@ DENONAVR_URLS = ReceiverURLs(
375
418
  command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
376
419
  command_pause=COMMAND_PAUSE,
377
420
  command_play=COMMAND_PLAY,
421
+ command_cusor_up=COMMAND_CURSOR_UP,
422
+ command_cusor_down=COMMAND_CURSOR_DOWN,
423
+ command_cusor_left=COMMAND_CURSOR_LEFT,
424
+ command_cusor_right=COMMAND_CURSOR_RIGHT,
425
+ command_cusor_enter=COMMAND_CURSOR_ENTER,
426
+ command_back=COMMAND_BACK,
427
+ command_info=COMMAND_INFO,
428
+ command_options=COMMAND_OPTIONS,
429
+ command_setup_open=COMMAND_SETUP_OPEN,
430
+ command_setup_close=COMMAND_SETUP_CLOSE,
431
+ command_setup_query=COMMAND_SETUP_QUERY,
378
432
  )
379
433
 
380
434
  ZONE2_URLS = ReceiverURLs(
@@ -400,6 +454,17 @@ ZONE2_URLS = ReceiverURLs(
400
454
  command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
401
455
  command_pause=COMMAND_PAUSE,
402
456
  command_play=COMMAND_PLAY,
457
+ command_cusor_up=COMMAND_CURSOR_UP,
458
+ command_cusor_down=COMMAND_CURSOR_DOWN,
459
+ command_cusor_left=COMMAND_CURSOR_LEFT,
460
+ command_cusor_right=COMMAND_CURSOR_RIGHT,
461
+ command_cusor_enter=COMMAND_CURSOR_ENTER,
462
+ command_back=COMMAND_BACK,
463
+ command_info=COMMAND_INFO,
464
+ command_options=COMMAND_OPTIONS,
465
+ command_setup_open=COMMAND_SETUP_OPEN,
466
+ command_setup_close=COMMAND_SETUP_CLOSE,
467
+ command_setup_query=COMMAND_SETUP_QUERY,
403
468
  )
404
469
 
405
470
  ZONE3_URLS = ReceiverURLs(
@@ -425,6 +490,17 @@ ZONE3_URLS = ReceiverURLs(
425
490
  command_set_all_zone_stereo=COMMAND_SET_ZST_URL,
426
491
  command_pause=COMMAND_PAUSE,
427
492
  command_play=COMMAND_PLAY,
493
+ command_cusor_up=COMMAND_CURSOR_UP,
494
+ command_cusor_down=COMMAND_CURSOR_DOWN,
495
+ command_cusor_left=COMMAND_CURSOR_LEFT,
496
+ command_cusor_right=COMMAND_CURSOR_RIGHT,
497
+ command_cusor_enter=COMMAND_CURSOR_ENTER,
498
+ command_back=COMMAND_BACK,
499
+ command_info=COMMAND_INFO,
500
+ command_options=COMMAND_OPTIONS,
501
+ command_setup_open=COMMAND_SETUP_OPEN,
502
+ command_setup_close=COMMAND_SETUP_CLOSE,
503
+ command_setup_query=COMMAND_SETUP_QUERY,
428
504
  )
429
505
 
430
506
  # Telnet Events
@@ -503,6 +579,17 @@ DENONAVR_TELNET_COMMANDS = TelnetCommands(
503
579
  command_tonecontrol="PSTONE CTRL ",
504
580
  command_bass="PSBAS ",
505
581
  command_treble="PSTRE ",
582
+ command_cusor_up="MNCUP",
583
+ command_cusor_down="MNCDN",
584
+ command_cusor_left="MNCLT",
585
+ command_cusor_right="MNCRT",
586
+ command_cusor_enter="MNENT",
587
+ command_back="MNRTN",
588
+ command_info="MNINF",
589
+ command_options="MNOPT",
590
+ command_setup_open="MNMEN ON",
591
+ command_setup_close="MNMEN OFF",
592
+ command_setup_query="MNMEN?",
506
593
  )
507
594
 
508
595
  ZONE2_TELNET_COMMANDS = TelnetCommands(
@@ -526,6 +613,17 @@ ZONE2_TELNET_COMMANDS = TelnetCommands(
526
613
  command_tonecontrol="PSTONE CTRL ",
527
614
  command_bass="PSBAS ",
528
615
  command_treble="PSTRE ",
616
+ command_cusor_up="MNCUP",
617
+ command_cusor_down="MNCDN",
618
+ command_cusor_left="MNCLT",
619
+ command_cusor_right="MNCRT",
620
+ command_cusor_enter="MNENT",
621
+ command_back="MNRTN",
622
+ command_info="MNINF",
623
+ command_options="MNOPT",
624
+ command_setup_open="MNMEN ON",
625
+ command_setup_close="MNMEN OFF",
626
+ command_setup_query="MNMEN?",
529
627
  )
530
628
 
531
629
  ZONE3_TELNET_COMMANDS = TelnetCommands(
@@ -549,6 +647,17 @@ ZONE3_TELNET_COMMANDS = TelnetCommands(
549
647
  command_tonecontrol="PSTONE CTRL ",
550
648
  command_bass="PSBAS ",
551
649
  command_treble="PSTRE ",
650
+ command_cusor_up="MNCUP",
651
+ command_cusor_down="MNCDN",
652
+ command_cusor_left="MNCLT",
653
+ command_cusor_right="MNCRT",
654
+ command_cusor_enter="MNENT",
655
+ command_back="MNRTN",
656
+ command_info="MNINF",
657
+ command_options="MNOPT",
658
+ command_setup_open="MNMEN ON",
659
+ command_setup_close="MNMEN OFF",
660
+ command_setup_query="MNMEN?",
552
661
  )
553
662
 
554
663
  # States
denonavr/decorators.py CHANGED
@@ -7,18 +7,14 @@ This module implements the REST API to Denon AVR receivers.
7
7
  :license: MIT, see LICENSE for more details.
8
8
  """
9
9
 
10
- import asyncio
11
10
  import inspect
12
11
  import logging
13
12
  import time
14
- import xml.etree.ElementTree as ET
15
13
  from functools import wraps
16
- from typing import Callable, Coroutine, TypeVar
14
+ from typing import Callable, TypeVar
17
15
 
18
16
  import httpx
19
17
  from asyncstdlib import lru_cache
20
- from defusedxml import DefusedXmlException
21
- from defusedxml.ElementTree import ParseError
22
18
 
23
19
  from .exceptions import (
24
20
  AvrForbiddenError,
@@ -34,118 +30,55 @@ AnyT = TypeVar("AnyT")
34
30
 
35
31
 
36
32
  def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
37
- """
38
- Handle exceptions raised when calling a Denon AVR endpoint asynchronously.
39
-
40
- The decorated function must either have a string variable as second
41
- argument or as "request" keyword argument.
42
- """
33
+ """Handle exceptions raised when calling a Denon AVR endpoint asynchronously."""
43
34
 
44
35
  @wraps(func)
45
36
  async def wrapper(*args, **kwargs):
46
37
  try:
47
38
  return await func(*args, **kwargs)
48
39
  except httpx.HTTPStatusError as err:
49
- _LOGGER.debug("HTTP status error on request %s", err.request, exc_info=True)
40
+ _LOGGER.debug("HTTP status error on request %s: %s", err.request, err)
50
41
  # Separate handling of 403 errors
51
42
  if err.response.status_code == 403:
52
43
  raise AvrForbiddenError(f"HTTPStatusError: {err}", err.request) from err
53
44
  raise AvrRequestError(f"HTTPStatusError: {err}", err.request) from err
54
45
  except httpx.TimeoutException as err:
55
- _LOGGER.debug(
56
- "HTTP timeout exception on request %s", err.request, exc_info=True
57
- )
46
+ _LOGGER.debug("HTTP timeout exception on request %s: %s", err.request, err)
58
47
  raise AvrTimoutError(f"TimeoutException: {err}", err.request) from err
59
48
  except httpx.NetworkError as err:
60
- _LOGGER.debug(
61
- "Network error exception on request %s", err.request, exc_info=True
62
- )
49
+ _LOGGER.debug("Network error exception on request %s: %s", err.request, err)
63
50
  raise AvrNetworkError(f"NetworkError: {err}", err.request) from err
64
51
  except httpx.RemoteProtocolError as err:
65
52
  _LOGGER.debug(
66
53
  "Remote protocol error exception on request %s",
67
54
  err.request,
68
- exc_info=True,
69
55
  )
70
56
  raise AvrInvalidResponseError(
71
57
  f"RemoteProtocolError: {err}", err.request
72
58
  ) from err
73
- except (
74
- ET.ParseError,
75
- DefusedXmlException,
76
- ParseError,
77
- UnicodeDecodeError,
78
- ) as err:
79
- _LOGGER.debug(
80
- "Defusedxml parse error on request %s", (args, kwargs), exc_info=True
81
- )
82
- raise AvrInvalidResponseError(
83
- f"XMLParseError: {err}", (args, kwargs)
84
- ) from err
85
59
 
86
60
  return wrapper
87
61
 
88
62
 
89
63
  def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
90
64
  """
91
- 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.
92
66
 
93
67
  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.
97
68
  """
98
69
  if inspect.signature(func).parameters.get("cache_id") is None:
99
70
  raise AttributeError(
100
71
  f"Function {func} does not have a 'cache_id' keyword parameter"
101
72
  )
102
73
 
103
- lru_decorator = lru_cache(maxsize=16)
74
+ lru_decorator = lru_cache(maxsize=32)
104
75
  cached_func = lru_decorator(func)
105
76
 
106
77
  @wraps(func)
107
78
  async def wrapper(*args, **kwargs):
108
79
  if kwargs.get("cache_id") is None:
109
80
  kwargs["cache_id"] = time.time()
110
- try:
111
- return await cached_func(*args, **kwargs)
112
- except Exception as err:
113
- _LOGGER.debug("Exception %s raised, clearing cache", err)
114
- cached_func.cache_clear()
115
- raise
116
81
 
117
- return wrapper
118
-
119
-
120
- def run_async_synchronously(async_func: Coroutine) -> Callable:
121
- """
122
- Decorate to run the configured asynchronous function synchronously instead.
123
-
124
- If available the corresponding function with async_ prefix is called in an
125
- own event loop. This is not efficient but it ensures backwards
126
- compatibility of this library.
127
- """
82
+ return await cached_func(*args, **kwargs)
128
83
 
129
- def decorator(func: Callable):
130
- # Check if function is a coroutine
131
- if not inspect.iscoroutinefunction(async_func):
132
- raise AttributeError(f"Function {async_func} is not a coroutine function")
133
- # Check if the signature of both functions is equal
134
- if inspect.signature(func) != inspect.signature(async_func):
135
- raise AttributeError(
136
- f"Functions {func} and {async_func} have different signatures"
137
- )
138
-
139
- @wraps(func)
140
- def wrapper(*args, **kwargs):
141
- # Run async function in own event loop
142
- loop = asyncio.new_event_loop()
143
-
144
- try:
145
- return loop.run_until_complete(async_func(*args, **kwargs))
146
- finally:
147
- loop.close()
148
-
149
- return wrapper
150
-
151
- return decorator
84
+ return wrapper