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.
Files changed (219) hide show
  1. {denonavr-0.11.4 → denonavr-0.11.6}/PKG-INFO +6 -4
  2. {denonavr-0.11.4 → denonavr-0.11.6}/README.md +3 -3
  3. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/__init__.py +1 -1
  4. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/api.py +117 -26
  5. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/audyssey.py +54 -10
  6. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/const.py +69 -6
  7. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/decorators.py +19 -25
  8. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/denonavr.py +49 -6
  9. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/foundation.py +24 -12
  10. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/input.py +41 -34
  11. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/soundmode.py +14 -8
  12. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/ssdp.py +2 -2
  13. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/tonecontrol.py +83 -27
  14. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/volume.py +28 -22
  15. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/PKG-INFO +6 -4
  16. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/requires.txt +1 -0
  17. {denonavr-0.11.4 → denonavr-0.11.6}/pyproject.toml +3 -1
  18. {denonavr-0.11.4 → denonavr-0.11.6}/tests/test_denonavr.py +40 -15
  19. {denonavr-0.11.4 → denonavr-0.11.6}/LICENSE +0 -0
  20. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/appcommand.py +0 -0
  21. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr/exceptions.py +0 -0
  22. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/SOURCES.txt +0 -0
  23. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/dependency_links.txt +0 -0
  24. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/not-zip-safe +0 -0
  25. {denonavr-0.11.4 → denonavr-0.11.6}/denonavr.egg-info/top_level.txt +0 -0
  26. {denonavr-0.11.4 → denonavr-0.11.6}/setup.cfg +0 -0
  27. {denonavr-0.11.4 → denonavr-0.11.6}/tests/__init__.py +0 -0
  28. {denonavr-0.11.4 → denonavr-0.11.6}/tests/test_ssdp.py +0 -0
  29. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-AppCommand-setup-8080.xml +0 -0
  30. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-AppCommand-update-8080.xml +0 -0
  31. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AV7703-Deviceinfo-8080.xml +0 -0
  32. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-AppCommand-setup-8080.xml +0 -0
  33. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-AppCommand-update-8080.xml +0 -0
  34. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-8500H-Deviceinfo-8080.xml +0 -0
  35. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-AppCommand-setup-8080.xml +0 -0
  36. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-AppCommand-update-8080.xml +0 -0
  37. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVC-X3700H-Deviceinfo-8080.xml +0 -0
  38. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-AppCommand-setup.xml +0 -0
  39. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-AppCommand-update.xml +0 -0
  40. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-Deviceinfo.xml +0 -0
  41. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formMainZone_MainZoneXml.xml +0 -0
  42. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formMainZone_MainZoneXmlStatus.xml +0 -0
  43. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formNetAudio_StatusXml.xml +0 -0
  44. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formTuner_HdXml.xml +0 -0
  45. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formTuner_TunerXml.xml +0 -0
  46. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formZone2_Zone2XmlStatus.xml +0 -0
  47. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1713-formZone3_Zone3XmlStatus.xml +0 -0
  48. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-AppCommand-setup.xml +0 -0
  49. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-AppCommand-update.xml +0 -0
  50. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-Deviceinfo.xml +0 -0
  51. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formMainZone_MainZoneXml.xml +0 -0
  52. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formMainZone_MainZoneXmlStatus.xml +0 -0
  53. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-1912-formNetAudio_StatusXml.xml +0 -0
  54. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-AppCommand-setup.xml +0 -0
  55. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-AppCommand-update.xml +0 -0
  56. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-Deviceinfo.xml +0 -0
  57. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formMainZone_MainZoneXml.xml +0 -0
  58. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formMainZone_MainZoneXmlStatus.xml +0 -0
  59. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-2312CI-formNetAudio_StatusXml.xml +0 -0
  60. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-AppCommand-setup.xml +0 -0
  61. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-AppCommand-update.xml +0 -0
  62. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-Deviceinfo.xml +0 -0
  63. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formMainZone_MainZoneXml.xml +0 -0
  64. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formMainZone_MainZoneXmlStatus.xml +0 -0
  65. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3311CI-formNetAudio_StatusXml.xml +0 -0
  66. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-AppCommand-setup.xml +0 -0
  67. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-AppCommand-update.xml +0 -0
  68. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-Deviceinfo.xml +0 -0
  69. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formMainZone_MainZoneXml.xml +0 -0
  70. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formMainZone_MainZoneXmlStatus.xml +0 -0
  71. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formNetAudio_StatusXml.xml +0 -0
  72. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formTuner_HdXml.xml +0 -0
  73. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formTuner_TunerXml.xml +0 -0
  74. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formZone2_Zone2XmlStatus.xml +0 -0
  75. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3312-formZone3_Zone3XmlStatus.xml +0 -0
  76. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-AppCommand-setup.xml +0 -0
  77. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-AppCommand-update.xml +0 -0
  78. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-Deviceinfo.xml +0 -0
  79. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formMainZone_MainZoneXml.xml +0 -0
  80. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formMainZone_MainZoneXmlStatus.xml +0 -0
  81. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formNetAudio_StatusXml.xml +0 -0
  82. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formTuner_HdXml.xml +0 -0
  83. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formTuner_TunerXml.xml +0 -0
  84. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formZone2_Zone2XmlStatus.xml +0 -0
  85. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-3313-formZone3_Zone3XmlStatus.xml +0 -0
  86. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-AppCommand-setup.xml +0 -0
  87. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-AppCommand-update.xml +0 -0
  88. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-Deviceinfo.xml +0 -0
  89. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formMainZone_MainZoneXml.xml +0 -0
  90. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formMainZone_MainZoneXmlStatus.xml +0 -0
  91. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formNetAudio_StatusXml.xml +0 -0
  92. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formTuner_HdXml.xml +0 -0
  93. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formTuner_TunerXml.xml +0 -0
  94. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formZone2_Zone2XmlStatus.xml +0 -0
  95. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-4810-formZone3_Zone3XmlStatus.xml +0 -0
  96. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-AppCommand-setup.xml +0 -0
  97. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-AppCommand-update.xml +0 -0
  98. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-Deviceinfo.xml +0 -0
  99. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formMainZone_MainZoneXml.xml +0 -0
  100. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  101. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formNetAudio_StatusXml.xml +0 -0
  102. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formTuner_HdXml.xml +0 -0
  103. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formTuner_TunerXml.xml +0 -0
  104. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formZone2_Zone2XmlStatus.xml +0 -0
  105. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1100W-formZone3_Zone3XmlStatus.xml +0 -0
  106. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X1600H_upnp.xml +0 -0
  107. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-AppCommand-setup.xml +0 -0
  108. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-AppCommand-update.xml +0 -0
  109. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-Deviceinfo.xml +0 -0
  110. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXml.xml +0 -0
  111. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  112. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-2-formNetAudio_StatusXml.xml +0 -0
  113. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-AppCommand-setup.xml +0 -0
  114. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-AppCommand-update.xml +0 -0
  115. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-Deviceinfo.xml +0 -0
  116. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formMainZone_MainZoneXml.xml +0 -0
  117. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formMainZone_MainZoneXmlStatus.xml +0 -0
  118. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formNetAudio_StatusXml.xml +0 -0
  119. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formTuner_HdXml.xml +0 -0
  120. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formTuner_TunerXml.xml +0 -0
  121. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formZone2_Zone2XmlStatus.xml +0 -0
  122. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2000-formZone3_Zone3XmlStatus.xml +0 -0
  123. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-AppCommand-setup.xml +0 -0
  124. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-AppCommand-update.xml +0 -0
  125. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-Deviceinfo.xml +0 -0
  126. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXml.xml +0 -0
  127. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  128. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-2-formNetAudio_StatusXml.xml +0 -0
  129. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-AppCommand-setup.xml +0 -0
  130. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-AppCommand-update.xml +0 -0
  131. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formMainZone_MainZoneXml.xml +0 -0
  132. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  133. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X2100W-formNetAudio_StatusXml.xml +0 -0
  134. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-AppCommand-setup.xml +0 -0
  135. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-AppCommand-update.xml +0 -0
  136. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-Deviceinfo.xml +0 -0
  137. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formMainZone_MainZoneXml.xml +0 -0
  138. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formMainZone_MainZoneXmlStatus.xml +0 -0
  139. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formNetAudio_StatusXml.xml +0 -0
  140. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formTuner_HdXml.xml +0 -0
  141. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formTuner_TunerXml.xml +0 -0
  142. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formZone2_Zone2XmlStatus.xml +0 -0
  143. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4000-formZone3_Zone3XmlStatus.xml +0 -0
  144. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-AppCommand-setup.xml +0 -0
  145. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-AppCommand-update.xml +0 -0
  146. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-Deviceinfo.xml +0 -0
  147. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formMainZone_MainZoneXml.xml +0 -0
  148. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  149. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4100W-formNetAudio_StatusXml.xml +0 -0
  150. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-AppCommand-setup-8080.xml +0 -0
  151. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-AppCommand-update-8080.xml +0 -0
  152. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/AVR-X4300H-Deviceinfo-8080.xml +0 -0
  153. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-AppCommand-setup.xml +0 -0
  154. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-AppCommand-update.xml +0 -0
  155. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-Deviceinfo.xml +0 -0
  156. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formMainZone_MainZoneXml.xml +0 -0
  157. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  158. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formNetAudio_StatusXml.xml +0 -0
  159. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formTuner_HdXml.xml +0 -0
  160. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-2-formTuner_TunerXml.xml +0 -0
  161. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-AppCommand-setup.xml +0 -0
  162. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-AppCommand-update.xml +0 -0
  163. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-Deviceinfo.xml +0 -0
  164. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formMainZone_MainZoneXml.xml +0 -0
  165. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formMainZone_MainZoneXmlStatus.xml +0 -0
  166. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formNetAudio_StatusXml.xml +0 -0
  167. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formTuner_HdXml.xml +0 -0
  168. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR510-formTuner_TunerXml.xml +0 -0
  169. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-AppCommand-setup.xml +0 -0
  170. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-AppCommand-update.xml +0 -0
  171. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-Deviceinfo.xml +0 -0
  172. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formMainZone_MainZoneXml.xml +0 -0
  173. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formMainZone_MainZoneXmlStatus.xml +0 -0
  174. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formNetAudio_StatusXml.xml +0 -0
  175. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formTuner_HdXml.xml +0 -0
  176. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formTuner_TunerXml.xml +0 -0
  177. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formZone2_Zone2XmlStatus.xml +0 -0
  178. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-CR603-formZone3_Zone3XmlStatus.xml +0 -0
  179. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-AppCommand-setup.xml +0 -0
  180. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-AppCommand-update.xml +0 -0
  181. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-Deviceinfo.xml +0 -0
  182. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formMainZone_MainZoneXml.xml +0 -0
  183. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formMainZone_MainZoneXmlStatus.xml +0 -0
  184. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formNetAudio_StatusXml.xml +0 -0
  185. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/M-RC610-formTuner_TunerXml.xml +0 -0
  186. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-AppCommand-setup.xml +0 -0
  187. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-AppCommand-update.xml +0 -0
  188. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-Deviceinfo.xml +0 -0
  189. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formMainZone_MainZoneXml.xml +0 -0
  190. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formMainZone_MainZoneXmlStatus.xml +0 -0
  191. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formNetAudio_StatusXml.xml +0 -0
  192. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formTuner_HdXml.xml +0 -0
  193. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formTuner_TunerXml.xml +0 -0
  194. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formZone2_Zone2XmlStatus.xml +0 -0
  195. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1604-formZone3_Zone3XmlStatus.xml +0 -0
  196. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-AppCommand-setup-8080.xml +0 -0
  197. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-AppCommand-update-8080.xml +0 -0
  198. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/NR1609-Deviceinfo-8080.xml +0 -0
  199. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-AppCommand-setup.xml +0 -0
  200. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-AppCommand-update.xml +0 -0
  201. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-Deviceinfo.xml +0 -0
  202. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formMainZone_MainZoneXml.xml +0 -0
  203. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formMainZone_MainZoneXmlStatus.xml +0 -0
  204. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formNetAudio_StatusXml.xml +0 -0
  205. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formTuner_HdXml.xml +0 -0
  206. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR5008-formTuner_TunerXml.xml +0 -0
  207. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-AppCommand-setup.xml +0 -0
  208. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-AppCommand-update.xml +0 -0
  209. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-Deviceinfo.xml +0 -0
  210. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formMainZone_MainZoneXml.xml +0 -0
  211. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formMainZone_MainZoneXmlStatus.xml +0 -0
  212. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formNetAudio_StatusXml.xml +0 -0
  213. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formTuner_HdXml.xml +0 -0
  214. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formTuner_TunerXml.xml +0 -0
  215. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formZone2_Zone2XmlStatus.xml +0 -0
  216. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6011-formZone3_Zone3XmlStatus.xml +0 -0
  217. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6012-AppCommand-setup-8080.xml +0 -0
  218. {denonavr-0.11.4 → denonavr-0.11.6}/tests/xml/SR6012-AppCommand-update-8080.xml +0 -0
  219. {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.4
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 availlable 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.
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.async_mute_on(True)
133
- >>> await d.async_mute_off(False)
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 availlable 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.
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.async_mute_on(True)
92
- >>> await d.async_mute_off(False)
91
+ >>> await d.async_mute(True)
92
+ >>> await d.async_mute(False)
93
93
  ```
94
94
 
95
95
  ### Other methods
@@ -19,7 +19,7 @@ from .ssdp import async_identify_denonavr_receivers
19
19
  logging.getLogger(__name__).addHandler(logging.NullHandler())
20
20
 
21
21
  __title__ = "denonavr"
22
- __version__ = "0.11.4"
22
+ __version__ = "0.11.6"
23
23
 
24
24
 
25
25
  async def async_discover():
@@ -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
- @set_cache_id
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
- @set_cache_id
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.AsyncCLient getter is used."""
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
- _callbacks: Dict[str, Callable] = attr.ib(
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
- self._protocol.write("PW?\r")
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(self._async_run_callbacks(event, zone, parameter))
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 send_commands(self, *commands: str) -> bool:
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._protocol.write(f"{command}\r")
673
- return True
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 typing import Hashable, List, Optional
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
- DYNAMIC_VOLUME_MAP_LABELS,
20
+ DYNAMIC_VOLUME_MAP_LABELS_APPCOMMAND,
21
+ DYNAMIC_VOLUME_MAP_LABELS_TELNET,
20
22
  MULTI_EQ_MAP,
21
- MULTI_EQ_MAP_LABELS,
23
+ MULTI_EQ_MAP_LABELS_APPCOMMAND,
24
+ MULTI_EQ_MAP_LABELS_TELNET,
22
25
  REF_LVL_OFFSET_MAP,
23
- REF_LVL_OFFSET_MAP_LABELS,
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
- return list(REF_LVL_OFFSET_MAP_LABELS.keys())
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
- return list(DYNAMIC_VOLUME_MAP_LABELS.keys())
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
- return list(MULTI_EQ_MAP_LABELS.keys())
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
- setting = MULTI_EQ_MAP_LABELS.get(value)
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
- setting = REF_LVL_OFFSET_MAP_LABELS.get(value)
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
- setting = DYNAMIC_VOLUME_MAP_LABELS.get(value)
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
- MULTI_EQ_MAP = {"0": "Off", "1": "Flat", "2": "L/R Bypass", "3": "Reference"}
550
- MULTI_EQ_MAP_LABELS = {(value, key) for key, value in MULTI_EQ_MAP.items()}
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
- REF_LVL_OFFSET_MAP = {"0": "0dB", "1": "+5dB", "2": "+10dB", "3": "+15dB"}
553
- REF_LVL_OFFSET_MAP_LABELS = {(value, key) for key, value in REF_LVL_OFFSET_MAP.items()}
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
- DYNAMIC_VOLUME_MAP = {"0": "Off", "1": "Light", "2": "Medium", "3": "Heavy"}
556
- DYNAMIC_VOLUME_MAP_LABELS = {(value, key) for key, value in DYNAMIC_VOLUME_MAP.items()}
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 an Denon AVR endpoint asynchronously.
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 cache_clear_on_exception(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
89
+ def cache_result(func: Callable[..., AnyT]) -> Callable[..., AnyT]:
89
90
  """
90
- Decorate a function to clear lru_cache if an exception occurs.
91
+ Decorate a function to cache its results with an lru_cache of maxsize 16.
91
92
 
92
- The decorator must be placed right before the @lru_cache decorator.
93
- It prevents memory leaks in home-assistant when receiver instances are
94
- created and deleted right away in case the device is offline on setup.
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 func(*args, **kwargs)
111
+ return await cached_func(*args, **kwargs)
101
112
  except Exception as err:
102
113
  _LOGGER.debug("Exception %s raised, clearing cache", err)
103
- func.cache_clear()
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.