denonavr 0.11.4__tar.gz → 0.11.6__tar.gz
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-0.11.4 → denonavr-0.11.6}/PKG-INFO +6 -4
- {denonavr-0.11.4 → denonavr-0.11.6}/README.md +3 -3
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/__init__.py +1 -1
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/api.py +117 -26
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/audyssey.py +54 -10
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/const.py +69 -6
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/decorators.py +19 -25
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/denonavr.py +49 -6
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/foundation.py +24 -12
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/input.py +41 -34
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/soundmode.py +14 -8
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/ssdp.py +2 -2
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/tonecontrol.py +83 -27
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/volume.py +28 -22
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/PKG-INFO +6 -4
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/requires.txt +1 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/pyproject.toml +3 -1
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/test_denonavr.py +40 -15
- {denonavr-0.11.4 → denonavr-0.11.6}/LICENSE +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/appcommand.py +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/exceptions.py +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/SOURCES.txt +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/dependency_links.txt +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/not-zip-safe +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/top_level.txt +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/setup.cfg +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/__init__.py +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/test_ssdp.py +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-Deviceinfo-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-Deviceinfo-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-Deviceinfo-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1600H_upnp.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-Deviceinfo-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-Deviceinfo-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-AppCommand-setup.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-AppCommand-update.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-Deviceinfo.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formMainZone_MainZoneXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formMainZone_MainZoneXmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formNetAudio_StatusXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formTuner_HdXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formTuner_TunerXml.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formZone2_Zone2XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formZone3_Zone3XmlStatus.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6012-AppCommand-setup-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6012-AppCommand-update-8080.xml +0 -0
- {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6012-Deviceinfo-8080.xml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: denonavr
|
|
3
|
-
Version: 0.11.
|
|
3
|
+
Version: 0.11.6
|
|
4
4
|
Summary: Automation Library for Denon AVR receivers
|
|
5
5
|
Author-email: Oliver Goetz <scarface@mywoh.de>
|
|
6
6
|
License: MIT
|
|
@@ -19,12 +19,14 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
23
|
Requires-Python: >=3.7
|
|
23
24
|
Description-Content-Type: text/markdown; charset=UTF-8
|
|
24
25
|
License-File: LICENSE
|
|
25
26
|
Requires-Dist: asyncstdlib>=3.10.2
|
|
26
27
|
Requires-Dist: attrs>=21.2.0
|
|
27
28
|
Requires-Dist: defusedxml>=0.7.1
|
|
29
|
+
Requires-Dist: ftfy>=6.1.1
|
|
28
30
|
Requires-Dist: httpx>=0.23.1
|
|
29
31
|
Requires-Dist: netifaces>=0.11.0
|
|
30
32
|
Requires-Dist: async-timeout>=4.0.2; python_version < "3.11"
|
|
@@ -58,7 +60,7 @@ In addition to retrieving the current device status via HTTP calls, this version
|
|
|
58
60
|
|
|
59
61
|
As of version 0.10.0 and newer, the `denonavr` library has switched to using`async` methods to interact with Denon receivers.
|
|
60
62
|
|
|
61
|
-
Legacy synchronous methods are still
|
|
63
|
+
Legacy synchronous methods are still available to avoid breaking existing implementations, but may be deprecated in the future. Switching to `async` methods is recommended. The existing sync methods are inefficient because they use the corresponding async methods by starting and stopping its own `asyncio` loop for each command.
|
|
62
64
|
|
|
63
65
|
### Other changes:
|
|
64
66
|
|
|
@@ -129,8 +131,8 @@ The `asyncio` library should automatically be imported in the REPL. Import the
|
|
|
129
131
|
```
|
|
130
132
|
### Sound
|
|
131
133
|
```
|
|
132
|
-
>>> await d.
|
|
133
|
-
>>> await d.
|
|
134
|
+
>>> await d.async_mute(True)
|
|
135
|
+
>>> await d.async_mute(False)
|
|
134
136
|
```
|
|
135
137
|
|
|
136
138
|
### Other methods
|
|
@@ -17,7 +17,7 @@ In addition to retrieving the current device status via HTTP calls, this version
|
|
|
17
17
|
|
|
18
18
|
As of version 0.10.0 and newer, the `denonavr` library has switched to using`async` methods to interact with Denon receivers.
|
|
19
19
|
|
|
20
|
-
Legacy synchronous methods are still
|
|
20
|
+
Legacy synchronous methods are still available to avoid breaking existing implementations, but may be deprecated in the future. Switching to `async` methods is recommended. The existing sync methods are inefficient because they use the corresponding async methods by starting and stopping its own `asyncio` loop for each command.
|
|
21
21
|
|
|
22
22
|
### Other changes:
|
|
23
23
|
|
|
@@ -88,8 +88,8 @@ The `asyncio` library should automatically be imported in the REPL. Import the
|
|
|
88
88
|
```
|
|
89
89
|
### Sound
|
|
90
90
|
```
|
|
91
|
-
>>> await d.
|
|
92
|
-
>>> await d.
|
|
91
|
+
>>> await d.async_mute(True)
|
|
92
|
+
>>> await d.async_mute(False)
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
### Other methods
|
|
@@ -14,22 +14,23 @@ import sys
|
|
|
14
14
|
import time
|
|
15
15
|
import xml.etree.ElementTree as ET
|
|
16
16
|
from collections import defaultdict
|
|
17
|
+
from collections.abc import Hashable
|
|
17
18
|
from io import BytesIO
|
|
18
19
|
from typing import (
|
|
19
20
|
Awaitable,
|
|
20
21
|
Callable,
|
|
22
|
+
Coroutine,
|
|
21
23
|
DefaultDict,
|
|
22
24
|
Dict,
|
|
23
|
-
Hashable,
|
|
24
25
|
List,
|
|
25
26
|
Optional,
|
|
27
|
+
Set,
|
|
26
28
|
Tuple,
|
|
27
29
|
cast,
|
|
28
30
|
)
|
|
29
31
|
|
|
30
32
|
import attr
|
|
31
33
|
import httpx
|
|
32
|
-
from asyncstdlib import lru_cache
|
|
33
34
|
from defusedxml.ElementTree import fromstring
|
|
34
35
|
|
|
35
36
|
from .appcommand import AppCommandCmd
|
|
@@ -48,15 +49,12 @@ from .const import (
|
|
|
48
49
|
ZONE2,
|
|
49
50
|
ZONE3,
|
|
50
51
|
)
|
|
51
|
-
from .decorators import
|
|
52
|
-
async_handle_receiver_exceptions,
|
|
53
|
-
cache_clear_on_exception,
|
|
54
|
-
set_cache_id,
|
|
55
|
-
)
|
|
52
|
+
from .decorators import async_handle_receiver_exceptions, cache_result
|
|
56
53
|
from .exceptions import (
|
|
57
54
|
AvrIncompleteResponseError,
|
|
58
55
|
AvrInvalidResponseError,
|
|
59
56
|
AvrNetworkError,
|
|
57
|
+
AvrProcessingError,
|
|
60
58
|
AvrTimoutError,
|
|
61
59
|
)
|
|
62
60
|
|
|
@@ -179,9 +177,7 @@ class DenonAVRApi:
|
|
|
179
177
|
# Return text
|
|
180
178
|
return res.text
|
|
181
179
|
|
|
182
|
-
@
|
|
183
|
-
@cache_clear_on_exception
|
|
184
|
-
@lru_cache(maxsize=32)
|
|
180
|
+
@cache_result
|
|
185
181
|
@async_handle_receiver_exceptions
|
|
186
182
|
async def async_get_xml(
|
|
187
183
|
self, request: str, cache_id: Hashable = None
|
|
@@ -196,9 +192,7 @@ class DenonAVRApi:
|
|
|
196
192
|
# Return ElementTree element
|
|
197
193
|
return xml_root
|
|
198
194
|
|
|
199
|
-
@
|
|
200
|
-
@cache_clear_on_exception
|
|
201
|
-
@lru_cache(maxsize=32)
|
|
195
|
+
@cache_result
|
|
202
196
|
@async_handle_receiver_exceptions
|
|
203
197
|
async def async_post_appcommand(
|
|
204
198
|
self, request: str, cmds: Tuple[AppCommandCmd], cache_id: Hashable = None
|
|
@@ -357,7 +351,7 @@ class DenonAVRApi:
|
|
|
357
351
|
return body_bytes
|
|
358
352
|
|
|
359
353
|
def is_default_async_client(self) -> bool:
|
|
360
|
-
"""Check if default httpx.
|
|
354
|
+
"""Check if default httpx.AsyncClient getter is used."""
|
|
361
355
|
return self.async_client_getter is get_default_async_client
|
|
362
356
|
|
|
363
357
|
|
|
@@ -430,11 +424,28 @@ class DenonAVRTelnetApi:
|
|
|
430
424
|
_telnet_event_map: Dict[str, List] = attr.ib(
|
|
431
425
|
default=attr.Factory(telnet_event_map_factory)
|
|
432
426
|
)
|
|
433
|
-
|
|
427
|
+
_callback_tasks: Set[asyncio.Task] = attr.ib(attr.Factory(set))
|
|
428
|
+
_send_lock: asyncio.Lock = attr.ib(default=attr.Factory(asyncio.Lock))
|
|
429
|
+
_send_confirmation_timeout: float = attr.ib(converter=float, default=2.0)
|
|
430
|
+
_send_confirmation_event: asyncio.Event = attr.ib(
|
|
431
|
+
default=attr.Factory(asyncio.Event)
|
|
432
|
+
)
|
|
433
|
+
_send_confirmation_command: str = attr.ib(converter=str, default="")
|
|
434
|
+
_send_tasks: Set[asyncio.Task] = attr.ib(attr.Factory(set))
|
|
435
|
+
_callbacks: Dict[str, List[Coroutine]] = attr.ib(
|
|
434
436
|
validator=attr.validators.instance_of(dict),
|
|
435
437
|
default=attr.Factory(dict),
|
|
436
438
|
init=False,
|
|
437
439
|
)
|
|
440
|
+
_raw_callbacks: List[Coroutine] = attr.ib(
|
|
441
|
+
validator=attr.validators.instance_of(list),
|
|
442
|
+
default=attr.Factory(list),
|
|
443
|
+
init=False,
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
def __attrs_post_init__(self) -> None:
|
|
447
|
+
"""Initialize special attributes."""
|
|
448
|
+
self._register_raw_callback(self._async_send_confirmation_callback)
|
|
438
449
|
|
|
439
450
|
async def async_connect(self) -> None:
|
|
440
451
|
"""Connect to the receiver asynchronously."""
|
|
@@ -478,7 +489,25 @@ class DenonAVRTelnetApi:
|
|
|
478
489
|
self._connection_enabled = True
|
|
479
490
|
self._last_message_time = time.monotonic()
|
|
480
491
|
self._schedule_monitor()
|
|
481
|
-
|
|
492
|
+
# Trigger update of all attributes
|
|
493
|
+
await self.async_send_commands(
|
|
494
|
+
"ZM?",
|
|
495
|
+
"SI?",
|
|
496
|
+
"MV?",
|
|
497
|
+
"MU?",
|
|
498
|
+
"Z2?",
|
|
499
|
+
"Z2MU?",
|
|
500
|
+
"Z3?",
|
|
501
|
+
"Z3MU?",
|
|
502
|
+
"PSTONE CTRL ?",
|
|
503
|
+
"PSBAS ?",
|
|
504
|
+
"PSTRE ?",
|
|
505
|
+
"PSDYNEQ ?",
|
|
506
|
+
"PSMULTEQ: ?",
|
|
507
|
+
"PSREFLEV ?",
|
|
508
|
+
"PSDYNVOL ?",
|
|
509
|
+
"MS?",
|
|
510
|
+
)
|
|
482
511
|
|
|
483
512
|
def _schedule_monitor(self) -> None:
|
|
484
513
|
"""Start the monitor task."""
|
|
@@ -584,6 +613,18 @@ class DenonAVRTelnetApi:
|
|
|
584
613
|
return
|
|
585
614
|
self._callbacks[event].remove(callback)
|
|
586
615
|
|
|
616
|
+
def _register_raw_callback(
|
|
617
|
+
self, callback: Callable[[str], Awaitable[None]]
|
|
618
|
+
) -> None:
|
|
619
|
+
"""Register a callback handler for raw telnet messages."""
|
|
620
|
+
self._raw_callbacks.append(callback)
|
|
621
|
+
|
|
622
|
+
def _unregister_raw_callback(
|
|
623
|
+
self, callback: Callable[[str], Awaitable[None]]
|
|
624
|
+
) -> None:
|
|
625
|
+
"""Unregister a callback handler for raw telnet messages."""
|
|
626
|
+
self._raw_callbacks.remove(callback)
|
|
627
|
+
|
|
587
628
|
def _process_event(self, message: str) -> None:
|
|
588
629
|
"""Process a realtime event."""
|
|
589
630
|
_LOGGER.debug("Incoming Telnet message: %s", message)
|
|
@@ -624,10 +665,28 @@ class DenonAVRTelnetApi:
|
|
|
624
665
|
if event not in TELNET_EVENTS:
|
|
625
666
|
return
|
|
626
667
|
|
|
627
|
-
asyncio.create_task(
|
|
668
|
+
task = asyncio.create_task(
|
|
669
|
+
self._async_run_callbacks(message, event, zone, parameter)
|
|
670
|
+
)
|
|
671
|
+
self._callback_tasks.add(task)
|
|
672
|
+
task.add_done_callback(self._callback_tasks.discard)
|
|
673
|
+
|
|
674
|
+
async def _async_run_callbacks(
|
|
675
|
+
self, message: str, event: str, zone: str, parameter: str
|
|
676
|
+
) -> None:
|
|
677
|
+
"""Handle triggering the registered callbacks."""
|
|
678
|
+
for callback in self._raw_callbacks:
|
|
679
|
+
try:
|
|
680
|
+
await callback(message)
|
|
681
|
+
except Exception as err: # pylint: disable=broad-except
|
|
682
|
+
# We don't want a single bad callback to trip up the
|
|
683
|
+
# whole system and prevent further execution
|
|
684
|
+
_LOGGER.error(
|
|
685
|
+
"%s: Raw callback caused an unhandled exception %s",
|
|
686
|
+
self.host,
|
|
687
|
+
err,
|
|
688
|
+
)
|
|
628
689
|
|
|
629
|
-
async def _async_run_callbacks(self, event: str, zone: str, parameter: str) -> None:
|
|
630
|
-
"""Handle triggering the registered callbacks for the event."""
|
|
631
690
|
if event in self._callbacks.keys():
|
|
632
691
|
for callback in self._callbacks[event]:
|
|
633
692
|
try:
|
|
@@ -662,15 +721,47 @@ class DenonAVRTelnetApi:
|
|
|
662
721
|
return event
|
|
663
722
|
return ""
|
|
664
723
|
|
|
665
|
-
def
|
|
724
|
+
async def _async_send_confirmation_callback(self, message: str) -> None:
|
|
725
|
+
"""Confirm that the telnet command has been executed."""
|
|
726
|
+
if len(message) < 3:
|
|
727
|
+
return
|
|
728
|
+
command = self._send_confirmation_command
|
|
729
|
+
if self._get_event(message) == self._get_event(self._send_confirmation_command):
|
|
730
|
+
self._send_confirmation_command = ""
|
|
731
|
+
self._send_confirmation_event.set()
|
|
732
|
+
_LOGGER.debug("Command %s confirmed", command)
|
|
733
|
+
|
|
734
|
+
async def _async_send_command(self, command: str) -> None:
|
|
735
|
+
"""Send one telnet command to the receiver."""
|
|
736
|
+
async with self._send_lock:
|
|
737
|
+
self._send_confirmation_command = command
|
|
738
|
+
self._send_confirmation_event.clear()
|
|
739
|
+
if not self.connected or not self.healthy:
|
|
740
|
+
raise AvrProcessingError(
|
|
741
|
+
f"Error sending command {command}. Telnet connected: "
|
|
742
|
+
f"{self.connected}, Connection healthy: {self.healthy}"
|
|
743
|
+
)
|
|
744
|
+
self._protocol.write(f"{command}\r")
|
|
745
|
+
try:
|
|
746
|
+
await asyncio.wait_for(
|
|
747
|
+
self._send_confirmation_event.wait(),
|
|
748
|
+
self._send_confirmation_timeout,
|
|
749
|
+
)
|
|
750
|
+
except asyncio.TimeoutError:
|
|
751
|
+
_LOGGER.info("Timeout waiting for confirmation of command: %s", command)
|
|
752
|
+
finally:
|
|
753
|
+
self._send_confirmation_command = ""
|
|
754
|
+
|
|
755
|
+
async def async_send_commands(self, *commands: str) -> None:
|
|
666
756
|
"""Send telnet commands to the receiver."""
|
|
667
|
-
if not self.connected:
|
|
668
|
-
return False
|
|
669
|
-
if not self.healthy:
|
|
670
|
-
return False
|
|
671
757
|
for command in commands:
|
|
672
|
-
self.
|
|
673
|
-
|
|
758
|
+
await self._async_send_command(command)
|
|
759
|
+
|
|
760
|
+
def send_commands(self, *commands: str) -> None:
|
|
761
|
+
"""Send telnet commands to the receiver."""
|
|
762
|
+
task = asyncio.create_task(self.async_send_commands(*commands))
|
|
763
|
+
self._send_tasks.add(task)
|
|
764
|
+
task.add_done_callback(self._send_tasks.discard)
|
|
674
765
|
|
|
675
766
|
##############
|
|
676
767
|
# Properties #
|
|
@@ -8,7 +8,8 @@ This module implements the Audyssey settings of Denon AVR receivers.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import logging
|
|
11
|
-
from
|
|
11
|
+
from collections.abc import Hashable
|
|
12
|
+
from typing import List, Optional
|
|
12
13
|
|
|
13
14
|
import attr
|
|
14
15
|
|
|
@@ -16,11 +17,14 @@ from .appcommand import AppCommandCmd, AppCommandCmdParam, AppCommands
|
|
|
16
17
|
from .const import (
|
|
17
18
|
DENON_ATTR_SETATTR,
|
|
18
19
|
DYNAMIC_VOLUME_MAP,
|
|
19
|
-
|
|
20
|
+
DYNAMIC_VOLUME_MAP_LABELS_APPCOMMAND,
|
|
21
|
+
DYNAMIC_VOLUME_MAP_LABELS_TELNET,
|
|
20
22
|
MULTI_EQ_MAP,
|
|
21
|
-
|
|
23
|
+
MULTI_EQ_MAP_LABELS_APPCOMMAND,
|
|
24
|
+
MULTI_EQ_MAP_LABELS_TELNET,
|
|
22
25
|
REF_LVL_OFFSET_MAP,
|
|
23
|
-
|
|
26
|
+
REF_LVL_OFFSET_MAP_LABELS_APPCOMMAND,
|
|
27
|
+
REF_LVL_OFFSET_MAP_LABELS_TELNET,
|
|
24
28
|
)
|
|
25
29
|
from .exceptions import AvrCommandError, AvrProcessingError
|
|
26
30
|
from .foundation import DenonAVRFoundation, convert_string_int_bool
|
|
@@ -149,7 +153,9 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
149
153
|
@property
|
|
150
154
|
def reference_level_offset_setting_list(self) -> List[str]:
|
|
151
155
|
"""Return a list of available reference level offset settings."""
|
|
152
|
-
|
|
156
|
+
if self._device.telnet_available:
|
|
157
|
+
return list(REF_LVL_OFFSET_MAP_LABELS_TELNET.keys())
|
|
158
|
+
return list(REF_LVL_OFFSET_MAP_LABELS_APPCOMMAND.keys())
|
|
153
159
|
|
|
154
160
|
@property
|
|
155
161
|
def dynamic_volume(self) -> Optional[str]:
|
|
@@ -159,7 +165,9 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
159
165
|
@property
|
|
160
166
|
def dynamic_volume_setting_list(self) -> List[str]:
|
|
161
167
|
"""Return a list of available Dynamic Volume settings."""
|
|
162
|
-
|
|
168
|
+
if self._device.telnet_available:
|
|
169
|
+
return list(DYNAMIC_VOLUME_MAP_LABELS_TELNET.keys())
|
|
170
|
+
return list(DYNAMIC_VOLUME_MAP_LABELS_APPCOMMAND.keys())
|
|
163
171
|
|
|
164
172
|
@property
|
|
165
173
|
def multi_eq(self) -> Optional[str]:
|
|
@@ -169,13 +177,19 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
169
177
|
@property
|
|
170
178
|
def multi_eq_setting_list(self) -> List[str]:
|
|
171
179
|
"""Return a list of available MultiEQ settings."""
|
|
172
|
-
|
|
180
|
+
if self._device.telnet_available:
|
|
181
|
+
return list(MULTI_EQ_MAP_LABELS_TELNET.keys())
|
|
182
|
+
return list(MULTI_EQ_MAP_LABELS_APPCOMMAND.keys())
|
|
173
183
|
|
|
174
184
|
##########
|
|
175
185
|
# Setter #
|
|
176
186
|
##########
|
|
177
187
|
async def async_dynamiceq_off(self) -> None:
|
|
178
188
|
"""Turn DynamicEQ off."""
|
|
189
|
+
if self._device.telnet_available:
|
|
190
|
+
telnet_command = self._device.telnet_commands.command_dynamiceq + "OFF"
|
|
191
|
+
await self._device.telnet_api.async_send_commands(telnet_command)
|
|
192
|
+
return
|
|
179
193
|
cmd = attr.evolve(
|
|
180
194
|
AppCommands.SetAudysseyDynamicEQ,
|
|
181
195
|
param_list=(AppCommandCmdParam(name="dynamiceq", text=0),),
|
|
@@ -184,6 +198,10 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
184
198
|
|
|
185
199
|
async def async_dynamiceq_on(self) -> None:
|
|
186
200
|
"""Turn DynamicEQ on."""
|
|
201
|
+
if self._device.telnet_available:
|
|
202
|
+
telnet_command = self._device.telnet_commands.command_dynamiceq + "ON"
|
|
203
|
+
await self._device.telnet_api.async_send_commands(telnet_command)
|
|
204
|
+
return
|
|
187
205
|
cmd = attr.evolve(
|
|
188
206
|
AppCommands.SetAudysseyDynamicEQ,
|
|
189
207
|
param_list=(AppCommandCmdParam(name="dynamiceq", text=1),),
|
|
@@ -192,7 +210,15 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
192
210
|
|
|
193
211
|
async def async_set_multieq(self, value: str) -> None:
|
|
194
212
|
"""Set MultiEQ mode."""
|
|
195
|
-
|
|
213
|
+
if self._device.telnet_available:
|
|
214
|
+
setting = MULTI_EQ_MAP_LABELS_TELNET.get(value)
|
|
215
|
+
if setting is None:
|
|
216
|
+
raise AvrCommandError(f"Value {value} not known for MultiEQ")
|
|
217
|
+
telnet_command = self._device.telnet_commands.command_multieq + setting
|
|
218
|
+
await self._device.telnet_api.async_send_commands(telnet_command)
|
|
219
|
+
return
|
|
220
|
+
|
|
221
|
+
setting = MULTI_EQ_MAP_LABELS_APPCOMMAND.get(value)
|
|
196
222
|
if setting is None:
|
|
197
223
|
raise AvrCommandError(f"Value {value} not known for MultiEQ")
|
|
198
224
|
cmd = attr.evolve(
|
|
@@ -208,7 +234,17 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
208
234
|
raise AvrCommandError(
|
|
209
235
|
"Reference level could only be set when DynamicEQ is active"
|
|
210
236
|
)
|
|
211
|
-
|
|
237
|
+
if self._device.telnet_available:
|
|
238
|
+
setting = REF_LVL_OFFSET_MAP_LABELS_TELNET.get(value)
|
|
239
|
+
if setting is None:
|
|
240
|
+
raise AvrCommandError(
|
|
241
|
+
f"Value {value} not known for Reference level offset"
|
|
242
|
+
)
|
|
243
|
+
telnet_command = self._device.telnet_commands.command_reflevoffset + setting
|
|
244
|
+
await self._device.telnet_api.async_send_commands(telnet_command)
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
setting = REF_LVL_OFFSET_MAP_LABELS_APPCOMMAND.get(value)
|
|
212
248
|
if setting is None:
|
|
213
249
|
raise AvrCommandError(f"Value {value} not known for Reference level offset")
|
|
214
250
|
cmd = attr.evolve(
|
|
@@ -219,7 +255,15 @@ class DenonAVRAudyssey(DenonAVRFoundation):
|
|
|
219
255
|
|
|
220
256
|
async def async_set_dynamicvol(self, value: str) -> None:
|
|
221
257
|
"""Set Dynamic Volume."""
|
|
222
|
-
|
|
258
|
+
if self._device.telnet_available:
|
|
259
|
+
setting = DYNAMIC_VOLUME_MAP_LABELS_TELNET.get(value)
|
|
260
|
+
if setting is None:
|
|
261
|
+
raise AvrCommandError(f"Value {value} not known for Dynamic Volume")
|
|
262
|
+
telnet_command = self._device.telnet_commands.command_dynamicvol + setting
|
|
263
|
+
await self._device.telnet_api.async_send_commands(telnet_command)
|
|
264
|
+
return
|
|
265
|
+
|
|
266
|
+
setting = DYNAMIC_VOLUME_MAP_LABELS_APPCOMMAND.get(value)
|
|
223
267
|
if setting is None:
|
|
224
268
|
raise AvrCommandError(f"Value {value} not known for Dynamic Volume")
|
|
225
269
|
cmd = attr.evolve(
|
|
@@ -61,6 +61,13 @@ TelnetCommands = namedtuple(
|
|
|
61
61
|
"command_set_all_zone_stereo",
|
|
62
62
|
"command_pause",
|
|
63
63
|
"command_play",
|
|
64
|
+
"command_multieq",
|
|
65
|
+
"command_dynamiceq",
|
|
66
|
+
"command_reflevoffset",
|
|
67
|
+
"command_dynamicvol",
|
|
68
|
+
"command_tonecontrol",
|
|
69
|
+
"command_bass",
|
|
70
|
+
"command_treble",
|
|
64
71
|
],
|
|
65
72
|
)
|
|
66
73
|
|
|
@@ -186,6 +193,7 @@ SOUND_MODE_MAPPING = {
|
|
|
186
193
|
"DOLBY PL2 CINEMA",
|
|
187
194
|
"DOLBY PL2 C",
|
|
188
195
|
"DOLBY PL2 X MOVIE",
|
|
196
|
+
"DOLBY PL2 MOVIE",
|
|
189
197
|
],
|
|
190
198
|
"GAME": [
|
|
191
199
|
"PLII GAME",
|
|
@@ -193,6 +201,7 @@ SOUND_MODE_MAPPING = {
|
|
|
193
201
|
"DOLBY PL2 GAME",
|
|
194
202
|
"DOLBY PL2 G",
|
|
195
203
|
"DOLBY PL2 X GAME",
|
|
204
|
+
"DOLBY PLII GAME",
|
|
196
205
|
],
|
|
197
206
|
"AUTO": ["None"],
|
|
198
207
|
"STANDARD": ["None2"],
|
|
@@ -208,6 +217,7 @@ SOUND_MODE_MAPPING = {
|
|
|
208
217
|
"DOLBY DIGITAL",
|
|
209
218
|
"DOLBY D + DOLBY SURROUND",
|
|
210
219
|
"DOLBY D+DS",
|
|
220
|
+
"DOLBY D+ +DS",
|
|
211
221
|
"DOLBY DIGITAL +",
|
|
212
222
|
"STANDARD(DOLBY)",
|
|
213
223
|
"DOLBY SURROUND",
|
|
@@ -233,9 +243,11 @@ SOUND_MODE_MAPPING = {
|
|
|
233
243
|
"DOLBY AUDIO - DD + DSUR",
|
|
234
244
|
"DOLBY AUDIO - DD+ + NEURAL:X",
|
|
235
245
|
"DOLBY AUDIO - DD+ + DSUR",
|
|
246
|
+
"DOLBY AUDIO-DD+ +DSUR",
|
|
236
247
|
"DOLBY AUDIO - DOLBY DIGITAL",
|
|
237
248
|
"DOLBY AUDIO-DSUR",
|
|
238
249
|
"DOLBY AUDIO-DD+DSUR",
|
|
250
|
+
"DOLBY PRO LOGIC",
|
|
239
251
|
],
|
|
240
252
|
"DTS SURROUND": [
|
|
241
253
|
"DTS SURROUND",
|
|
@@ -484,6 +496,13 @@ DENONAVR_TELNET_COMMANDS = TelnetCommands(
|
|
|
484
496
|
command_set_all_zone_stereo="MN",
|
|
485
497
|
command_pause="NS9B",
|
|
486
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 ",
|
|
487
506
|
)
|
|
488
507
|
|
|
489
508
|
ZONE2_TELNET_COMMANDS = TelnetCommands(
|
|
@@ -500,6 +519,13 @@ ZONE2_TELNET_COMMANDS = TelnetCommands(
|
|
|
500
519
|
command_set_all_zone_stereo="MN",
|
|
501
520
|
command_pause="NS9B",
|
|
502
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 ",
|
|
503
529
|
)
|
|
504
530
|
|
|
505
531
|
ZONE3_TELNET_COMMANDS = TelnetCommands(
|
|
@@ -516,6 +542,13 @@ ZONE3_TELNET_COMMANDS = TelnetCommands(
|
|
|
516
542
|
command_set_all_zone_stereo="MN",
|
|
517
543
|
command_pause="NS9B",
|
|
518
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 ",
|
|
519
552
|
)
|
|
520
553
|
|
|
521
554
|
# States
|
|
@@ -546,11 +579,41 @@ APPCOMMAND_CMD_TEXT = "cmd_text"
|
|
|
546
579
|
APPCOMMAND_NAME = "name"
|
|
547
580
|
|
|
548
581
|
# Audyssey parameter
|
|
549
|
-
|
|
550
|
-
|
|
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()}
|
|
551
595
|
|
|
552
|
-
|
|
553
|
-
|
|
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
|
+
}
|
|
554
605
|
|
|
555
|
-
|
|
556
|
-
|
|
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
|
+
}
|
|
@@ -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.
|
|
@@ -85,44 +86,37 @@ def async_handle_receiver_exceptions(func: Callable[..., AnyT]) -> Callable[...,
|
|
|
85
86
|
return wrapper
|
|
86
87
|
|
|
87
88
|
|
|
88
|
-
def
|
|
89
|
+
def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
89
90
|
"""
|
|
90
|
-
Decorate a function to
|
|
91
|
+
Decorate a function to cache its results with an lru_cache of maxsize 16.
|
|
91
92
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
95
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)
|
|
96
105
|
|
|
97
106
|
@wraps(func)
|
|
98
107
|
async def wrapper(*args, **kwargs):
|
|
108
|
+
if kwargs.get("cache_id") is None:
|
|
109
|
+
kwargs["cache_id"] = time.time()
|
|
99
110
|
try:
|
|
100
|
-
return await
|
|
111
|
+
return await cached_func(*args, **kwargs)
|
|
101
112
|
except Exception as err:
|
|
102
113
|
_LOGGER.debug("Exception %s raised, clearing cache", err)
|
|
103
|
-
|
|
114
|
+
cached_func.cache_clear()
|
|
104
115
|
raise
|
|
105
116
|
|
|
106
117
|
return wrapper
|
|
107
118
|
|
|
108
119
|
|
|
109
|
-
def set_cache_id(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
|
|
110
|
-
"""
|
|
111
|
-
Decorate a function to add cache_id keyword argument if it is not present.
|
|
112
|
-
|
|
113
|
-
The function must be called with a fix cache_id keyword argument to be able
|
|
114
|
-
to get cached data. This prevents accidential caching of a function result.
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
@wraps(func)
|
|
118
|
-
def wrapper(*args, **kwargs):
|
|
119
|
-
if kwargs.get("cache_id") is None:
|
|
120
|
-
kwargs["cache_id"] = time.time()
|
|
121
|
-
return func(*args, **kwargs)
|
|
122
|
-
|
|
123
|
-
return wrapper
|
|
124
|
-
|
|
125
|
-
|
|
126
120
|
def run_async_synchronously(async_func: Coroutine) -> Callable:
|
|
127
121
|
"""
|
|
128
122
|
Decorate to run the configured asynchronous function synchronously instead.
|