mx-remote 6.3.0__tar.gz → 8.0.2__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 (270) hide show
  1. {mx_remote-6.3.0 → mx_remote-8.0.2}/PKG-INFO +1 -1
  2. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/api.md +146 -0
  3. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/callbacks.md +1 -1
  4. mx_remote-8.0.2/docs/devices-and-bays.md +94 -0
  5. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/oneip.md +170 -3
  6. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/routing.md +6 -0
  7. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/Interface.py +702 -51
  8. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/Interface.pyi +239 -5
  9. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/const.py +1 -1
  10. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/BayConfig.py +5 -4
  11. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Constants.py +367 -17
  12. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Constants.pyi +180 -2
  13. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Factory.py +15 -0
  14. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAudioSetRoute.py +16 -2
  15. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAudioSetRoute.pyi +3 -0
  16. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBase.py +65 -1
  17. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBase.pyi +7 -1
  18. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayConfig.py +4 -0
  19. mx_remote-8.0.2/mx_remote/proto/FrameBayContent.py +77 -0
  20. mx_remote-8.0.2/mx_remote/proto/FrameBayContent.pyi +18 -0
  21. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayHide.py +8 -1
  22. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayStatus.py +36 -8
  23. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayStatus.pyi +6 -0
  24. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameDiscover.py +12 -0
  25. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameDiscover.pyi +3 -0
  26. mx_remote-8.0.2/mx_remote/proto/FrameFactoryReset.py +51 -0
  27. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameFactoryReset.pyi +2 -0
  28. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameFilterStatus.py +7 -3
  29. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameFirmwareVersion.py +34 -3
  30. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameFirmwareVersion.pyi +2 -0
  31. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameHello.py +9 -1
  32. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMirrorStatus.py +16 -8
  33. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMonitoringPulse.py +3 -3
  34. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameNetworkStatus.py +6 -2
  35. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCIr.py +11 -1
  36. mx_remote-8.0.2/mx_remote/proto/FrameReboot.py +39 -0
  37. mx_remote-8.0.2/mx_remote/proto/FrameReboot.pyi +13 -0
  38. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRoutingChange.py +17 -2
  39. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetName.py +13 -8
  40. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetName.pyi +2 -0
  41. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetRoute.py +5 -1
  42. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetRoute.pyi +2 -0
  43. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetupStatus.py +4 -2
  44. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSignalStatusNew.py +35 -15
  45. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSysTemperature.py +3 -1
  46. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSystemStatus.py +4 -1
  47. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTopology.py +7 -3
  48. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTxIR.py +3 -2
  49. mx_remote-8.0.2/mx_remote/proto/FrameUnitCommand.py +70 -0
  50. mx_remote-8.0.2/mx_remote/proto/FrameUnitCommand.pyi +20 -0
  51. mx_remote-8.0.2/mx_remote/proto/FrameUnitStatus.py +70 -0
  52. mx_remote-8.0.2/mx_remote/proto/FrameUnitStatus.pyi +16 -0
  53. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPAudio.py +129 -26
  54. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPAudio.pyi +21 -4
  55. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPBayMapping.py +4 -1
  56. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +136 -55
  57. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +11 -3
  58. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +9 -2
  59. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPMultiviewer.py +4 -0
  60. mx_remote-8.0.2/mx_remote/proto/FrameV2IPOsdSync.py +251 -0
  61. mx_remote-8.0.2/mx_remote/proto/FrameV2IPOsdSync.pyi +41 -0
  62. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSettingsAll.py +11 -5
  63. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSettingsAll.pyi +1 -1
  64. mx_remote-8.0.2/mx_remote/proto/FrameV2IPSinkSdp.py +122 -0
  65. mx_remote-8.0.2/mx_remote/proto/FrameV2IPSinkSdp.pyi +29 -0
  66. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSourceSwitch.py +9 -3
  67. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPTestcard.py +6 -1
  68. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeSet.py +18 -15
  69. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Bay.py +299 -42
  70. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Bay.pyi +19 -5
  71. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/ConnectionAsync.py +5 -1
  72. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/ConnectionAsync.pyi +2 -0
  73. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Device.py +397 -31
  74. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Device.pyi +49 -3
  75. mx_remote-8.0.2/mx_remote/remote/OsdSync.py +250 -0
  76. mx_remote-8.0.2/mx_remote/remote/OsdSync.pyi +47 -0
  77. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Remote.py +183 -16
  78. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Remote.pyi +10 -3
  79. mx_remote-8.0.2/tests/audiolock.py +219 -0
  80. mx_remote-8.0.2/tests/baycontent.py +99 -0
  81. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/complete.py +31 -6
  82. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/deprecated.py +37 -1
  83. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/e2e.py +43 -3
  84. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/handlers.py +8 -0
  85. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/handlers_cover.py +26 -83
  86. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/hello.py +3 -2
  87. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/idempotent.py +14 -9
  88. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/lengths.py +3 -1
  89. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/merge.py +24 -24
  90. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/mesh.py +23 -3
  91. mx_remote-8.0.2/tests/meshbays.py +295 -0
  92. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/newops.py +7 -0
  93. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/offline.py +23 -1
  94. mx_remote-8.0.2/tests/osdsync.py +315 -0
  95. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/ping.py +10 -0
  96. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/proto_stamp.py +3 -0
  97. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/rcsettings.py +4 -2
  98. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/roundtrip.py +24 -1
  99. mx_remote-8.0.2/tests/routes.py +244 -0
  100. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/run.py +7 -0
  101. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/smoke.py +24 -1
  102. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/structs.py +25 -1
  103. mx_remote-8.0.2/tests/unit.py +198 -0
  104. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/unknowns.py +24 -1
  105. mx_remote-8.0.2/tests/v2ipptp.py +93 -0
  106. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/v2ipscaling.py +17 -7
  107. mx_remote-8.0.2/tests/v2ipsdp.py +117 -0
  108. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/v2ipsettings.py +185 -0
  109. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/v2ipsubject.py +1 -1
  110. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/v2iptestcard.py +13 -1
  111. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/wirefix.py +86 -33
  112. mx_remote-6.3.0/docs/devices-and-bays.md +0 -54
  113. mx_remote-6.3.0/mx_remote/proto/FrameFactoryReset.py +0 -53
  114. mx_remote-6.3.0/mx_remote/proto/FrameReboot.py +0 -21
  115. mx_remote-6.3.0/mx_remote/proto/FrameReboot.pyi +0 -6
  116. mx_remote-6.3.0/tests/audiolock.py +0 -119
  117. {mx_remote-6.3.0 → mx_remote-8.0.2}/.gitignore +0 -0
  118. {mx_remote-6.3.0 → mx_remote-8.0.2}/AGENTS.md +0 -0
  119. {mx_remote-6.3.0 → mx_remote-8.0.2}/CLAUDE.md +0 -0
  120. {mx_remote-6.3.0 → mx_remote-8.0.2}/LICENSE +0 -0
  121. {mx_remote-6.3.0 → mx_remote-8.0.2}/README.md +0 -0
  122. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/README.md +0 -0
  123. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/_static/brand.css +0 -0
  124. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/_static/favicon.svg +0 -0
  125. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/_static/logo-dark.svg +0 -0
  126. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/_static/logo.svg +0 -0
  127. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/audio.md +0 -0
  128. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/conf.py +0 -0
  129. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/configuration.md +0 -0
  130. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/diagnostics.md +0 -0
  131. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/index.md +0 -0
  132. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/multiviewer.md +0 -0
  133. {mx_remote-6.3.0 → mx_remote-8.0.2}/docs/requirements.txt +0 -0
  134. {mx_remote-6.3.0 → mx_remote-8.0.2}/hatch_build.py +0 -0
  135. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/Uid.py +0 -0
  136. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/Uid.pyi +0 -0
  137. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/__init__.py +0 -0
  138. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/__init__.pyi +0 -0
  139. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/compat.py +0 -0
  140. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/compat.pyi +0 -0
  141. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/const.pyi +0 -0
  142. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/deprecated.py +0 -0
  143. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/deprecated.pyi +0 -0
  144. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/main.py +0 -0
  145. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/main.pyi +0 -0
  146. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/BayConfig.pyi +0 -0
  147. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Data.py +0 -0
  148. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Data.pyi +0 -0
  149. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Factory.pyi +0 -0
  150. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
  151. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
  152. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
  153. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
  154. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAudioClip.py +0 -0
  155. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameAudioClip.pyi +0 -0
  156. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayConfig.pyi +0 -0
  157. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
  158. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
  159. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameBayHide.pyi +0 -0
  160. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameConnectStatus.py +0 -0
  161. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
  162. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameDebug.py +0 -0
  163. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameDebug.pyi +0 -0
  164. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameEDID.py +0 -0
  165. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameEDID.pyi +0 -0
  166. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameEDIDProfile.py +0 -0
  167. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
  168. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
  169. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameHeader.py +0 -0
  170. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameHeader.pyi +0 -0
  171. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameHello.pyi +0 -0
  172. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameLinks.py +0 -0
  173. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameLinks.pyi +0 -0
  174. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMeshOperation.py +0 -0
  175. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMeshOperation.pyi +0 -0
  176. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
  177. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
  178. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
  179. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FramePing.py +0 -0
  180. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FramePing.pyi +0 -0
  181. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FramePowerChange.py +0 -0
  182. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FramePowerChange.pyi +0 -0
  183. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCAction.py +0 -0
  184. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCAction.pyi +0 -0
  185. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCIr.pyi +0 -0
  186. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCKey.py +0 -0
  187. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCKey.pyi +0 -0
  188. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCSettings.py +0 -0
  189. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRCSettings.pyi +0 -0
  190. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
  191. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetInstaller.py +0 -0
  192. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
  193. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
  194. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSignalStatus.py +0 -0
  195. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
  196. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
  197. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
  198. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
  199. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTXRCAction.py +0 -0
  200. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
  201. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTXRCKey.py +0 -0
  202. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
  203. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTime.py +0 -0
  204. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTime.pyi +0 -0
  205. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTimeZone.py +0 -0
  206. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTimeZone.pyi +0 -0
  207. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTopology.pyi +0 -0
  208. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameTxIR.pyi +0 -0
  209. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameUpgradeFPGA.py +0 -0
  210. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
  211. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
  212. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPDetectBays.py +0 -0
  213. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
  214. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPLink.py +0 -0
  215. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
  216. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +0 -0
  217. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
  218. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPPowerSave.py +0 -0
  219. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
  220. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSetMaster.py +0 -0
  221. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
  222. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
  223. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSources.py +0 -0
  224. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPSources.pyi +0 -0
  225. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPStats.py +0 -0
  226. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPStats.pyi +0 -0
  227. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPTestcard.pyi +0 -0
  228. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPTiling.py +0 -0
  229. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
  230. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPVideoWall.py +0 -0
  231. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
  232. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolume.py +0 -0
  233. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolume.pyi +0 -0
  234. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeDown.py +0 -0
  235. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
  236. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
  237. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeUp.py +0 -0
  238. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
  239. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/LinkConfig.py +0 -0
  240. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/LinkConfig.pyi +0 -0
  241. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Multiviewer.py +0 -0
  242. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Multiviewer.pyi +0 -0
  243. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Svd.py +0 -0
  244. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/Svd.pyi +0 -0
  245. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/V2IPConfig.py +0 -0
  246. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/V2IPConfig.pyi +0 -0
  247. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/V2IPStats.py +0 -0
  248. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/V2IPStats.pyi +0 -0
  249. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/__init__.py +0 -0
  250. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/__init__.pyi +0 -0
  251. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/proto/svd.csv +0 -0
  252. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/py.typed +0 -0
  253. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Link.py +0 -0
  254. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/Link.pyi +0 -0
  255. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/State.py +0 -0
  256. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/State.pyi +0 -0
  257. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/V2IP.py +0 -0
  258. {mx_remote-6.3.0 → mx_remote-8.0.2}/mx_remote/remote/V2IP.pyi +0 -0
  259. {mx_remote-6.3.0 → mx_remote-8.0.2}/pyproject.toml +0 -0
  260. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/audio_ir.py +0 -0
  261. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/capture.py +0 -0
  262. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/entry.py +0 -0
  263. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/offsets.py +0 -0
  264. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/protogate.py +0 -0
  265. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/sources.py +0 -0
  266. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/staterequest.py +0 -0
  267. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/stats.py +0 -0
  268. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/txresult.py +0 -0
  269. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/v2ipvlan.py +0 -0
  270. {mx_remote-6.3.0 → mx_remote-8.0.2}/tests/vdetails.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: mx_remote
