denonavr 1.1.2__py3-none-any.whl → 1.2.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/input.py CHANGED
@@ -164,7 +164,7 @@ class DenonAVRInput(DenonAVRFoundation):
164
164
  _image_url: Optional[str] = attr.ib(
165
165
  converter=attr.converters.optional(str), default=None
166
166
  )
167
- _image_available: Optional[str] = attr.ib(
167
+ _image_available: Optional[bool] = attr.ib(
168
168
  converter=attr.converters.optional(str), default=None
169
169
  )
170
170
 
@@ -174,6 +174,7 @@ class DenonAVRInput(DenonAVRFoundation):
174
174
  ),
175
175
  default=attr.Factory(set),
176
176
  )
177
+ _callback_tasks: Set[asyncio.Task] = attr.ib(attr.Factory(set))
177
178
 
178
179
  # Update tags for attributes
179
180
  # AppCommand.xml interface
@@ -197,22 +198,18 @@ class DenonAVRInput(DenonAVRFoundation):
197
198
  power_event = "Z2"
198
199
  elif self._device.zone == ZONE3:
199
200
  power_event = "Z3"
201
+ self._device.telnet_api.register_callback(power_event, self._power_callback)
202
+ self._device.telnet_api.register_callback("SI", self._input_callback)
203
+ self._device.telnet_api.register_callback("NSE", self._netaudio_callback)
204
+ self._device.telnet_api.register_callback("TF", self._tuner_callback)
205
+ self._device.telnet_api.register_callback("HD", self._hdtuner_callback)
200
206
  self._device.telnet_api.register_callback(
201
- power_event, self._async_power_callback
202
- )
203
- self._device.telnet_api.register_callback("SI", self._async_input_callback)
204
- self._device.telnet_api.register_callback("NSE", self._async_netaudio_callback)
205
- self._device.telnet_api.register_callback("TF", self._async_tuner_callback)
206
- self._device.telnet_api.register_callback("HD", self._async_hdtuner_callback)
207
- self._device.telnet_api.register_callback(
208
- "SS", self._async_input_func_update_callback
207
+ "SS", self._input_func_update_callback
209
208
  )
210
209
 
211
210
  self._is_setup = True
212
211
 
213
- async def _async_input_callback(
214
- self, zone: str, event: str, parameter: str
215
- ) -> None:
212
+ def _input_callback(self, zone: str, event: str, parameter: str) -> None:
216
213
  """Handle an input change event."""
217
214
  if self._device.zone != zone:
218
215
  return
@@ -228,9 +225,7 @@ class DenonAVRInput(DenonAVRFoundation):
228
225
  self._unset_media_state()
229
226
  self._state = STATE_ON
230
227
 
231
- async def _async_power_callback(
232
- self, zone: str, event: str, parameter: str
233
- ) -> None:
228
+ def _power_callback(self, zone: str, event: str, parameter: str) -> None:
234
229
  """Handle a power change event."""
235
230
  if self._device.zone != zone:
236
231
  return
@@ -285,9 +280,7 @@ class DenonAVRInput(DenonAVRFoundation):
285
280
  else:
286
281
  self._stop_media_update()
287
282
 
288
- async def _async_netaudio_callback(
289
- self, zone: str, event: str, parameter: str
290
- ) -> None:
283
+ def _netaudio_callback(self, zone: str, event: str, parameter: str) -> None:
291
284
  """Handle a netaudio update event."""
292
285
  if self._device.power != POWER_ON:
293
286
  return
@@ -305,12 +298,13 @@ class DenonAVRInput(DenonAVRFoundation):
305
298
  self._station = None
306
299
 
307
300
  # Refresh cover with a hash for media URL when track is changing
