denonavr 1.0.0__tar.gz → 1.1.0__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 (284) hide show
  1. {denonavr-1.0.0 → denonavr-1.1.0}/PKG-INFO +5 -21
  2. {denonavr-1.0.0 → denonavr-1.1.0}/README.md +1 -17
  3. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/__init__.py +1 -1
  4. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/api.py +181 -60
  5. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/audyssey.py +105 -0
  6. denonavr-1.1.0/denonavr/const.py +1606 -0
  7. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/decorators.py +5 -32
  8. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/denonavr.py +500 -3
  9. denonavr-1.1.0/denonavr/dirac.py +89 -0
  10. denonavr-1.1.0/denonavr/foundation.py +2019 -0
  11. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/input.py +44 -3
  12. denonavr-1.1.0/denonavr/soundmode.py +1242 -0
  13. denonavr-1.1.0/denonavr/volume.py +629 -0
  14. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/PKG-INFO +5 -21
  15. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/SOURCES.txt +7 -0
  16. {denonavr-1.0.0 → denonavr-1.1.0}/pyproject.toml +2 -3
  17. denonavr-1.1.0/tests/test_const.py +57 -0
  18. {denonavr-1.0.0 → denonavr-1.1.0}/tests/test_denonavr.py +29 -21
  19. denonavr-1.1.0/tests/xml/AVC-A10H-AppCommand-setup-8080.xml +6 -0
  20. denonavr-1.1.0/tests/xml/AVC-A10H-AppCommand-update-8080.xml +237 -0
  21. denonavr-1.1.0/tests/xml/AVC-A10H-AppCommand-update-soundmode-8080.xml +6 -0
  22. denonavr-1.1.0/tests/xml/AVC-A10H-AppCommand-update-tonecontrol-8080.xml +11 -0
  23. denonavr-1.1.0/tests/xml/AVC-A10H-Deviceinfo-8080.xml +3474 -0
  24. denonavr-1.0.0/denonavr/const.py +0 -728
  25. denonavr-1.0.0/denonavr/foundation.py +0 -849
  26. denonavr-1.0.0/denonavr/soundmode.py +0 -333
  27. denonavr-1.0.0/denonavr/volume.py +0 -218
  28. {denonavr-1.0.0 → denonavr-1.1.0}/LICENSE +0 -0
  29. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/appcommand.py +0 -0
  30. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/exceptions.py +0 -0
  31. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/ssdp.py +0 -0
  32. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr/tonecontrol.py +0 -0
  33. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/dependency_links.txt +0 -0
  34. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/not-zip-safe +0 -0
  35. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/requires.txt +0 -0
  36. {denonavr-1.0.0 → denonavr-1.1.0}/denonavr.egg-info/top_level.txt +0 -0
  37. {denonavr-1.0.0 → denonavr-1.1.0}/setup.cfg +0 -0
  38. {denonavr-1.0.0 → denonavr-1.1.0}/tests/__init__.py +0 -0
  39. {denonavr-1.0.0 → denonavr-1.1.0}/tests/test_ssdp.py +0 -0
  40. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AV7703-AppCommand-setup-8080.xml +0 -0
  41. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AV7703-AppCommand-update-8080.xml +0 -0
  42. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AV7703-AppCommand-update-soundmode-8080.xml +0 -0
  43. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AV7703-AppCommand-update-tonecontrol-8080.xml +0 -0
  44. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AV7703-Deviceinfo-8080.xml +0 -0
  45. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-8500H-AppCommand-setup-8080.xml +0 -0
  46. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-8500H-AppCommand-update-8080.xml +0 -0
  47. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-8500H-AppCommand-update-soundmode-8080.xml +0 -0
  48. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-8500H-AppCommand-update-tonecontrol-8080.xml +0 -0
  49. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-8500H-Deviceinfo-8080.xml +0 -0
  50. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-X3700H-AppCommand-setup-8080.xml +0 -0
  51. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-X3700H-AppCommand-update-8080.xml +0 -0
  52. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-X3700H-AppCommand-update-soundmode-8080.xml +0 -0
  53. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-X3700H-AppCommand-update-tonecontrol-8080.xml +0 -0
  54. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVC-X3700H-Deviceinfo-8080.xml +0 -0
  55. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-AppCommand-setup.xml +0 -0
  56. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-AppCommand-update-soundmode.xml +0 -0
  57. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-AppCommand-update-tonecontrol.xml +0 -0
  58. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-AppCommand-update.xml +0 -0
  59. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-Deviceinfo.xml +0 -0
  60. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formMainZone_MainZoneXml.xml +0 -0
  61. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formMainZone_MainZoneXmlStatus.xml +0 -0
  62. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formNetAudio_StatusXml.xml +0 -0
  63. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formTuner_HdXml.xml +0 -0
  64. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formTuner_TunerXml.xml +0 -0
  65. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formZone2_Zone2XmlStatus.xml +0 -0
  66. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1713-formZone3_Zone3XmlStatus.xml +0 -0
  67. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-AppCommand-setup.xml +0 -0
  68. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-AppCommand-update-soundmode.xml +0 -0
  69. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-AppCommand-update-tonecontrol.xml +0 -0
  70. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-AppCommand-update.xml +0 -0
  71. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-Deviceinfo.xml +0 -0
  72. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-formMainZone_MainZoneXml.xml +0 -0
  73. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-formMainZone_MainZoneXmlStatus.xml +0 -0
  74. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-1912-formNetAudio_StatusXml.xml +0 -0
  75. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-AppCommand-setup.xml +0 -0
  76. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-AppCommand-update-soundmode.xml +0 -0
  77. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-AppCommand-update-tonecontrol.xml +0 -0
  78. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-AppCommand-update.xml +0 -0
  79. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-Deviceinfo.xml +0 -0
  80. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-formMainZone_MainZoneXml.xml +0 -0
  81. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-formMainZone_MainZoneXmlStatus.xml +0 -0
  82. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-2312CI-formNetAudio_StatusXml.xml +0 -0
  83. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-AppCommand-setup.xml +0 -0
  84. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-AppCommand-update-soundmode.xml +0 -0
  85. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-AppCommand-update-tonecontrol.xml +0 -0
  86. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-AppCommand-update.xml +0 -0
  87. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-Deviceinfo.xml +0 -0
  88. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-formMainZone_MainZoneXml.xml +0 -0
  89. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-formMainZone_MainZoneXmlStatus.xml +0 -0
  90. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3311CI-formNetAudio_StatusXml.xml +0 -0
  91. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-AppCommand-setup.xml +0 -0
  92. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-AppCommand-update-soundmode.xml +0 -0
  93. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-AppCommand-update-tonecontrol.xml +0 -0
  94. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-AppCommand-update.xml +0 -0
  95. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-Deviceinfo.xml +0 -0
  96. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formMainZone_MainZoneXml.xml +0 -0
  97. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formMainZone_MainZoneXmlStatus.xml +0 -0
  98. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formNetAudio_StatusXml.xml +0 -0
  99. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formTuner_HdXml.xml +0 -0
  100. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formTuner_TunerXml.xml +0 -0
  101. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formZone2_Zone2XmlStatus.xml +0 -0
  102. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3312-formZone3_Zone3XmlStatus.xml +0 -0
  103. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-AppCommand-setup.xml +0 -0
  104. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-AppCommand-update-soundmode.xml +0 -0
  105. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-AppCommand-update-tonecontrol.xml +0 -0
  106. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-AppCommand-update.xml +0 -0
  107. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-Deviceinfo.xml +0 -0
  108. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formMainZone_MainZoneXml.xml +0 -0
  109. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formMainZone_MainZoneXmlStatus.xml +0 -0
  110. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formNetAudio_StatusXml.xml +0 -0
  111. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formTuner_HdXml.xml +0 -0
  112. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formTuner_TunerXml.xml +0 -0
  113. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formZone2_Zone2XmlStatus.xml +0 -0
  114. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-3313-formZone3_Zone3XmlStatus.xml +0 -0
  115. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-AppCommand-setup.xml +0 -0
  116. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-AppCommand-update-soundmode.xml +0 -0
  117. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-AppCommand-update-tonecontrol.xml +0 -0
  118. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-AppCommand-update.xml +0 -0
  119. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-Deviceinfo.xml +0 -0
  120. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formMainZone_MainZoneXml.xml +0 -0
  121. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formMainZone_MainZoneXmlStatus.xml +0 -0
  122. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formNetAudio_StatusXml.xml +0 -0
  123. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formTuner_HdXml.xml +0 -0
  124. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formTuner_TunerXml.xml +0 -0
  125. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formZone2_Zone2XmlStatus.xml +0 -0
  126. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-4810-formZone3_Zone3XmlStatus.xml +0 -0
  127. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-AppCommand-setup.xml +0 -0
  128. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-AppCommand-update-soundmode.xml +0 -0
  129. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-AppCommand-update-tonecontrol.xml +0 -0
  130. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-AppCommand-update.xml +0 -0
  131. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-Deviceinfo.xml +0 -0
  132. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formMainZone_MainZoneXml.xml +0 -0
  133. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  134. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formNetAudio_StatusXml.xml +0 -0
  135. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formTuner_HdXml.xml +0 -0
  136. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formTuner_TunerXml.xml +0 -0
  137. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formZone2_Zone2XmlStatus.xml +0 -0
  138. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1100W-formZone3_Zone3XmlStatus.xml +0 -0
  139. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X1600H_upnp.xml +0 -0
  140. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-AppCommand-setup.xml +0 -0
  141. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-AppCommand-update-soundmode.xml +0 -0
  142. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-AppCommand-update-tonecontrol.xml +0 -0
  143. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-AppCommand-update.xml +0 -0
  144. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-Deviceinfo.xml +0 -0
  145. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXml.xml +0 -0
  146. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  147. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-2-formNetAudio_StatusXml.xml +0 -0
  148. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-AppCommand-setup.xml +0 -0
  149. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-AppCommand-update-soundmode.xml +0 -0
  150. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-AppCommand-update-tonecontrol.xml +0 -0
  151. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-AppCommand-update.xml +0 -0
  152. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-Deviceinfo.xml +0 -0
  153. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formMainZone_MainZoneXml.xml +0 -0
  154. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formMainZone_MainZoneXmlStatus.xml +0 -0
  155. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formNetAudio_StatusXml.xml +0 -0
  156. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formTuner_HdXml.xml +0 -0
  157. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formTuner_TunerXml.xml +0 -0
  158. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formZone2_Zone2XmlStatus.xml +0 -0
  159. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2000-formZone3_Zone3XmlStatus.xml +0 -0
  160. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-AppCommand-setup.xml +0 -0
  161. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-AppCommand-update-soundmode.xml +0 -0
  162. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-AppCommand-update-tonecontrol.xml +0 -0
  163. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-AppCommand-update.xml +0 -0
  164. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-Deviceinfo.xml +0 -0
  165. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXml.xml +0 -0
  166. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  167. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-2-formNetAudio_StatusXml.xml +0 -0
  168. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-AppCommand-setup.xml +0 -0
  169. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-AppCommand-update-soundmode.xml +0 -0
  170. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-AppCommand-update-tonecontrol.xml +0 -0
  171. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-AppCommand-update.xml +0 -0
  172. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-formMainZone_MainZoneXml.xml +0 -0
  173. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  174. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X2100W-formNetAudio_StatusXml.xml +0 -0
  175. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-AppCommand-setup.xml +0 -0
  176. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-AppCommand-update-soundmode.xml +0 -0
  177. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-AppCommand-update-tonecontrol.xml +0 -0
  178. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-AppCommand-update.xml +0 -0
  179. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-Deviceinfo.xml +0 -0
  180. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formMainZone_MainZoneXml.xml +0 -0
  181. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formMainZone_MainZoneXmlStatus.xml +0 -0
  182. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formNetAudio_StatusXml.xml +0 -0
  183. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formTuner_HdXml.xml +0 -0
  184. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formTuner_TunerXml.xml +0 -0
  185. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formZone2_Zone2XmlStatus.xml +0 -0
  186. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4000-formZone3_Zone3XmlStatus.xml +0 -0
  187. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-AppCommand-setup.xml +0 -0
  188. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-AppCommand-update-soundmode.xml +0 -0
  189. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-AppCommand-update-tonecontrol.xml +0 -0
  190. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-AppCommand-update.xml +0 -0
  191. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-Deviceinfo.xml +0 -0
  192. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-formMainZone_MainZoneXml.xml +0 -0
  193. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-formMainZone_MainZoneXmlStatus.xml +0 -0
  194. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4100W-formNetAudio_StatusXml.xml +0 -0
  195. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4300H-AppCommand-setup-8080.xml +0 -0
  196. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4300H-AppCommand-update-8080.xml +0 -0
  197. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4300H-AppCommand-update-soundmode-8080.xml +0 -0
  198. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4300H-AppCommand-update-tonecontrol-8080.xml +0 -0
  199. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/AVR-X4300H-Deviceinfo-8080.xml +0 -0
  200. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-AppCommand-setup.xml +0 -0
  201. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-AppCommand-update-soundmode.xml +0 -0
  202. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-AppCommand-update-tonecontrol.xml +0 -0
  203. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-AppCommand-update.xml +0 -0
  204. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-Deviceinfo.xml +0 -0
  205. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-formMainZone_MainZoneXml.xml +0 -0
  206. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-formMainZone_MainZoneXmlStatus.xml +0 -0
  207. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-formNetAudio_StatusXml.xml +0 -0
  208. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-formTuner_HdXml.xml +0 -0
  209. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-2-formTuner_TunerXml.xml +0 -0
  210. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-AppCommand-setup.xml +0 -0
  211. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-AppCommand-update-soundmode.xml +0 -0
  212. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-AppCommand-update-tonecontrol.xml +0 -0
  213. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-AppCommand-update.xml +0 -0
  214. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-Deviceinfo.xml +0 -0
  215. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-formMainZone_MainZoneXml.xml +0 -0
  216. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-formMainZone_MainZoneXmlStatus.xml +0 -0
  217. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-formNetAudio_StatusXml.xml +0 -0
  218. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-formTuner_HdXml.xml +0 -0
  219. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR510-formTuner_TunerXml.xml +0 -0
  220. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-AppCommand-setup.xml +0 -0
  221. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-AppCommand-update-soundmode.xml +0 -0
  222. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-AppCommand-update-tonecontrol.xml +0 -0
  223. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-AppCommand-update.xml +0 -0
  224. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-Deviceinfo.xml +0 -0
  225. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formMainZone_MainZoneXml.xml +0 -0
  226. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formMainZone_MainZoneXmlStatus.xml +0 -0
  227. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formNetAudio_StatusXml.xml +0 -0
  228. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formTuner_HdXml.xml +0 -0
  229. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formTuner_TunerXml.xml +0 -0
  230. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formZone2_Zone2XmlStatus.xml +0 -0
  231. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-CR603-formZone3_Zone3XmlStatus.xml +0 -0
  232. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-AppCommand-setup.xml +0 -0
  233. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-AppCommand-update-soundmode.xml +0 -0
  234. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-AppCommand-update-tonecontrol.xml +0 -0
  235. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-AppCommand-update.xml +0 -0
  236. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-Deviceinfo.xml +0 -0
  237. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-formMainZone_MainZoneXml.xml +0 -0
  238. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-formMainZone_MainZoneXmlStatus.xml +0 -0
  239. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-formNetAudio_StatusXml.xml +0 -0
  240. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/M-RC610-formTuner_TunerXml.xml +0 -0
  241. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-AppCommand-setup.xml +0 -0
  242. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-AppCommand-update-soundmode.xml +0 -0
  243. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-AppCommand-update-tonecontrol.xml +0 -0
  244. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-AppCommand-update.xml +0 -0
  245. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-Deviceinfo.xml +0 -0
  246. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formMainZone_MainZoneXml.xml +0 -0
  247. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formMainZone_MainZoneXmlStatus.xml +0 -0
  248. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formNetAudio_StatusXml.xml +0 -0
  249. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formTuner_HdXml.xml +0 -0
  250. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formTuner_TunerXml.xml +0 -0
  251. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formZone2_Zone2XmlStatus.xml +0 -0
  252. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1604-formZone3_Zone3XmlStatus.xml +0 -0
  253. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1609-AppCommand-setup-8080.xml +0 -0
  254. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1609-AppCommand-update-8080.xml +0 -0
  255. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1609-AppCommand-update-soundmode-8080.xml +0 -0
  256. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1609-AppCommand-update-tonecontrol-8080.xml +0 -0
  257. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/NR1609-Deviceinfo-8080.xml +0 -0
  258. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-AppCommand-setup.xml +0 -0
  259. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-AppCommand-update-soundmode.xml +0 -0
  260. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-AppCommand-update-tonecontrol.xml +0 -0
  261. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-AppCommand-update.xml +0 -0
  262. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-Deviceinfo.xml +0 -0
  263. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-formMainZone_MainZoneXml.xml +0 -0
  264. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-formMainZone_MainZoneXmlStatus.xml +0 -0
  265. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-formNetAudio_StatusXml.xml +0 -0
  266. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-formTuner_HdXml.xml +0 -0
  267. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR5008-formTuner_TunerXml.xml +0 -0
  268. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-AppCommand-setup.xml +0 -0
  269. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-AppCommand-update-soundmode.xml +0 -0
  270. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-AppCommand-update-tonecontrol.xml +0 -0
  271. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-AppCommand-update.xml +0 -0
  272. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-Deviceinfo.xml +0 -0
  273. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formMainZone_MainZoneXml.xml +0 -0
  274. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formMainZone_MainZoneXmlStatus.xml +0 -0
  275. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formNetAudio_StatusXml.xml +0 -0
  276. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formTuner_HdXml.xml +0 -0
  277. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formTuner_TunerXml.xml +0 -0
  278. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formZone2_Zone2XmlStatus.xml +0 -0
  279. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6011-formZone3_Zone3XmlStatus.xml +0 -0
  280. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6012-AppCommand-setup-8080.xml +0 -0
  281. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6012-AppCommand-update-8080.xml +0 -0
  282. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6012-AppCommand-update-soundmode-8080.xml +0 -0
  283. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6012-AppCommand-update-tonecontrol-8080.xml +0 -0
  284. {denonavr-1.0.0 → denonavr-1.1.0}/tests/xml/SR6012-Deviceinfo-8080.xml +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: denonavr
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: Automation Library for Denon AVR receivers
5
5
  Author-email: Oliver Goetz <scarface@mywoh.de>