3
- Version: 6.3.0
3
+ Version: 8.0.2
4
4
  Summary: Python 3 library for interfacing with MX Remote compatible devices
5
5
  Project-URL: Homepage, https://github.com/opdenkamp/mx-remote/
6
6
  Project-URL: Documentation, https://opdenkamp.github.io/mx-remote/
@@ -31,6 +31,60 @@ they are what the registry hands out and what a callback receives.
31
31
  :members:
32
32
  ```
33
33
 
34
+ ## Bay content
35
+
36
+ What the source on an input is showing, and how much of it a unit keeps.
37
+
38
+ ```{eval-rst}
39
+ .. autodata:: mx_remote.proto.Constants.BAY_CONTENT_KEY_MAX
40
+
41
+ .. autodata:: mx_remote.proto.Constants.BAY_CONTENT_VALUE_MAX
42
+ ```
43
+
44
+ ## Overlay sync
45
+
46
+ A management unit having other units copy its overlay captions, logo choice and
47
+ place, backgrounds and logo images.
48
+
49
+ ```{eval-rst}
50
+ .. autoclass:: mx_remote.proto.Constants.OsdSyncWhat
51
+ :members:
52
+
53
+ .. autoclass:: mx_remote.proto.Constants.OsdSyncState
54
+ :members:
55
+
56
+ .. autoclass:: mx_remote.proto.Constants.OsdSyncSize
57
+ :members:
58
+
59
+ .. autoclass:: mx_remote.proto.Constants.OsdCaptionAlign
60
+ :members:
61
+
62
+ .. autoclass:: mx_remote.proto.Constants.OsdCaptionFormat
63
+ :members:
64
+
65
+ .. autoclass:: mx_remote.proto.Constants.OsdCaptionField
66
+ :members:
67
+
68
+ .. autoclass:: mx_remote.proto.Constants.OsdLogoField
69
+ :members:
70
+
71
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_SLOTS
72
+
73
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_RECORDS_MAX
74
+
75
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_FONT_MAX
76
+
77
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_TEXT_MAX
78
+
79
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_IMAGE_MAX
80
+
81
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_IMAGE_WIDTH_MAX
82
+
83
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_IMAGE_HEIGHT_MAX
84
+
85
+ .. autodata:: mx_remote.proto.Constants.OSD_SYNC_PERCENT_MAX
86
+ ```
87
+
34
88
  ## Device identity
35
89
 
36
90
  ```{eval-rst}