308
- self._image_url = ALBUM_COVERS_URL.format(
309
- host=self._device.api.host,
310
- port=self._device.api.port,
311
- hash=hash((self._title, self._artist, self._album)),
301
+ self._set_image_url(
302
+ ALBUM_COVERS_URL.format(
303
+ host=self._device.api.host,
304
+ port=self._device.api.port,
305
+ hash=hash((self._title, self._artist, self._album)),
306
+ )
312
307
  )
313
- await self._async_test_image_accessible()
314
308
 
315
309
  def _schedule_tuner_update(self) -> None:
316
310
  """Schedule a tuner update task."""
@@ -330,9 +324,7 @@ class DenonAVRInput(DenonAVRFoundation):
330
324
  else:
331
325
  self._stop_media_update()
332
326
 
333
- async def _async_tuner_callback(
334
- self, zone: str, event: str, parameter: str
335
- ) -> None:
327
+ def _tuner_callback(self, zone: str, event: str, parameter: str) -> None:
336
328
  """Handle a tuner update event."""
337
329
  if self._device.power != POWER_ON:
338
330
  return
@@ -353,10 +345,11 @@ class DenonAVRInput(DenonAVRFoundation):
353
345
  self._album = None
354
346
 
355
347
  # No special cover, using a static one
356
- self._image_url = STATIC_ALBUM_URL.format(
357
- host=self._device.api.host, port=self._device.api.port
348
+ self._set_image_url(
349
+ STATIC_ALBUM_URL.format(
350
+ host=self._device.api.host, port=self._device.api.port
351
+ )
358
352
  )
359
- await self._async_test_image_accessible()
360
353
 
361
354
  def _schedule_hdtuner_update(self) -> None:
362
355
  """Schedule a HD tuner update task."""
@@ -374,9 +367,7 @@ class DenonAVRInput(DenonAVRFoundation):
374
367
  else:
375
368
  self._stop_media_update()
376
369
 
377
- async def _async_hdtuner_callback(
378
- self, zone: str, event: str, parameter: str
379
- ) -> None:
370
+ def _hdtuner_callback(self, zone: str, event: str, parameter: str) -> None:
380
371
  """Handle an HD tuner update event."""
381
372
  if self._device.power != POWER_ON:
382
373
  return
@@ -396,19 +387,35 @@ class DenonAVRInput(DenonAVRFoundation):
396
387
  self._frequency = None
397
388
 
398
389
  # No special cover, using a static one
399
- self._image_url = STATIC_ALBUM_URL.format(
400
- host=self._device.api.host, port=self._device.api.port
390
+ self._set_image_url(
391
+ STATIC_ALBUM_URL.format(
392
+ host=self._device.api.host, port=self._device.api.port
393
+ )
401
394
  )
402
- await self._async_test_image_accessible()
403
395
 
404
- async def _async_input_func_update_callback(
396
+ def _input_func_update_callback(
405
397
  self, zone: str, event: str, parameter: str
406
398
  ) -> None:
407
399
  """Handle input func update events."""
408
400
  if self._input_func_update_lock.locked():
409
401
  return
410
- async with self._input_func_update_lock:
411
- await self.async_update_inputfuncs()
402
+ task = asyncio.create_task(self.async_update_inputfuncs())
403
+ self._callback_tasks.add(task)
404
+ task.add_done_callback(self._callback_tasks.discard)
405
+
406
+ def _set_image_url(self, image_url: str) -> None:
407
+ """Set image URL if it is accessible."""
408
+ if self._image_available is False:
409
+ return
410
+
411
+ self._image_url = image_url
412
+
413
+ if self._image_available:
414
+ return
415
+
416
+ task = asyncio.create_task(self._async_test_image_accessible())
417
+ self._callback_tasks.add(task)
418
+ task.add_done_callback(self._callback_tasks.discard)
412
419
 
413
420
  async def async_update(
414
421
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
@@ -621,16 +628,17 @@ class DenonAVRInput(DenonAVRFoundation):
621
628
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
622
629
  ) -> None:
623
630
  """Update sources list from receiver."""
624
- if self._device.receiver in [AVR_X, AVR_X_2016]:
625
- await self._async_update_inputfuncs_avr_x(
626
- global_update=global_update, cache_id=cache_id
627
- )
628
- elif self._device.receiver in [AVR]:
629
- await self._async_update_inputfuncs_avr(cache_id=cache_id)
630
- else:
631
- raise AvrProcessingError(
632
- "Device is not setup correctly, receiver type not set"
633
- )
631
+ async with self._input_func_update_lock:
632
+ if self._device.receiver in [AVR_X, AVR_X_2016]:
633
+ await self._async_update_inputfuncs_avr_x(
634
+ global_update=global_update, cache_id=cache_id
635
+ )
636
+ elif self._device.receiver in [AVR]:
637
+ await self._async_update_inputfuncs_avr(cache_id=cache_id)
638
+ else:
639
+ raise AvrProcessingError(
640
+ "Device is not setup correctly, receiver type not set"
641
+ )
634
642
 
635
643
  async def _async_update_inputfuncs_avr_x(
636
644
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
denonavr/soundmode.py CHANGED
@@ -22,19 +22,25 @@ from .const import (
22
22
  AURO_3D_MODE_MAP_MAP_LABELS,
23
23
  AURO_MATIC_3D_PRESET_MAP,
24
24
  AURO_MATIC_3D_PRESET_MAP_LABELS,
25
+ DAC_FILTERS_MAP,
26
+ DAC_FILTERS_MAP_LABELS,
25
27
  DENON_ATTR_SETATTR,
26
28
  DIALOG_ENHANCER_LEVEL_MAP,
27
29
  DIALOG_ENHANCER_LEVEL_MAP_LABELS,
28
30
  EFFECT_SPEAKER_SELECTION_MAP,
29
31
  EFFECT_SPEAKER_SELECTION_MAP_LABELS,
32
+ MDAX_MAP,
33
+ MDAX_MAP_LABELS,
30
34
  SOUND_MODE_MAPPING,
31
35
  Auro3DModes,
32
36
  AuroMatic3DPresets,
37
+ DACFilters,
33
38
  DialogEnhancerLevels,
34
39
  DRCs,
35
40
  EffectSpeakers,
36
41
  IMAXHPFs,
37
42
  IMAXLPFs,
43
+ MDAXs,
38
44
  )
39
45
  from .exceptions import AvrCommandError, AvrIncompleteResponseError, AvrProcessingError
40
46
  from .foundation import DenonAVRFoundation, convert_on_off_bool
@@ -145,6 +151,14 @@ class DenonAVRSoundMode(DenonAVRFoundation):
145
151
  _effect_speakers = get_args(EffectSpeakers)
146
152
  _drc: Optional[str] = attr.ib(converter=attr.converters.optional(str), default=None)
147
153
  _drcs = get_args(DRCs)
154
+ _mdax: Optional[str] = attr.ib(
155
+ converter=attr.converters.optional(str), default=None
156
+ )
157
+ _mdaxs = get_args(MDAXs)
158
+ _dac_filter: Optional[str] = attr.ib(
159
+ converter=attr.converters.optional(str), default=None
160
+ )
161
+ _dac_filters = get_args(DACFilters)
148
162
  _sound_mode_map: Dict[str, list] = attr.ib(
149
163
  validator=attr.validators.deep_mapping(
150
164
  attr.validators.instance_of(str),
@@ -188,43 +202,41 @@ class DenonAVRSoundMode(DenonAVRFoundation):
188
202
  for tag in self.appcommand_attrs:
189
203
  self._device.api.add_appcommand_update_tag(tag)
190
204
 
205
+ self._device.telnet_api.register_callback("MS", self._soundmode_callback)
206
+ self._device.telnet_api.register_callback("PS", self._neural_x_callback)
207
+ self._device.telnet_api.register_callback("PS", self._imax_callback)
208
+ self._device.telnet_api.register_callback("PS", self._cinema_eq_callback)
191
209
  self._device.telnet_api.register_callback(
192
- "MS", self._async_soundmode_callback
193
- )
194
- self._device.telnet_api.register_callback(
195
- "PS", self._async_neural_x_callback
196
- )
197
- self._device.telnet_api.register_callback("PS", self._async_imax_callback)
198
- self._device.telnet_api.register_callback(
199
- "PS", self._async_cinema_eq_callback
200
- )
201
- self._device.telnet_api.register_callback(
202
- "PS", self._async_center_spread_callback
210
+ "PS", self._center_spread_callback
203
211
  )
204
212
  self._device.telnet_api.register_callback(
205
- "PS", self._async_loudness_management_callback
213
+ "PS", self._loudness_management_callback
206
214
  )
207
215
  self._device.telnet_api.register_callback(
208
- "PS", self._async_dialog_enhancer_callback
216
+ "PS", self._dialog_enhancer_callback
209
217
  )
210
- self._device.telnet_api.register_callback("PS", self._async_auro_callback)
218
+ self._device.telnet_api.register_callback("PS", self._auro_callback)
211
219
  self._device.telnet_api.register_callback(
212
- "PS", self._async_dialog_control_callback
220
+ "PS", self._dialog_control_callback
213
221
  )
214
222
  self._device.telnet_api.register_callback(
215
- "PS", self._async_speaker_virtualizer_callback
223
+ "PS", self._speaker_virtualizer_callback
216
224
  )
217
225
  self._device.telnet_api.register_callback(
218
- "PS", self._async_effect_speaker_selection_callback
226
+ "PS", self._effect_speaker_selection_callback
219
227
  )
220
- self._device.telnet_api.register_callback("PS", self._async_drc_callback)
228
+ self._device.telnet_api.register_callback("PS", self._drc_callback)
229
+
230
+ if not self._device.is_denon:
231
+ self._device.telnet_api.register_callback("PS", self._mdax_callback)
232
+ self._device.telnet_api.register_callback(
233
+ "PS", self._dac_filter_callback
234
+ )
221
235
 
222
236
  self._is_setup = True
223
237
  _LOGGER.debug("Finished sound mode setup")
224
238
 
225
- async def _async_soundmode_callback(
226
- self, zone: str, event: str, parameter: str
227
- ) -> None:
239
+ def _soundmode_callback(self, zone: str, event: str, parameter: str) -> None:
228
240
  """Handle a sound mode change event."""
229
241
  if self._device.zone != zone:
230
242
  return
@@ -235,15 +247,13 @@ class DenonAVRSoundMode(DenonAVRFoundation):
235
247
 
236
248
  self._sound_mode_raw = parameter
237
249
 
238
- async def _async_neural_x_callback(
239
- self, zone: str, event: str, parameter: str
240
- ) -> None:
250
+ def _neural_x_callback(self, zone: str, event: str, parameter: str) -> None:
241
251
  """Handle a Neural X:change event."""
242
252
  parameter_name_length = len("NEURAL")
243
253
  if parameter[:parameter_name_length] == "NEURAL":
244
254
  self._neural_x = parameter[parameter_name_length + 1 :]
245
255
 
246
- async def _async_imax_callback(self, zone: str, event: str, parameter: str) -> None:
256
+ def _imax_callback(self, zone: str, event: str, parameter: str) -> None:
247
257
  """Handle an IMAX change event."""
248
258
  key_value = parameter.split()
249
259
  if len(key_value) != 2 or key_value[0][:4] != "IMAX":
@@ -262,37 +272,31 @@ class DenonAVRSoundMode(DenonAVRFoundation):
262
272
  elif key_value[0] == "IMAXSWO":
263
273
  self._imax_subwoofer_output = parameter[8:]
264
274
 
265
- async def _async_cinema_eq_callback(
266
- self, zone: str, event: str, parameter: str
267
- ) -> None:
275
+ def _cinema_eq_callback(self, zone: str, event: str, parameter: str) -> None:
268
276
  """Handle a Cinema EQ change event."""
269
277
  if parameter[:10] == "CINEMA EQ.":
270
278
  self._cinema_eq = parameter[10:]
271
279
 
272
- async def _async_center_spread_callback(
273
- self, zone: str, event: str, parameter: str
274
- ) -> None:
280
+ def _center_spread_callback(self, zone: str, event: str, parameter: str) -> None:
275
281
  """Handle a Center Spread change event."""
276
282
  if parameter[:3] == "CES":
277
283
  self._center_spread = parameter[4:]
278
284
 
279
- async def _async_loudness_management_callback(
285
+ def _loudness_management_callback(
280
286
  self, zone: str, event: str, parameter: str
281
287
  ) -> None:
282
288
  """Handle a Loudness Management change event."""
283
289
  if parameter[:3] == "LOM":
284
290
  self._loudness_management = parameter[4:]
285
291
 
286
- async def _async_dialog_enhancer_callback(
287
- self, zone: str, event: str, parameter: str
288
- ) -> None:
292
+ def _dialog_enhancer_callback(self, zone: str, event: str, parameter: str) -> None:
289
293
  """Handle a Dialog Enhancer change event."""
290
294
  if parameter[:3] == "DEH":
291
295
  self._dialog_enhancer_level = DIALOG_ENHANCER_LEVEL_MAP_LABELS[
292
296
  parameter[4:]
293
297
  ]
294
298
 
295
- async def _async_auro_callback(self, zone: str, event: str, parameter: str) -> None:
299
+ def _auro_callback(self, zone: str, event: str, parameter: str) -> None:
296
300
  """Handle a Auro change event."""
297
301
  key_value = parameter.split()
298
302
  if len(key_value) != 2 or key_value[0][:4] != "AURO":
@@ -305,9 +309,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
305
309
  elif key_value[0] == "AUROMODE":
306
310
  self._auro_3d_mode = AURO_3D_MODE_MAP_MAP_LABELS[parameter[9:]]
307
311
 
308
- async def _async_dialog_control_callback(
309
- self, zone: str, event: str, parameter: str
310
- ) -> None:
312
+ def _dialog_control_callback(self, zone: str, event: str, parameter: str) -> None:
311
313
  """Handle a Dialog Control change event."""
312
314
  key_value = parameter.split()
313
315
  if len(key_value) != 2 or key_value[0] != "DIC":
@@ -315,7 +317,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
315
317
 
316
318
  self._dialog_control = int(key_value[1])
317
319
 
318
- async def _async_speaker_virtualizer_callback(
320
+ def _speaker_virtualizer_callback(
319
321
  self, zone: str, event: str, parameter: str
320
322
  ) -> None:
321
323
  """Handle a Speaker Virtualizer change event."""
@@ -325,7 +327,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
325
327
 
326
328
  self._speaker_virtualizer = key_value[1]
327
329
 
328
- async def _async_effect_speaker_selection_callback(
330
+ def _effect_speaker_selection_callback(
329
331
  self, zone: str, event: str, parameter: str
330
332
  ) -> None:
331
333
  """Handle a Effect Speaker Selection change event."""
@@ -337,7 +339,7 @@ class DenonAVRSoundMode(DenonAVRFoundation):
337
339
  key_value[1]
338
340
  ]
339
341
 
340
- async def _async_drc_callback(self, zone: str, event: str, parameter: str) -> None:
342
+ def _drc_callback(self, zone: str, event: str, parameter: str) -> None:
341
343
  """Handle a DRC change event."""
342
344
  key_value = parameter.split()
343
345
  if len(key_value) != 2 or key_value[0] != "DRC":
@@ -345,6 +347,22 @@ class DenonAVRSoundMode(DenonAVRFoundation):
345
347
 
346
348
  self._drc = key_value[1]
347
349
 
350
+ def _mdax_callback(self, zone: str, event: str, parameter: str) -> None:
351
+ """Handle a M-DAX change event."""
352
+ key_value = parameter.split()
353
+ if len(key_value) != 2 or key_value[0] != "MDAX":
354
+ return
355
+
356
+ self._mdax = MDAX_MAP_LABELS[key_value[1]]
357
+
358
+ def _dac_filter_callback(self, zone: str, event: str, parameter: str) -> None:
359
+ """Handle a DAC Filter change event."""
360
+ key_value = parameter.split()
361
+ if len(key_value) != 2 or key_value[0] != "DACFIL":
362
+ return
363
+
364
+ self._dac_filter = DAC_FILTERS_MAP_LABELS[key_value[1]]
365
+
348
366
  async def async_update(
349
367
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
350
368
  ) -> None:
@@ -691,6 +709,28 @@ class DenonAVRSoundMode(DenonAVRFoundation):
691
709
  """
692
710
  return self._drc
693
711
 
712
+ @property
713
+ def mdax(self) -> Optional[str]:
714
+ """
715
+ Return the current M-DAX status.
716
+
717
+ Only available on Marantz devices and when using Telnet.
718
+
719
+ Possible values are: "Off", "Low", "Medium", "High"
720
+ """
721
+ return self._mdax
722
+
723
+ @property
724
+ def dac_filter(self) -> Optional[str]:
725
+ """
726
+ Return the current DAC Filter status.
727
+
728
+ Only available on Marantz devices and when using Telnet.
729
+
730
+ Possible values are: "Mode 1", "Mode 2"
731
+ """
732
+ return self._dac_filter
733
+
694
734
  ##########
695
735
  # Setter #
696
736
  ##########
@@ -1227,6 +1267,50 @@ class DenonAVRSoundMode(DenonAVRFoundation):
1227
1267
  self._device.urls.command_drc.format(mode=mode)
1228
1268
  )
1229
1269
 
1270
+ async def async_mdax(self, mode: MDAXs) -> None:
1271
+ """
1272
+ Set M-DAX mode.
1273
+
1274
+ Only available for Marantz devices.
1275
+ """
1276
+ if self._device.is_denon:
1277
+ raise AvrCommandError("M-DAX is only available for Marantz devices")
1278
+
1279
+ if mode not in self._mdaxs:
1280
+ raise AvrCommandError(f"{mode} is not a valid M-DAX mode")
1281
+
1282
+ local_mode = MDAX_MAP[mode]
1283
+ if self._device.telnet_available:
1284
+ await self._device.telnet_api.async_send_commands(
1285
+ self._device.telnet_commands.command_mdax.format(mode=local_mode)
1286
+ )
1287
+ else:
1288
+ await self._device.api.async_get_command(
1289
+ self._device.urls.command_mdax.format(mode=local_mode)
1290
+ )
1291
+
1292
+ async def async_dac_filter(self, mode: DACFilters) -> None:
1293
+ """
1294
+ Set DAC Filter mode.
1295
+
1296
+ Only available for Marantz devices.
1297
+ """
1298
+ if self._device.is_denon:
1299
+ raise AvrCommandError("DAC Filter is only available for Marantz devices")
1300
+
1301
+ if mode not in self._dac_filters:
1302
+ raise AvrCommandError(f"{mode} is not a valid DAC Filter mode")
1303
+
1304
+ local_mode = DAC_FILTERS_MAP[mode]
1305
+ if self._device.telnet_available:
1306
+ await self._device.telnet_api.async_send_commands(
1307
+ self._device.telnet_commands.command_dac_filter.format(mode=local_mode)
1308
+ )
1309
+ else:
1310
+ await self._device.api.async_get_command(
1311
+ self._device.urls.command_dac_filter.format(mode=local_mode)
1312
+ )
1313
+
1230
1314
 
1231
1315
  def sound_mode_factory(instance: DenonAVRFoundation) -> DenonAVRSoundMode:
1232
1316
  """Create DenonAVRSoundMode at receiver instances."""
denonavr/ssdp.py CHANGED
@@ -91,17 +91,18 @@ async def async_identify_denonavr_receivers() -> List[Dict]:
91
91
  # Check which responding device is a DenonAVR device and prepare output
92
92
  receivers = []
93
93
 
94
- for url in urls:
95
- try:
96
- async with httpx.AsyncClient() as client:
97
- res = await client.get(url, timeout=5.0)
98
- res.raise_for_status()
99
- except httpx.HTTPError:
100
- continue
101
- else:
102
- receiver = evaluate_scpd_xml(url, res.text)
103
- if receiver is not None:
104
- receivers.append(receiver)
94
+ async with httpx.AsyncClient() as client:
95
+ for url in urls:
96
+ try:
97
+ async with client.stream("GET", url, timeout=5.0) as res:
98
+ res.raise_for_status()
99
+ await res.aread()
100
+ except httpx.HTTPError:
101
+ continue
102
+ else:
103
+ receiver = evaluate_scpd_xml(url, res.text)
104
+ if receiver is not None:
105
+ receivers.append(receiver)
105
106
 
106
107
  return receivers
107
108
 
denonavr/tonecontrol.py CHANGED
@@ -67,16 +67,12 @@ class DenonAVRToneControl(DenonAVRFoundation):
67
67
  for tag in self.appcommand_attrs:
68
68
  self._device.api.add_appcommand_update_tag(tag)
69
69
 
70
- self._device.telnet_api.register_callback(
71
- "PS", self._async_sound_detail_callback
72
- )
70
+ self._device.telnet_api.register_callback("PS", self._sound_detail_callback)
73
71
 
74
72
  self._is_setup = True
75
73
  _LOGGER.debug("Finished tone control setup")
76
74
 
77
- async def _async_sound_detail_callback(
78
- self, zone: str, event: str, parameter: str
79
- ) -> None:
75
+ def _sound_detail_callback(self, zone: str, event: str, parameter: str) -> None:
80
76
  """Handle a sound detail change event."""
81
77
  if self._device.zone != zone:
82
78
  return
denonavr/volume.py CHANGED
@@ -82,25 +82,17 @@ class DenonAVRVolume(DenonAVRFoundation):
82
82
  for tag in self.appcommand_attrs:
83
83
  self._device.api.add_appcommand_update_tag(tag)
84
84
 
85
- self._device.telnet_api.register_callback("MV", self._async_volume_callback)
86
- self._device.telnet_api.register_callback("MU", self._async_mute_callback)
87
- self._device.telnet_api.register_callback(
88
- "CV", self._async_channel_volume_callback
89
- )
90
- self._device.telnet_api.register_callback(
91
- "PS", self._async_subwoofer_state_callback
92
- )
93
- self._device.telnet_api.register_callback(
94
- "PS", self._async_subwoofer_levels_callback
95
- )
96
- self._device.telnet_api.register_callback("PS", self._async_lfe_callback)
97
- self._device.telnet_api.register_callback("PS", self._async_bass_sync_callback)
85
+ self._device.telnet_api.register_callback("MV", self._volume_callback)
86
+ self._device.telnet_api.register_callback("MU", self._mute_callback)
87
+ self._device.telnet_api.register_callback("CV", self._channel_volume_callback)
88
+ self._device.telnet_api.register_callback("PS", self._subwoofer_state_callback)
89
+ self._device.telnet_api.register_callback("PS", self._subwoofer_levels_callback)
90
+ self._device.telnet_api.register_callback("PS", self._lfe_callback)
91
+ self._device.telnet_api.register_callback("PS", self._bass_sync_callback)
98
92
 
99
93
  self._is_setup = True
100
94
 
101
- async def _async_volume_callback(
102
- self, zone: str, event: str, parameter: str
103
- ) -> None:
95
+ def _volume_callback(self, zone: str, event: str, parameter: str) -> None:
104
96
  """Handle a volume change event."""
105
97
  if self._device.zone != zone:
106
98
  return
@@ -112,16 +104,14 @@ class DenonAVRVolume(DenonAVRFoundation):
112
104
  fraction = 0.1 * float(parameter[2])
113
105
  self._volume = -80.0 + whole_number + fraction
114
106
 
115
- async def _async_mute_callback(self, zone: str, event: str, parameter: str) -> None:
107
+ def _mute_callback(self, zone: str, event: str, parameter: str) -> None:
116
108
  """Handle a muting change event."""
117
109
  if self._device.zone != zone:
118
110
  return
119
111
 
120
112
  self._muted = parameter
121
113
 
122
- async def _async_channel_volume_callback(
123
- self, zone: str, event: str, parameter: str
124
- ) -> None:
114
+ def _channel_volume_callback(self, zone: str, event: str, parameter: str) -> None:
125
115
  """Handle a channel volume change event."""
126
116
  if event != "CV":
127
117
  return
@@ -141,16 +131,12 @@ class DenonAVRVolume(DenonAVRFoundation):
141
131
  volume = channel_volume[1]
142
132
  self._channel_volumes[channel] = CHANNEL_VOLUME_MAP[volume]
143
133
 
144
- async def _async_subwoofer_state_callback(
145
- self, zone: str, event: str, parameter: str
146
- ) -> None:
134
+ def _subwoofer_state_callback(self, zone: str, event: str, parameter: str) -> None:
147
135
  """Handle a subwoofer state change event."""
148
136
  if parameter[:3] == "SWR":
149
137
  self._subwoofer = parameter[4:]
150
138
 
151
- async def _async_subwoofer_levels_callback(
152
- self, zone: str, event: str, parameter: str
153
- ) -> None:
139
+ def _subwoofer_levels_callback(self, zone: str, event: str, parameter: str) -> None:
154
140
  """Handle a subwoofer levels change event."""
155
141
  if parameter[:3] != "SWL":
156
142
  return
@@ -173,16 +159,14 @@ class DenonAVRVolume(DenonAVRFoundation):
173
159
  elif level in CHANNEL_VOLUME_MAP:
174
160
  self._subwoofer_levels[subwoofer] = CHANNEL_VOLUME_MAP[level]
175
161
 
176
- async def _async_lfe_callback(self, zone: str, event: str, parameter: str) -> None:
162
+ def _lfe_callback(self, zone: str, event: str, parameter: str) -> None:
177
163
  """Handle a LFE change event."""
178
164
  if parameter[:3] != "LFE":
179
165
  return
180
166
 
181
167
  self._lfe = int(parameter[4:]) * -1
182
168
 
183
- async def _async_bass_sync_callback(
184
- self, zone: str, event: str, parameter: str
185
- ) -> None:
169
+ def _bass_sync_callback(self, zone: str, event: str, parameter: str) -> None:
186
170
  """Handle a LFE change event."""
187
171
  if parameter[:3] != "BSC":
188
172
  return
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: denonavr
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: Automation Library for Denon AVR receivers
5
5
  Author-email: Oliver Goetz <scarface@mywoh.de>
6
6
  License: MIT
@@ -20,6 +20,7 @@ Classifier: Programming Language :: Python :: 3.10
20
20
  Classifier: Programming Language :: Python :: 3.11
21
21
  Classifier: Programming Language :: Python :: 3.12
22
22
  Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
23
24
  Requires-Python: >=3.8
24
25
  Description-Content-Type: text/markdown; charset=UTF-8
25
26
  License-File: LICENSE