6
6
  License: MIT
@@ -14,14 +14,13 @@ Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Topic :: Software Development :: Libraries
16
16
  Classifier: Topic :: Home Automation
17
- Classifier: Programming Language :: Python :: 3.7
18
17
  Classifier: Programming Language :: Python :: 3.8
19
18
  Classifier: Programming Language :: Python :: 3.9
20
19
  Classifier: Programming Language :: Python :: 3.10
21
20
  Classifier: Programming Language :: Python :: 3.11
22
21
  Classifier: Programming Language :: Python :: 3.12
23
22
  Classifier: Programming Language :: Python :: 3.13
24
- Requires-Python: >=3.7
23
+ Requires-Python: >=3.8
25
24
  Description-Content-Type: text/markdown; charset=UTF-8
26
25
  License-File: LICENSE
27
26
  Requires-Dist: asyncstdlib>=3.10.2
@@ -41,6 +40,7 @@ Requires-Dist: pytest-asyncio; extra == "testing"
41
40
  Requires-Dist: pytest-httpx; extra == "testing"
42
41
  Requires-Dist: flake8-docstrings; extra == "testing"
43
42
  Requires-Dist: flake8; extra == "testing"
43
+ Dynamic: license-file
44
44
 
45
45
  # denonavr
46
46
  [![Release](https://img.shields.io/github/v/release/ol-iver/denonavr?sort=semver)](https://github.com/ol-iver/denonavr/releases/latest)
@@ -132,27 +132,11 @@ Other `async` methods available include:
132
132
  * `d.async_set_volume(50)`
133
133
 
134
134
  ## Collection of HTTP calls
135
- For a collection of HTTP calls for Denon receivers please have a look at the `doc` folder.
135
+ For a collection of HTTP calls for Denon receivers please have a look at the [doc folder](doc/XML_data_dump.txt).
136
136
 
137
137
  ## License
138
138
  MIT
139
139
 
140
- ## Author
141
- @ol-iver: https://github.com/ol-iver
142
-
143
- ## Contributors
144
- @soldag: https://github.com/soldag
145
- @shapiromatron: https://github.com/shapiromatron
146
- @glance-: https://github.com/glance-
147
- @p3dda: https://github.com/p3dda
148
- @russel: https://github.com/russell
149
- @starkillerOG: https://github.com/starkillerOG
150
- @andrewsayre: https://github.com/andrewsayre
151
- @JPHutchins: https://github.com/JPHutchins
152
- @MarBra: https://github.com/MarBra
153
- @dcmeglio: https://github.com/dcmeglio
154
- @bdraco: https://github.com/bdraco
155
-
156
140
  ## Users
157
141
  Home Assistant: https://github.com/home-assistant/home-assistant/
158
142
  denonavr-cli: https://pypi.org/project/denonavr-cli/
@@ -88,27 +88,11 @@ Other `async` methods available include:
88
88
  * `d.async_set_volume(50)`
89
89
 
90
90
  ## Collection of HTTP calls
91
- For a collection of HTTP calls for Denon receivers please have a look at the `doc` folder.
91
+ For a collection of HTTP calls for Denon receivers please have a look at the [doc folder](doc/XML_data_dump.txt).
92
92
 
93
93
  ## License
94
94
  MIT
95
95
 
96
- ## Author
97
- @ol-iver: https://github.com/ol-iver
98
-
99
- ## Contributors
100
- @soldag: https://github.com/soldag
101
- @shapiromatron: https://github.com/shapiromatron
102
- @glance-: https://github.com/glance-
103
- @p3dda: https://github.com/p3dda
104
- @russel: https://github.com/russell
105
- @starkillerOG: https://github.com/starkillerOG
106
- @andrewsayre: https://github.com/andrewsayre
107
- @JPHutchins: https://github.com/JPHutchins
108
- @MarBra: https://github.com/MarBra
109
- @dcmeglio: https://github.com/dcmeglio
110
- @bdraco: https://github.com/bdraco
111
-
112
96
  ## Users
113
97
  Home Assistant: https://github.com/home-assistant/home-assistant/
114
98
  denonavr-cli: https://pypi.org/project/denonavr-cli/
@@ -17,7 +17,7 @@ from .ssdp import async_identify_denonavr_receivers
17
17
  logging.getLogger(__name__).addHandler(logging.NullHandler())
18
18
 
19
19
  __title__ = "denonavr"
20
- __version__ = "1.0.0"
20
+ __version__ = "1.1.0"
21
21
 
22
22
 
23
23
  async def async_discover():
@@ -31,7 +31,8 @@ from typing import (
31
31
 
32
32
  import attr
33
33
  import httpx
34
- from defusedxml.ElementTree import fromstring
34
+ from defusedxml import DefusedXmlException
35
+ from defusedxml.ElementTree import ParseError, fromstring
35
36
 
36
37
  from .appcommand import AppCommandCmd
37
38
  from .const import (
@@ -83,16 +84,86 @@ def telnet_event_map_factory() -> Dict[str, List]:
83
84
  return dict(event_map)
84
85
 
85
86
 
86
- @attr.s(auto_attribs=True, hash=False, on_setattr=DENON_ATTR_SETATTR)
87
+ @attr.s(auto_attribs=True, hash=False)
88
+ class HTTPXAsyncClient:
89
+ """Perform cached HTTP calls with httpx.AsyncClient."""
90
+
91
+ client_getter: Callable[[], httpx.AsyncClient] = attr.ib(
92
+ validator=attr.validators.is_callable(),
93
+ default=get_default_async_client,
94
+ init=False,
95
+ )
96
+
97
+ def __hash__(self) -> int:
98
+ """Hash the class using its ID that caching works."""
99
+ return id(self)
100
+
101
+ @cache_result
102
+ @async_handle_receiver_exceptions
103
+ async def async_get(
104
+ self,
105
+ url: str,
106
+ timeout: float,
107
+ read_timeout: float,
108
+ *,
109
+ cache_id: Hashable = None,
110
+ ) -> httpx.Response:
111
+ """Call GET endpoint of Denon AVR receiver asynchronously."""
112
+ client = self.client_getter()
113
+ try:
114
+ res = await client.get(
115
+ url, timeout=httpx.Timeout(timeout, read=read_timeout)
116
+ )
117
+ res.raise_for_status()
118
+ finally:
119
+ # Close the default AsyncClient but keep custom clients open
120
+ if self.is_default_async_client():
121
+ await client.aclose()
122
+
123
+ return res
124
+
125
+ @cache_result
126
+ @async_handle_receiver_exceptions
127
+ async def async_post(
128
+ self,
129
+ url: str,
130
+ timeout: float,
131
+ read_timeout: float,
132
+ *,
133
+ content: Optional[bytes] = None,
134
+ data: Optional[Dict] = None,
135
+ cache_id: Hashable = None,
136
+ ) -> httpx.Response:
137
+ """Call GET endpoint of Denon AVR receiver asynchronously."""
138
+ client = self.client_getter()
139
+ try:
140
+ res = await client.post(
141
+ url,
142
+ content=content,
143
+ data=data,
144
+ timeout=httpx.Timeout(timeout, read=read_timeout),
145
+ )
146
+ res.raise_for_status()
147
+ finally:
148
+ # Close the default AsyncClient but keep custom clients open
149
+ if self.is_default_async_client():
150
+ await client.aclose()
151
+
152
+ return res
153
+
154
+ def is_default_async_client(self) -> bool:
155
+ """Check if default httpx.AsyncClient getter is used."""
156
+ return self.client_getter is get_default_async_client
157
+
158
+
159
+ @attr.s(auto_attribs=True, on_setattr=DENON_ATTR_SETATTR)
87
160
  class DenonAVRApi:
88
161
  """Perform API calls to Denon AVR REST interface."""
89
162
 
90
163
  host: str = attr.ib(converter=str, default="localhost")
91
164
  port: int = attr.ib(converter=int, default=80)
92
- timeout: httpx.Timeout = attr.ib(
93
- validator=attr.validators.instance_of(httpx.Timeout),
94
- default=httpx.Timeout(2.0, read=15.0),
95
- )
165
+ timeout: float = attr.ib(converter=float, default=2.0)
166
+ read_timeout: float = attr.ib(converter=float, default=15.0)
96
167
  _appcommand_update_tags: Tuple[AppCommandCmd] = attr.ib(
97
168
  validator=attr.validators.deep_iterable(
98
169
  attr.validators.instance_of(AppCommandCmd),
@@ -107,23 +178,18 @@ class DenonAVRApi:
107
178
  ),
108
179
  default=attr.Factory(tuple),
109
180
  )
110
- async_client_getter: Callable[[], httpx.AsyncClient] = attr.ib(
111
- validator=attr.validators.is_callable(),
112
- default=get_default_async_client,
181
+ httpx_async_client: HTTPXAsyncClient = attr.ib(
182
+ validator=attr.validators.instance_of(HTTPXAsyncClient),
183
+ default=attr.Factory(HTTPXAsyncClient),
113
184
  init=False,
114
185
  )
115
186
 
116
- def __hash__(self) -> int:
117
- """
118
- Hash the class in a custom way that caching works.
119
-
120
- It should react on changes of host and port.
121
- """
122
- return hash((self.host, self.port))
123
-
124
- @async_handle_receiver_exceptions
125
187
  async def async_get(
126
- self, request: str, port: Optional[int] = None
188
+ self,
189
+ request: str,
190
+ *,
191
+ port: Optional[int] = None,
192
+ cache_id: Hashable = None,
127
193
  ) -> httpx.Response:
128
194
  """Call GET endpoint of Denon AVR receiver asynchronously."""
129
195
  # Use default port of the receiver if no different port is specified
@@ -131,24 +197,18 @@ class DenonAVRApi:
131
197
 
132
198
  endpoint = f"http://{self.host}:{port}{request}"
133
199
 
134
- client = self.async_client_getter()
135
- try:
136
- res = await client.get(endpoint, timeout=self.timeout)
137
- res.raise_for_status()
138
- finally:
139
- # Close the default AsyncClient but keep custom clients open
140
- if self.is_default_async_client():
141
- await client.aclose()
142
-
143
- return res
200
+ return await self.httpx_async_client.async_get(
201
+ endpoint, self.timeout, self.read_timeout, cache_id=cache_id
202
+ )
144
203
 
145
- @async_handle_receiver_exceptions
146
204
  async def async_post(
147
205
  self,
148
206
  request: str,
207
+ *,
149
208
  content: Optional[bytes] = None,
150
209
  data: Optional[Dict] = None,
151
210
  port: Optional[int] = None,
211
+ cache_id: Hashable = None,
152
212
  ) -> httpx.Response:
153
213
  """Call POST endpoint of Denon AVR receiver asynchronously."""
154
214
  # Use default port of the receiver if no different port is specified
@@ -156,20 +216,15 @@ class DenonAVRApi:
156
216
 
157
217
  endpoint = f"http://{self.host}:{port}{request}"
158
218
 
159
- client = self.async_client_getter()
160
- try:
161
- res = await client.post(
162
- endpoint, content=content, data=data, timeout=self.timeout
163
- )
164
- res.raise_for_status()
165
- finally:
166
- # Close the default AsyncClient but keep custom clients open
167
- if self.is_default_async_client():
168
- await client.aclose()
169
-
170
- return res
219
+ return await self.httpx_async_client.async_post(
220
+ endpoint,
221
+ self.timeout,
222
+ self.read_timeout,
223
+ content=content,
224
+ data=data,
225
+ cache_id=cache_id,
226
+ )
171
227
 
172
- @async_handle_receiver_exceptions
173
228
  async def async_get_command(self, request: str) -> str:
174
229
  """Send HTTP GET command to Denon AVR receiver asynchronously."""
175
230
  # HTTP GET to endpoint
@@ -177,34 +232,46 @@ class DenonAVRApi:
177
232
  # Return text
178
233
  return res.text
179
234
 
180
- @cache_result
181
- @async_handle_receiver_exceptions
182
235
  async def async_get_xml(
183
- self, request: str, cache_id: Hashable = None
236
+ self, request: str, *, cache_id: Hashable = None
184
237
  ) -> ET.Element:
185
238
  """Return XML data from HTTP GET endpoint asynchronously."""
186
239
  # HTTP GET to endpoint
187
- res = await self.async_get(request)
240
+ res = await self.async_get(request, cache_id=cache_id)
188
241
  # create ElementTree
189
- xml_root = fromstring(res.text)
242
+ try:
243
+ xml_root = fromstring(res.text)
244
+ except (
245
+ ET.ParseError,
246
+ DefusedXmlException,
247
+ ParseError,
248
+ UnicodeDecodeError,
249
+ ) as err:
250
+ raise AvrInvalidResponseError(f"XMLParseError: {err}", request) from err
190
251
  # Check validity of XML
191
252
  self.check_xml_validity(request, xml_root)
192
253
  # Return ElementTree element
193
254
  return xml_root
194
255
 
195
- @cache_result
196
- @async_handle_receiver_exceptions
197
256
  async def async_post_appcommand(
198
- self, request: str, cmds: Tuple[AppCommandCmd], cache_id: Hashable = None
257
+ self, request: str, cmds: Tuple[AppCommandCmd], *, cache_id: Hashable = None
199
258
  ) -> ET.Element:
200
259
  """Return XML from Appcommand(0300) endpoint asynchronously."""
201
260
  # Prepare XML body for POST call
202
261
  content = self.prepare_appcommand_body(cmds)
203
262
  _LOGGER.debug("Content for %s endpoint: %s", request, content)
204
263
  # HTTP POST to endpoint
205
- res = await self.async_post(request, content=content)
264
+ res = await self.async_post(request, content=content, cache_id=cache_id)
206
265
  # create ElementTree
207
- xml_root = fromstring(res.text)
266
+ try:
267
+ xml_root = fromstring(res.text)
268
+ except (
269
+ ET.ParseError,
270
+ DefusedXmlException,
271
+ ParseError,
272
+ UnicodeDecodeError,
273
+ ) as err:
274
+ raise AvrInvalidResponseError(f"XMLParseError: {err}", request) from err
208
275
  # Check validity of XML
209
276
  self.check_xml_validity(request, xml_root)
210
277
  # Add query tags to result
@@ -350,10 +417,6 @@ class DenonAVRApi:
350
417
 
351
418
  return body_bytes
352
419
 
353
- def is_default_async_client(self) -> bool:
354
- """Check if default httpx.AsyncClient getter is used."""
355
- return self.async_client_getter is get_default_async_client
356
-
357
420
 
358
421
  class DenonAVRTelnetProtocol(asyncio.Protocol):
359
422
  """Protocol for the Denon AVR Telnet interface."""
@@ -481,8 +544,8 @@ class DenonAVRTelnetApi:
481
544
  "%s: Connection failed on telnet reconnect: %s", self.host, err
482
545
  )
483
546
  raise AvrNetworkError(f"OSError: {err}", "telnet connect") from err
484
- _LOGGER.debug("%s: telnet connection established", self.host)
485
547
  self._protocol = cast(DenonAVRTelnetProtocol, transport_protocol[1])
548
+ _LOGGER.debug("%s: telnet connection established", self.host)
486
549
  self._connection_enabled = True
487
550
  self._last_message_time = time.monotonic()
488
551
  self._schedule_monitor()
@@ -500,10 +563,55 @@ class DenonAVRTelnetApi:
500
563
  "PSBAS ?",
501
564
  "PSTRE ?",
502
565
  "PSDYNEQ ?",
566
+ "PSLFC ?",
567
+ "PSCNTAMT ?",
503
568
  "PSMULTEQ: ?",
504
569
  "PSREFLEV ?",
505
570
  "PSDYNVOL ?",
506
571
  "MS?",
572
+ "MNMEN?",
573
+ "DIM ?",
574
+ "PSDELAY?",
575
+ "ECO?",
576
+ "VSMONI ?",
577
+ "PSDIRAC ?",
578
+ "CV?",
579
+ "PSNEURAL ?",
580
+ "PSIMAX ?",
581
+ "PSIMAXAUD ?",
582
+ "PSIMAXHPF ?",
583
+ "PSIMAXLPF ?",
584
+ "PSIMAXSWM ?",
585
+ "PSIMAXSWO ?",
586
+ "PSSWR ?",
587
+ "PSSWL ?",
588
+ "SSTTR ?",
589
+ "MSQUICK ?",
590
+ "STBY?",
591
+ "SLP?",
592
+ "VSAUDIO ?",
593
+ "PSCES ?",
594
+ "VSVPM ?",
595
+ "PSLFE ?",
596
+ "PSLOM ?",
597
+ "PSBSC ?",
598
+ "PSDEH ?",
599
+ "PSCINEMA EQ. ?",
600
+ "PSAUROPR ?",
601
+ "PSAUROST ?",
602
+ "PSAUROMODE ?",
603
+ "PSRSZ ?",
604
+ "TR?",
605
+ "SPPR ?",
606
+ "BTTX ?",
607
+ "PSDIC ?",
608
+ "PSSPV ?",
609
+ "PSSP: ?",
610
+ "PSDRC ?",
611
+ "PSDEL ?",
612
+ "PSRSTR ?",
613
+ "PSGEQ ?",
614
+ "PSHEQ ?",
507
615
  skip_confirmation=True,
508
616
  )
509
617
 
@@ -543,7 +651,8 @@ class DenonAVRTelnetApi:
543
651
  self._stop_monitor()
544
652
  if not self._connection_enabled:
545
653
  return
546
- self._reconnect_task = asyncio.create_task(self._async_reconnect())
654
+ if self._reconnect_task is None:
655
+ self._reconnect_task = asyncio.create_task(self._async_reconnect())
547
656
 
548
657
  async def async_disconnect(self) -> None:
549
658
  """Close the connection to the receiver asynchronously."""
@@ -581,6 +690,12 @@ class DenonAVRTelnetApi:
581
690
  )
582
691
  except AvrNetworkError as err:
583
692
  _LOGGER.debug("%s: %s", self.host, err)
693
+ except AvrProcessingError as err:
694
+ _LOGGER.debug(
695
+ "%s: Failed updating state on telnet reconnect: %s",
696
+ self.host,
697
+ err,
698
+ )
584
699
  except Exception as err: # pylint: disable=broad-except
585
700
  _LOGGER.error(
586
701
  "%s: Unexpected exception on telnet reconnect",
@@ -589,11 +704,13 @@ class DenonAVRTelnetApi:
589
704
  )
590
705
  else:
591
706
  _LOGGER.info("%s: Telnet reconnected", self.host)
592
- return
707
+ break
593
708
 
594
709
  await asyncio.sleep(backoff)
595
710
  backoff = min(30.0, backoff * 2)
596
711
 
712
+ self._reconnect_task = None
713
+
597
714
  def register_callback(
598
715
  self, event: str, callback: Callable[[str, str, str], Awaitable[None]]
599
716
  ) -> None:
@@ -604,6 +721,8 @@ class DenonAVRTelnetApi:
604
721
 
605
722
  if event not in self._callbacks.keys():
606
723
  self._callbacks[event] = []
724
+ elif callback in self._callbacks[event]:
725
+ return
607
726
  self._callbacks[event].append(callback)
608
727
 
609
728
  def unregister_callback(
@@ -618,6 +737,8 @@ class DenonAVRTelnetApi:
618
737
  self, callback: Callable[[str], Awaitable[None]]
619
738
  ) -> None:
620
739
  """Register a callback handler for raw telnet messages."""
740
+ if callback in self._raw_callbacks:
741
+ return
621
742
  self._raw_callbacks.append(callback)
622
743
 
623
744
  def _unregister_raw_callback(
@@ -60,6 +60,12 @@ class DenonAVRAudyssey(DenonAVRFoundation):
60
60
  _multeq_control: Optional[bool] = attr.ib(
61
61
  converter=attr.converters.optional(convert_string_int_bool), default=None
62
62
  )
63
+ _lfc: Optional[bool] = attr.ib(
64
+ converter=attr.converters.optional(convert_string_int_bool), default=None
65
+ )
66
+ _containment_amount: Optional[int] = attr.ib(
67
+ converter=attr.converters.optional(int), default=None
68
+ )
63
69
 
64
70
  # Update tags for attributes
65
71
  # AppCommand0300.xml interface
@@ -94,6 +100,12 @@ class DenonAVRAudyssey(DenonAVRFoundation):
94
100
  self._dynamiceq = "1"
95
101
  elif parameter == "DYNEQ OFF":
96
102
  self._dynamiceq = "0"
103
+ elif parameter == "LFC ON":
104
+ self._lfc = "1"
105
+ elif parameter == "LFC OFF":
106
+ self._lfc = "0"
107
+ elif parameter[:6] == "CNTAMT":
108
+ self._containment_amount = int(parameter[7:])
97
109
 
98
110
  async def async_update(
99
111
  self, global_update: bool = False, cache_id: Optional[Hashable] = None
@@ -186,6 +198,24 @@ class DenonAVRAudyssey(DenonAVRFoundation):
186
198
  return list(MULTI_EQ_MAP_LABELS_TELNET.keys())
187
199
  return list(MULTI_EQ_MAP_LABELS_APPCOMMAND.keys())
188
200
 
201
+ @property
202
+ def lfc(self) -> Optional[bool]:
203
+ """
204
+ Return value of LFC.
205
+
206
+ Only available if using Telnet.
207
+ """
208
+ return self._lfc
209
+
210
+ @property
211
+ def containment_amount(self) -> Optional[int]:
212
+ """
213
+ Return value of Containment Amount.
214
+
215
+ Only available if using Telnet.
216
+ """
217
+ return self._containment_amount
218
+
189
219
  ##########
190
220
  # Setter #
191
221
  ##########
@@ -284,6 +314,81 @@ class DenonAVRAudyssey(DenonAVRFoundation):
284
314
  else:
285
315
  await self.async_dynamiceq_on()
286
316
 
317
+ async def async_lfc_on(self):
318
+ """Turn LFC on."""
319
+ if self._device.telnet_available:
320
+ await self._device.telnet_api.async_send_commands(
321
+ self._device.telnet_commands.command_lfc.format(mode="ON")
322
+ )
323
+ return
324
+ await self._device.api.async_get_command(
325
+ self._device.urls.command_lfc.format(mode="ON")
326
+ )
327
+
328
+ async def async_lfc_off(self):
329
+ """Turn LFC off."""
330
+ if self._device.telnet_available:
331
+ await self._device.telnet_api.async_send_commands(
332
+ self._device.telnet_commands.command_lfc.format(mode="OFF")
333
+ )
334
+ return
335
+ await self._device.api.async_get_command(
336
+ self._device.urls.command_lfc.format(mode="OFF")
337
+ )
338
+
339
+ async def async_toggle_lfc(self):
340
+ """Toggle LFC."""
341
+ if self._lfc:
342
+ await self.async_lfc_off()
343
+ else:
344
+ await self.async_lfc_on()
345
+
346
+ async def async_containment_amount(self, amount: int) -> None:
347
+ """
348
+ Set Containment Amount.
349
+
350
+ Valid values are 1-7.
351
+ """
352
+ if amount < 1 or amount > 7:
353
+ raise AvrCommandError("Containment amount must be between 1 and 7")
354
+ local_amount = f"{amount:02}"
355
+ if self._device.telnet_available:
356
+ await self._device.telnet_api.async_send_commands(
357
+ self._device.telnet_commands.command_containment_amount.format(
358
+ value=local_amount
359
+ )
360
+ )
361
+ return
362
+ await self._device.api.async_get_command(
363
+ self._device.urls.command_containment_amount.format(value=local_amount)
364
+ )
365
+
366
+ async def async_containment_amount_up(self) -> None:
367
+ """Increase Containment Amount."""
368
+ if self._device.telnet_available:
369
+ await self._device.telnet_api.async_send_commands(
370
+ self._device.telnet_commands.command_containment_amount.format(
371
+ value="UP"
372
+ )
373
+ )
374
+ return
375
+ await self._device.api.async_get_command(
376
+ self._device.urls.command_containment_amount.format(value="UP")
377
+ )
378
+
379
+ async def async_containment_amount_down(self) -> None:
380
+ """Decrease Containment Amount."""
381
+ if self._device.telnet_available:
382
+ await self._device.telnet_api.async_send_commands(
383
+ self._device.telnet_commands.command_containment_amount.format(
384
+ value="DOWN"
385
+ )
386
+ )
387
+ return
388
+ await self._device.api.async_get_command(
389
+ self._device.urls.command_containment_amount.format(value="DOWN")
390
+ )
391
+
287
392
 
288
393
  def audyssey_factory(instance: DenonAVRFoundation) -> DenonAVRAudyssey:
289
394
  """Create DenonAVRAudyssey at receiver instances."""