@@ -81,6 +135,9 @@ bit, and the range of the infrared profiles.
81
135
  .. autoclass:: mx_remote.OneIPPowerSaveSchedule
82
136
  :members:
83
137
 
138
+ .. autoclass:: mx_remote.proto.Constants.OneIPPowerSaveLevel
139
+ :members:
140
+
84
141
  .. autoclass:: mx_remote.OneIPVlan
85
142
  :members:
86
143
 
@@ -94,6 +151,95 @@ bit, and the range of the infrared profiles.
94
151
  .. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_ID_MAX
95
152
  ```
96
153
 
154
+ ## OneIP PTP
155
+
156
+ A device's PTP settings, which it reports and a controller writes, and the PTP
157
+ state only the device reports.
158
+
159
+ ```{eval-rst}
160
+ .. autoclass:: mx_remote.OneIPPtpState
161
+ :members:
162
+
163
+ .. autoclass:: mx_remote.proto.Constants.OneIPPtpMode
164
+ :members:
165
+
166
+ .. autoclass:: mx_remote.proto.Constants.OneIPPtpFlag
167
+ :members:
168
+
169
+ .. autoclass:: mx_remote.proto.Constants.OneIPPtpLock
170
+ :members:
171
+
172
+ .. autodata:: mx_remote.proto.Constants.ONEIP_DEVICE_SETTINGS_PTP
173
+
174
+ .. autoclass:: mx_remote.OneIPPtpMessages
175
+ :members:
176
+
177
+ .. autodata:: mx_remote.proto.Constants.ONEIP_DEVICE_SETTINGS_PTP_MESSAGES
178
+
179
+ .. autodata:: mx_remote.proto.Constants.ONEIP_DEVICE_SETTINGS_BLOCK
180
+
181
+ .. autodata:: mx_remote.proto.Constants.ONEIP_STREAM_TTL_DEFAULT
182
+
183
+ .. autodata:: mx_remote.proto.Constants.ONEIP_PTP_DOMAIN_MAX
184
+ ```
185
+
186
+ ## Unit status and commands
187
+
188
+ A unit's health and IP configuration, and the commands sent to one unit.
189
+
190
+ ```{eval-rst}
191
+ .. autoclass:: mx_remote.UnitStatus
192
+ :members:
193
+
194
+ .. autoclass:: mx_remote.UnitNetConfig
195
+ :members:
196
+
197
+ .. autoclass:: mx_remote.proto.Constants.UnitFlag
198
+ :members:
199
+
200
+ .. autoclass:: mx_remote.proto.Constants.UnitCommandKind
201
+ :members:
202
+
203
+ .. autoclass:: mx_remote.proto.Constants.UnitCommandFlag
204
+ :members:
205
+
206
+ .. autodata:: mx_remote.proto.Constants.UNIT_MAX_TEMPERATURES
207
+
208
+ .. autoclass:: mx_remote.proto.Constants.UnitPowerSave
209
+ :members:
210
+
211
+ .. autodata:: mx_remote.proto.Constants.UNIT_POWER_SAVE_LEVELS
212
+ ```
213
+
214
+ ## OneIP session descriptions
215
+
216
+ What an output plays from a session description, and how it is timed.
217
+
218
+ ```{eval-rst}
219
+ .. autoclass:: mx_remote.OneIPSinkSdp
220
+ :members:
221
+
222
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpFlag
223
+ :members:
224
+
225
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpEncoding
226
+ :members:
227
+
228
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpMediaClock
229
+ :members:
230
+
231
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpRefClock
232
+ :members:
233
+
234
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpClockMode
235
+ :members:
236
+
237
+ .. autoclass:: mx_remote.proto.Constants.OneIPSdpClockState
238
+ :members:
239
+
240
+ .. autodata:: mx_remote.proto.Constants.ONEIP_SDP_MAX
241
+ ```
242
+
97
243
  ## OneIP test card
98
244
 
99
245
  A sink's test pattern, tone and lip-sync flash, and the ranges it accepts.
@@ -51,7 +51,7 @@ Available callback methods:
51
51
  | `on_status_signal_detected_changed` | signal detect status changed |
52
52
  | `on_status_faulty_changed` | fault status changed |
53
53
  | `on_status_hidden_changed` | hidden status changed |
54
- | `on_status_poe_powered_changed` | PoE power status changed |
54
+ | `on_status_zone_powered_changed` | The amplifier zone a bay drives powered on or off (ProAmp8v2) |
55
55
  | `on_status_hdbt_connected_changed` | HDBaseT link status changed |
56
56
  | `on_status_signal_type_changed` | signal type changed |
57
57
  | `on_status_hpd_detected_changed` | hotplug detect changed |
@@ -0,0 +1,94 @@
1
+ # Devices and bays
2
+
3
+ Naming, hiding, EDID and the device registry.
4
+
5
+ ## Device Management
6
+
7
+ ```python
8
+ # reboot a device
9
+ await device.reboot()
10
+
11
+ # ask a device to hello now; False for one below protocol 0x2A
12
+ await device.ping()
13
+
14
+ # read the device log
15
+ log = await device.get_log()
16
+
17
+ # call an HTTP API endpoint on the device
18
+ result = await device.get_api("system/status")
19
+ ```
20
+
21
+ A device on protocol 0x2A pings a peer it suspects is gone and takes it
22
+ offline when nothing answers within about 1.5s. The client answers a ping
23
+ addressed to it with a hello at once, from any sender.
24
+
25
+ ## Bay Naming
26
+
27
+ ```python
28
+ await bay.set_name("Living Room TV")
29
+ ```
30
+
31
+ ## Bay Visibility
32
+
33
+ Hide or show bays:
34
+
35
+ ```python
36
+ await bay.set_hidden(True) # hide
37
+ await bay.set_hidden(False) # show
38
+ ```
39
+
40
+ ## EDID Profiles
41
+
42
+ Change the EDID profile on input bays:
43
+
44
+ ```python
45
+ from mx_remote import EdidProfile
46
+
47
+ await bay.select_edid_profile(EdidProfile.TEMPLATE_1080P_STEREO)
48
+ await bay.select_edid_profile(EdidProfile.TEMPLATE_4K_HDR_7_1)
49
+ await bay.select_edid_profile(EdidProfile.LOWEST_COMMON_DENOMINATOR)
50
+ ```
51
+
52
+ ## Bay Content
53
+
54
+ A unit with a source driver, such as the Sky Q one, reports what the source on
55
+ an input is showing as named values, in the order they are meant to be shown:
56
+
57
+ ```python
58
+ print(bay.content) # e.g. name='BBC One', number='101'
59
+ print(bay.content.get('name')) # None when the source reports no such value
60
+ ```
61
+
62
+ The names are open-ended: a driver for a new kind of source adds its own, so
63
+ pass on the ones you do not know. Each value is cleaned as a receiving unit
64
+ cleans it, so it reads as the unit's own API shows it. The content outlives the
65
+ signal, so check `signal_detected` before showing it. `on_bay_content_changed`
66
+ reports a change, and an empty `content` is a source showing nothing.
67
+
68
+ ## Mesh Bays
69
+
70
+ A OneIP unit lists the inputs and outputs of the other units in its mesh as
71
+ bays of its own. Such a mesh bay stands for bay 0 in the same direction on the
72
+ unit its `oneip_uid` names, and `is_local` is False for it.
73
+
74
+ A mesh bay keeps only its identity: its port, `bay_name`, bay number, features
75
+ and `oneip_uid`. Everything else - its user name, signal, status, routes and
76
+ volume - is read from the bay it stands for, since what one unit reports about
77
+ another unit's bay is a copy that is never refreshed. Until that unit has
78
+ reported the bay, the rest reads as never reported. A change to the bay is
79
+ reported for every mesh bay standing for it too, except its registration and
80
+ the key presses and actions that arrive on it.
81
+
82
+ A command about a mesh bay - a rename, hide, EDID profile, action, key,
83
+ power, volume, zone settings or route - goes to the unit it stands for, about
84
+ that unit's bay, and is refused while that unit has not reported the bay. A
85
+ route names that unit as the sink, and its source by port in the numbering of
86
+ the unit listing the mesh bay.
87
+
88
+ Mesh bays are created by the unit's bay mappings, numbered by port in the
89
+ unit's own numbering: from protocol 0x2B input n is port n and output n port
90
+ 127 + n; below it the first 16 bays of each direction come first.
91
+
92
+ ---
93
+
94
+ [Documentation index](README.md) | [Project README](https://github.com/opdenkamp/mx-remote#readme)
@@ -107,9 +107,9 @@ output mode. Each is written behind its own validity bit, so moving one leaves
107
107
  the other where it is.
108
108
 
109
109
  ```python
110
- # what the sink reports. Trust this block only from a device whose hello carries
110
+ # what the sink reports, read only from a device whose hello carries
111
111
  # CONFIG_INITIALISED - firmware without it builds the block over uninitialised
112
- # stack, where the valid bit itself is noise.
112
+ # stack, where the valid bit itself is noise. No released build announces it.
113
113
  scaling = device.oneip_details.scaling
114
114
  print(scaling.auto_scaling) # None when the sender did not say
115
115
  print(scaling.configured_mode) # (signal type, refresh), None when it has none
@@ -133,6 +133,9 @@ in silence. Setting the mode first and turning automatic scaling back on
133
133
  afterwards is the order that survives, because the mode is checked while
134
134
  automatic scaling is still off.
135
135
 
136
+ These are refused for a unit below protocol 0x2F: released firmware drops a
137
+ scaling write from management.
138
+
136
139
  Nothing acknowledges any of these. `set_oneip_output_mode` returns False for a
137
140
  mode no sink would take, but a True only says the frame went out: the sink
138
141
  weighs the format against the display's EDID and against what its own output
@@ -222,6 +225,82 @@ goes out at 176 bytes: a receiver with the schedule ignores the settings of a
222
225
  shorter frame, and one whose settings end at the idle minutes takes it all the
223
226
  same.
224
227
 
228
+ How far a device powers down is its power save level: reduced, low or off, each
229
+ powering more down than the one before. Its unit status says which levels it
230
+ supports and what wakes it at each.
231
+
232
+ ```python
233
+ from mx_remote import OneIPPowerSaveLevel, UnitPowerSave
234
+
235
+ print(settings.power_save_level)
236
+ print(device.unit_status.power_save_level(OneIPPowerSaveLevel.LOW)) # e.g. SUPPORTED|INPUT_WAKE
237
+
238
+ await device.set_oneip_power_save_level(OneIPPowerSaveLevel.LOW)
239
+ ```
240
+
241
+ A level this library does not name is refused before it is sent, and not cached
242
+ from another controller's write.
243
+
244
+ `OneIPDeviceSetting.POWER_SAVE_DISABLED` is a switch that keeps a device from
245
+ powering down by itself; a power save request still powers it down. A device
246
+ that takes a power save level switches it off, so a level write, this client's
247
+ or another sender's, clears it unless the same frame states it. Firmware
248
+ without the bit never reports it, and the switch is refused there.
249
+
250
+ ### PTP
251
+
252
+ A device's PTP mode, domain and grandmaster priority1 are settings like the
253
+ others, each behind its own bit.
254
+
255
+ ```python
256
+ from mx_remote import OneIPPtpMode
257
+
258
+ print(settings.ptp_mode, settings.ptp_domain, settings.ptp_priority1)
259
+
260
+ await device.set_oneip_ptp_mode(OneIPPtpMode.AUTO) # follow, or lead when no one does
261
+ await device.set_oneip_ptp_domain(0) # up to ONEIP_PTP_DOMAIN_MAX
262
+ await device.set_oneip_ptp_priority1(128) # lower wins
263
+ ```
264
+
265
+ A mode this library does not name and a domain above `ONEIP_PTP_DOMAIN_MAX` are
266
+ refused before they are sent, and not cached from another controller's write.
267
+
268
+ How the device paces its PTP messages is five settings more, whose values
269
+ travel in a block of their own: the announce, sync and delay request intervals
270
+ as base-2 logarithms of seconds, the announce timeout and the messages' DSCP.
271
+
272
+ ```python
273
+ from mx_remote import OneIPDeviceSetting, OneIPPtpMessages
274
+
275
+ print(settings.ptp_messages) # None until the device reports one of them
276
+
277
+ await device.set_oneip_ptp_messages(
278
+ OneIPDeviceSetting.PTP_SYNC | OneIPDeviceSetting.PTP_DSCP,
279
+ OneIPPtpMessages(log_sync_interval=-3, dscp=46)) # 125 ms, EF
280
+ ```
281
+
282
+ The SAP expiry in minutes and announcement interval in seconds travel in the
283
+ same block, behind `SAP_EXPIRE` and `SAP_INTERVAL`, and are set the same way;
284
+ `SAP_LISTEN` and `SAP_ANNOUNCE` are switches like the other on/off settings.
285
+ A device with an encoder reports its streams' TTL there too, behind
286
+ `STREAM_TTL`; a TTL of 0 is refused, as a device changes nothing for one.
287
+
288
+ Only the values behind the bits named are sent. A DSCP above `ONEIP_DSCP_MAX` is
289
+ refused, and not cached from another controller's write. A write carrying one of
290
+ these runs on to 224 bytes, or 232 with the TTL; every other write keeps the 176
291
+ every device knows.
292
+
293
+ What the device's clock is actually doing is its PTP state, which only the
294
+ device reports about itself and nothing writes:
295
+
296
+ ```python
297
+ ptp = device.oneip_ptp # None: no report yet, no PTP, or in power save
298
+ if ptp is not None:
299
+ print(ptp.mode, ptp.domain, ptp.lock, ptp.port_state) # port_state per IEEE 1588
300
+ print(ptp.followed) # locked to a master since PTP started
301
+ print(ptp.grandmaster) # its clock identity, None while there is none
302
+ ```
303
+
225
304
  ### VLAN
226
305
 
227
306
  A device that announces `DeviceFeature.VLAN` tags its uplink by a VLAN
@@ -282,6 +361,57 @@ falls outside them in silence: see `OneIPTestTone.is_valid()` and
282
361
  as the sink stops it regardless. The frame needs protocol 0x2B, so a sink
283
362
  announcing less is refused as well.
284
363
 
364
+ ### Session descriptions
365
+
366
+ An output plays an AES67 stream from a session description it is handed, and
367
+ reports what it plays when that changes and at least once a minute.
368
+
369
+ ```python
370
+ await sink.play_oneip_sdp(sdp_text) # sent in 1 KB pages, played once the last is in
371
+ await sink.set_oneip_sdp_screen(1) # what it shows while it plays audio alone
372
+ await sink.request_oneip_sink_sdp() # report now
373
+ await sink.stop_oneip_sdp()
374
+
375
+ print(sink.oneip_sink_sdp) # None until the output has reported
376
+ ```
377
+
378
+ An output takes these only from its mesh controller or a management
379
+ application, which this client announces itself as, and only from protocol
380
+ 0x2E. A description is 1 to `ONEIP_SDP_MAX` bytes: an output drops a longer one
381
+ after its last page, so one is refused before it is sent. Nothing acknowledges
382
+ the pages; `oneip_sink_sdp` reads what the output reports next.
383
+
384
+ ### Overlay sync
385
+
386
+ A management unit can have the other units copy its overlay captions, logo
387
+ choice and place, backgrounds and logo images. Watching one between units:
388
+
389
+ ```python
390
+ print(controller.osd_sync) # the last sync it sent
391
+ print(unit.osd_sync_report) # taking, done, failed or deferred, and why
392
+ ```
393
+
394
+ This client can send one too, which every unit then takes:
395
+
396
+ ```python
397
+ from mx_remote import OsdCaption, OsdSyncContent, OsdSyncEntry, OsdSyncImage
398
+ from mx_remote.proto.Constants import OsdCaptionField, OsdSyncWhat
399
+
400
+ seq = await mx.send_osd_sync(OsdSyncContent(
401
+ what=OsdSyncWhat.CAPTIONS,
402
+ entries=(OsdSyncEntry(value=OsdCaption(text='Lobby'), set=OsdCaptionField.TEXT),),
403
+ images=None)) # or four OsdSyncImage, served by this client
404
+ await mx.resend_osd_sync(unit) # one unit again
405
+ await mx.clear_osd_sync() # stop answering for it
406
+ ```
407
+
408
+ Each unit asks for the settings it lacks and takes only those, so this client
409
+ holds the content and answers until it is replaced or cleared, announcing
410
+ itself meanwhile as the mesh's overlay sync manager: a unit waking from power
411
+ save then takes this content rather than the controller's. Logo images are
412
+ served over HTTP from this client, on `logo_port` or a free port. Content a unit
413
+ would refuse is refused before anything is sent; see `send_osd_sync`.
414
+
285
415
  ### Every device at once
286
416
 
287
417
  One broadcast changes settings on every OneIP device of the mesh. Each device
@@ -300,7 +430,44 @@ await mx.set_all_oneip_device_settings(OneIPDeviceSettings(
300
430
  Nothing is cached from it: each device that applies a change reports its
301
431
  settings, and its `oneip_settings` reads that. What every device would ignore is
302
432
  refused rather than sent - no setting at all, one only a device reports about
303
- itself, a profile out of range, or a schedule time that is not a time of day.
433
+ itself, a profile, PTP mode or PTP domain out of range, or a schedule time that
434
+ is not a time of day.
435
+
436
+ ## Unit status and commands
437
+
438
+ A unit on protocol 0x2C reports its health and IP configuration with its
439
+ periodic broadcast, and within a few seconds of a change to its flags, status
440
+ or addresses.
441
+
442
+ ```python
443
+ from mx_remote import UnitFlag
444
+
445
+ status = device.unit_status # None until the unit has reported
446
+ print(status.uptime, status.boot_count, status.reboot_count)
447
+ print(status.network) # address, netmask, gateway, two DNS servers
448
+ print(status.fan_rpm, status.temperatures, status.status_message)
449
+ print(UnitFlag.DHCP in status.flags, status.network_pending)
450
+ ```
451
+
452
+ A unit takes a command only from its mesh controller or a management
453
+ application, which this client announces itself as:
454
+
455
+ ```python
456
+ from mx_remote import UnitNetConfig
457
+
458
+ await device.clear_unit_status()
459
+ await device.upgrade_unit_video_processor(force=False)
460
+ await device.set_unit_network(UnitNetConfig(
461
+ ip='10.1.2.3', netmask='255.255.255.0', gateway='10.1.2.254', dns1='10.1.2.254'))
462
+ await device.confirm_unit_network() # keep it, once the unit reports it
463
+ await device.set_unit_dhcp()
464
+ ```
465
+
466
+ A changed IP configuration applies at once and reverts unless the mesh
467
+ controller confirms it in time; `status.network_pending` says whether it still
468
+ waits. Each command returns False without sending for a device that is not a
469
+ OneIP unit, one below 0x2C, or an address and netmask a unit cannot hold.
470
+ Nothing acknowledges a command: `unit_status` reads what the unit reports next.
304
471
 
305
472
  ## Mesh and firmware
306
473
 
@@ -19,6 +19,12 @@ await output.select_video_source_by_user_name("Blu-ray")
19
19
  await output.select_audio_source(source=0)
20
20
  ```
21
21
 
22
+ On a OneIP output the audio follows the video once the video is routed: a
23
+ separate audio route is dropped, so route the audio after the video to keep the
24
+ two apart. A unit below protocol 0x27 is told the source's audio stream
25
+ instead, since some of those route no audio for "follow the video".
26
+ `audio_source` reads the video source while the audio follows it.
27
+
22
28
  ---
23
29
 
24
30
  [Documentation index](README.md) | [Project README](https://github.com/opdenkamp/mx-remote#readme)