mx-remote 2.0.0__tar.gz → 4.7.3__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 (218) hide show
  1. mx_remote-4.7.3/.claude/settings.local.json +13 -0
  2. {mx_remote-2.0.0 → mx_remote-4.7.3}/.gitignore +1 -0
  3. mx_remote-4.7.3/PKG-INFO +515 -0
  4. mx_remote-4.7.3/README.md +483 -0
  5. mx_remote-4.7.3/hatch_build.py +53 -0
  6. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/Interface.py +1075 -404
  7. mx_remote-4.7.3/mx_remote/Interface.pyi +1056 -0
  8. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/Uid.py +16 -12
  9. mx_remote-4.7.3/mx_remote/Uid.pyi +31 -0
  10. mx_remote-4.7.3/mx_remote/__init__.py +33 -0
  11. mx_remote-4.7.3/mx_remote/__init__.pyi +5 -0
  12. mx_remote-4.7.3/mx_remote/const.py +29 -0
  13. mx_remote-4.7.3/mx_remote/const.pyi +8 -0
  14. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/main.py +39 -33
  15. mx_remote-4.7.3/mx_remote/main.pyi +7 -0
  16. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/BayConfig.py +38 -35
  17. mx_remote-4.7.3/mx_remote/proto/BayConfig.pyi +38 -0
  18. mx_remote-4.7.3/mx_remote/proto/Constants.py +537 -0
  19. mx_remote-4.7.3/mx_remote/proto/Constants.pyi +238 -0
  20. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/Data.py +17 -15
  21. mx_remote-4.7.3/mx_remote/proto/Data.pyi +42 -0
  22. mx_remote-4.7.3/mx_remote/proto/Factory.py +210 -0
  23. mx_remote-4.7.3/mx_remote/proto/Factory.pyi +6 -0
  24. mx_remote-4.7.3/mx_remote/proto/FrameAmpDolbySettings.py +76 -0
  25. mx_remote-4.7.3/mx_remote/proto/FrameAmpDolbySettings.pyi +20 -0
  26. mx_remote-4.7.3/mx_remote/proto/FrameAmpZoneSettings.py +151 -0
  27. mx_remote-4.7.3/mx_remote/proto/FrameAmpZoneSettings.pyi +47 -0
  28. mx_remote-4.7.3/mx_remote/proto/FrameBase.py +155 -0
  29. mx_remote-4.7.3/mx_remote/proto/FrameBase.pyi +46 -0
  30. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameBayConfig.py +17 -17
  31. mx_remote-4.7.3/mx_remote/proto/FrameBayConfig.pyi +10 -0
  32. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameBayConfigSecondary.py +20 -17
  33. mx_remote-4.7.3/mx_remote/proto/FrameBayConfigSecondary.pyi +10 -0
  34. mx_remote-4.7.3/mx_remote/proto/FrameBayHide.py +52 -0
  35. mx_remote-4.7.3/mx_remote/proto/FrameBayHide.pyi +14 -0
  36. mx_remote-4.7.3/mx_remote/proto/FrameBayStatus.py +60 -0
  37. mx_remote-4.7.3/mx_remote/proto/FrameBayStatus.pyi +15 -0
  38. mx_remote-4.7.3/mx_remote/proto/FrameConnectStatus.py +35 -0
  39. mx_remote-4.7.3/mx_remote/proto/FrameConnectStatus.pyi +10 -0
  40. mx_remote-4.7.3/mx_remote/proto/FrameDebug.py +18 -0
  41. mx_remote-4.7.3/mx_remote/proto/FrameDebug.pyi +4 -0
  42. mx_remote-4.7.3/mx_remote/proto/FrameDiscover.py +25 -0
  43. mx_remote-4.7.3/mx_remote/proto/FrameDiscover.pyi +8 -0
  44. mx_remote-4.7.3/mx_remote/proto/FrameEDID.py +23 -0
  45. mx_remote-4.7.3/mx_remote/proto/FrameEDID.pyi +6 -0
  46. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameEDIDProfile.py +7 -8
  47. mx_remote-4.7.3/mx_remote/proto/FrameEDIDProfile.pyi +6 -0
  48. mx_remote-4.7.3/mx_remote/proto/FrameFactoryReset.py +38 -0
  49. mx_remote-4.7.3/mx_remote/proto/FrameFactoryReset.pyi +9 -0
  50. mx_remote-4.7.3/mx_remote/proto/FrameFilterStatus.py +37 -0
  51. mx_remote-4.7.3/mx_remote/proto/FrameFilterStatus.pyi +11 -0
  52. mx_remote-4.7.3/mx_remote/proto/FrameFirmwareVersion.py +55 -0
  53. mx_remote-4.7.3/mx_remote/proto/FrameFirmwareVersion.pyi +17 -0
  54. mx_remote-4.7.3/mx_remote/proto/FrameHeader.py +164 -0
  55. mx_remote-4.7.3/mx_remote/proto/FrameHeader.pyi +42 -0
  56. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameHello.py +39 -33
  57. mx_remote-4.7.3/mx_remote/proto/FrameHello.pyi +25 -0
  58. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameLinks.py +16 -15
  59. mx_remote-4.7.3/mx_remote/proto/FrameLinks.pyi +10 -0
  60. mx_remote-4.7.3/mx_remote/proto/FrameMeshOperation.py +84 -0
  61. mx_remote-4.7.3/mx_remote/proto/FrameMeshOperation.pyi +24 -0
  62. mx_remote-4.7.3/mx_remote/proto/FrameMirrorStatus.py +57 -0
  63. mx_remote-4.7.3/mx_remote/proto/FrameMirrorStatus.pyi +17 -0
  64. mx_remote-4.7.3/mx_remote/proto/FrameMonitoringPulse.py +19 -0
  65. mx_remote-4.7.3/mx_remote/proto/FrameMonitoringPulse.pyi +3 -0
  66. mx_remote-4.7.3/mx_remote/proto/FrameNetworkStatus.py +284 -0
  67. mx_remote-4.7.3/mx_remote/proto/FrameNetworkStatus.pyi +108 -0
  68. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FramePDUState.py +12 -11
  69. mx_remote-4.7.3/mx_remote/proto/FramePDUState.pyi +23 -0
  70. mx_remote-4.7.3/mx_remote/proto/FramePowerChange.py +31 -0
  71. mx_remote-4.7.3/mx_remote/proto/FramePowerChange.pyi +10 -0
  72. mx_remote-4.7.3/mx_remote/proto/FrameRCAction.py +45 -0
  73. mx_remote-4.7.3/mx_remote/proto/FrameRCAction.pyi +13 -0
  74. mx_remote-4.7.3/mx_remote/proto/FrameRCIr.py +29 -0
  75. mx_remote-4.7.3/mx_remote/proto/FrameRCIr.pyi +9 -0
  76. mx_remote-4.7.3/mx_remote/proto/FrameRCKey.py +34 -0
  77. mx_remote-4.7.3/mx_remote/proto/FrameRCKey.pyi +11 -0
  78. mx_remote-4.7.3/mx_remote/proto/FrameRCSettings.py +18 -0
  79. mx_remote-4.7.3/mx_remote/proto/FrameRCSettings.pyi +4 -0
  80. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameReboot.py +9 -14
  81. mx_remote-4.7.3/mx_remote/proto/FrameReboot.pyi +6 -0
  82. mx_remote-4.7.3/mx_remote/proto/FrameRoutingChange.py +46 -0
  83. mx_remote-4.7.3/mx_remote/proto/FrameRoutingChange.pyi +16 -0
  84. mx_remote-4.7.3/mx_remote/proto/FrameSetInstaller.py +24 -0
  85. mx_remote-4.7.3/mx_remote/proto/FrameSetInstaller.pyi +6 -0
  86. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameSetName.py +9 -10
  87. mx_remote-4.7.3/mx_remote/proto/FrameSetName.pyi +6 -0
  88. mx_remote-4.7.3/mx_remote/proto/FrameSetRoute.py +39 -0
  89. mx_remote-4.7.3/mx_remote/proto/FrameSetRoute.pyi +12 -0
  90. mx_remote-4.7.3/mx_remote/proto/FrameSetupStatus.py +29 -0
  91. mx_remote-4.7.3/mx_remote/proto/FrameSetupStatus.pyi +6 -0
  92. mx_remote-4.7.3/mx_remote/proto/FrameSignalStatus.py +38 -0
  93. mx_remote-4.7.3/mx_remote/proto/FrameSignalStatus.pyi +12 -0
  94. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameSignalStatusNew.py +86 -83
  95. mx_remote-4.7.3/mx_remote/proto/FrameSignalStatusNew.pyi +109 -0
  96. mx_remote-4.7.3/mx_remote/proto/FrameSysTemperature.py +41 -0
  97. mx_remote-4.7.3/mx_remote/proto/FrameSysTemperature.pyi +10 -0
  98. mx_remote-4.7.3/mx_remote/proto/FrameSystemStatus.py +31 -0
  99. mx_remote-4.7.3/mx_remote/proto/FrameSystemStatus.pyi +10 -0
  100. mx_remote-4.7.3/mx_remote/proto/FrameTXRCAction.py +58 -0
  101. mx_remote-4.7.3/mx_remote/proto/FrameTXRCAction.pyi +20 -0
  102. mx_remote-4.7.3/mx_remote/proto/FrameTopology.py +54 -0
  103. mx_remote-4.7.3/mx_remote/proto/FrameTopology.pyi +16 -0
  104. mx_remote-4.7.3/mx_remote/proto/FrameTxIR.py +79 -0
  105. mx_remote-4.7.3/mx_remote/proto/FrameTxIR.pyi +25 -0
  106. mx_remote-4.7.3/mx_remote/proto/FrameUpgradeFPGA.py +19 -0
  107. mx_remote-4.7.3/mx_remote/proto/FrameUpgradeFPGA.pyi +3 -0
  108. mx_remote-4.7.3/mx_remote/proto/FrameV2IPAudio.py +876 -0
  109. mx_remote-4.7.3/mx_remote/proto/FrameV2IPAudio.pyi +272 -0
  110. mx_remote-4.7.3/mx_remote/proto/FrameV2IPBayMapping.py +74 -0
  111. mx_remote-4.7.3/mx_remote/proto/FrameV2IPBayMapping.pyi +21 -0
  112. mx_remote-4.7.3/mx_remote/proto/FrameV2IPDeviceConfiguration.py +108 -0
  113. mx_remote-4.7.3/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +39 -0
  114. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameV2IPLink.py +3 -5
  115. mx_remote-4.7.3/mx_remote/proto/FrameV2IPLink.pyi +3 -0
  116. mx_remote-4.7.3/mx_remote/proto/FrameV2IPManualSourceSwitch.py +116 -0
  117. mx_remote-4.7.3/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +28 -0
  118. mx_remote-4.7.3/mx_remote/proto/FrameV2IPMultiviewer.py +396 -0
  119. mx_remote-4.7.3/mx_remote/proto/FrameV2IPMultiviewer.pyi +110 -0
  120. mx_remote-4.7.3/mx_remote/proto/FrameV2IPPowerSave.py +47 -0
  121. mx_remote-4.7.3/mx_remote/proto/FrameV2IPPowerSave.pyi +12 -0
  122. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameV2IPSetMaster.py +3 -5
  123. mx_remote-4.7.3/mx_remote/proto/FrameV2IPSetMaster.pyi +3 -0
  124. mx_remote-4.7.3/mx_remote/proto/FrameV2IPSourceSwitch.py +98 -0
  125. mx_remote-4.7.3/mx_remote/proto/FrameV2IPSourceSwitch.pyi +22 -0
  126. mx_remote-4.7.3/mx_remote/proto/FrameV2IPSources.py +44 -0
  127. mx_remote-4.7.3/mx_remote/proto/FrameV2IPSources.pyi +11 -0
  128. mx_remote-4.7.3/mx_remote/proto/FrameV2IPStats.py +80 -0
  129. mx_remote-4.7.3/mx_remote/proto/FrameV2IPStats.pyi +23 -0
  130. mx_remote-4.7.3/mx_remote/proto/FrameV2IPStreamDetails.py +60 -0
  131. mx_remote-4.7.3/mx_remote/proto/FrameV2IPStreamDetails.pyi +17 -0
  132. mx_remote-4.7.3/mx_remote/proto/FrameV2IPTiling.py +50 -0
  133. mx_remote-4.7.3/mx_remote/proto/FrameV2IPTiling.pyi +18 -0
  134. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/FrameVolume.py +23 -22
  135. mx_remote-4.7.3/mx_remote/proto/FrameVolume.pyi +15 -0
  136. mx_remote-4.7.3/mx_remote/proto/FrameVolumeDown.py +26 -0
  137. mx_remote-4.7.3/mx_remote/proto/FrameVolumeDown.pyi +9 -0
  138. mx_remote-4.7.3/mx_remote/proto/FrameVolumeSet.py +85 -0
  139. mx_remote-4.7.3/mx_remote/proto/FrameVolumeSet.pyi +22 -0
  140. mx_remote-4.7.3/mx_remote/proto/FrameVolumeUp.py +26 -0
  141. mx_remote-4.7.3/mx_remote/proto/FrameVolumeUp.pyi +9 -0
  142. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/LinkConfig.py +36 -22
  143. mx_remote-4.7.3/mx_remote/proto/LinkConfig.pyi +37 -0
  144. mx_remote-4.7.3/mx_remote/proto/Multiviewer.py +360 -0
  145. mx_remote-4.7.3/mx_remote/proto/Multiviewer.pyi +208 -0
  146. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/PDUState.py +19 -14
  147. mx_remote-4.7.3/mx_remote/proto/PDUState.pyi +29 -0
  148. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/Svd.py +19 -7
  149. mx_remote-4.7.3/mx_remote/proto/Svd.pyi +28 -0
  150. mx_remote-4.7.3/mx_remote/proto/V2IPConfig.py +133 -0
  151. mx_remote-4.7.3/mx_remote/proto/V2IPConfig.pyi +55 -0
  152. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/V2IPStats.py +34 -10
  153. mx_remote-4.7.3/mx_remote/proto/V2IPStats.pyi +50 -0
  154. mx_remote-4.7.3/mx_remote/proto/__init__.py +16 -0
  155. mx_remote-4.7.3/mx_remote/proto/__init__.pyi +1 -0
  156. mx_remote-4.7.3/mx_remote/py.typed +0 -0
  157. mx_remote-4.7.3/mx_remote/remote/Bay.py +1170 -0
  158. mx_remote-4.7.3/mx_remote/remote/Bay.pyi +314 -0
  159. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/remote/ConnectionAsync.py +25 -11
  160. mx_remote-4.7.3/mx_remote/remote/ConnectionAsync.pyi +25 -0
  161. mx_remote-4.7.3/mx_remote/remote/Device.py +1088 -0
  162. mx_remote-4.7.3/mx_remote/remote/Device.pyi +230 -0
  163. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/remote/Link.py +68 -70
  164. mx_remote-4.7.3/mx_remote/remote/Link.pyi +33 -0
  165. mx_remote-2.0.0/mx_remote/remote/PDU.py → mx_remote-4.7.3/mx_remote/remote/P8PDU.py +23 -19
  166. mx_remote-4.7.3/mx_remote/remote/P8PDU.pyi +46 -0
  167. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/remote/Remote.py +135 -54
  168. mx_remote-4.7.3/mx_remote/remote/Remote.pyi +70 -0
  169. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/remote/State.py +6 -1
  170. mx_remote-4.7.3/mx_remote/remote/State.pyi +9 -0
  171. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/remote/V2IP.py +16 -10
  172. mx_remote-4.7.3/mx_remote/remote/V2IP.pyi +28 -0
  173. {mx_remote-2.0.0 → mx_remote-4.7.3}/pyproject.toml +8 -5
  174. mx_remote-2.0.0/PKG-INFO +0 -90
  175. mx_remote-2.0.0/README.md +0 -58
  176. mx_remote-2.0.0/mx_remote/__init__.py +0 -12
  177. mx_remote-2.0.0/mx_remote/api/BayConfig.py +0 -53
  178. mx_remote-2.0.0/mx_remote/api/__init__.py +0 -8
  179. mx_remote-2.0.0/mx_remote/const.py +0 -20
  180. mx_remote-2.0.0/mx_remote/proto/Constants.py +0 -382
  181. mx_remote-2.0.0/mx_remote/proto/Factory.py +0 -168
  182. mx_remote-2.0.0/mx_remote/proto/FrameAmpDolbySettings.py +0 -51
  183. mx_remote-2.0.0/mx_remote/proto/FrameAmpZoneSettings.py +0 -123
  184. mx_remote-2.0.0/mx_remote/proto/FrameBase.py +0 -80
  185. mx_remote-2.0.0/mx_remote/proto/FrameBayHide.py +0 -53
  186. mx_remote-2.0.0/mx_remote/proto/FrameBayStatus.py +0 -51
  187. mx_remote-2.0.0/mx_remote/proto/FrameConnectStatus.py +0 -38
  188. mx_remote-2.0.0/mx_remote/proto/FrameDiscover.py +0 -21
  189. mx_remote-2.0.0/mx_remote/proto/FrameEDID.py +0 -20
  190. mx_remote-2.0.0/mx_remote/proto/FrameFilterStatus.py +0 -39
  191. mx_remote-2.0.0/mx_remote/proto/FrameFirmwareVersion.py +0 -40
  192. mx_remote-2.0.0/mx_remote/proto/FrameHeader.py +0 -92
  193. mx_remote-2.0.0/mx_remote/proto/FrameMeshOperation.py +0 -66
  194. mx_remote-2.0.0/mx_remote/proto/FrameMirrorStatus.py +0 -49
  195. mx_remote-2.0.0/mx_remote/proto/FrameNetworkStatus.py +0 -163
  196. mx_remote-2.0.0/mx_remote/proto/FramePowerChange.py +0 -38
  197. mx_remote-2.0.0/mx_remote/proto/FrameRCAction.py +0 -50
  198. mx_remote-2.0.0/mx_remote/proto/FrameRCIr.py +0 -17
  199. mx_remote-2.0.0/mx_remote/proto/FrameRCKey.py +0 -40
  200. mx_remote-2.0.0/mx_remote/proto/FrameRoutingChange.py +0 -66
  201. mx_remote-2.0.0/mx_remote/proto/FrameSignalStatus.py +0 -46
  202. mx_remote-2.0.0/mx_remote/proto/FrameSysTemperature.py +0 -50
  203. mx_remote-2.0.0/mx_remote/proto/FrameTXRCAction.py +0 -58
  204. mx_remote-2.0.0/mx_remote/proto/FrameTopology.py +0 -36
  205. mx_remote-2.0.0/mx_remote/proto/FrameV2IPDeviceConfiguration.py +0 -86
  206. mx_remote-2.0.0/mx_remote/proto/FrameV2IPSourceSwitch.py +0 -84
  207. mx_remote-2.0.0/mx_remote/proto/FrameV2IPSources.py +0 -43
  208. mx_remote-2.0.0/mx_remote/proto/FrameV2IPStats.py +0 -55
  209. mx_remote-2.0.0/mx_remote/proto/FrameV2IPStreamDetails.py +0 -46
  210. mx_remote-2.0.0/mx_remote/proto/FrameVolumeDown.py +0 -28
  211. mx_remote-2.0.0/mx_remote/proto/FrameVolumeSet.py +0 -81
  212. mx_remote-2.0.0/mx_remote/proto/FrameVolumeUp.py +0 -28
  213. mx_remote-2.0.0/mx_remote/proto/V2IPConfig.py +0 -71
  214. mx_remote-2.0.0/mx_remote/proto/__init__.py +0 -8
  215. mx_remote-2.0.0/mx_remote/remote/Bay.py +0 -923
  216. mx_remote-2.0.0/mx_remote/remote/Device.py +0 -530
  217. {mx_remote-2.0.0 → mx_remote-4.7.3}/LICENSE +0 -0
  218. {mx_remote-2.0.0 → mx_remote-4.7.3}/mx_remote/proto/svd.csv +0 -0
@@ -0,0 +1,13 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(scp *)",
5
+ "Bash(ssh hass@home '~/venv-hass/bin/pip install --upgrade /tmp/mx_remote-4.3.0-py3-none-any.whl')",
6
+ "Bash(ssh hass@home *)",
7
+ "Bash(git reset *)",
8
+ "Bash(mount)",
9
+ "Bash(curl -s -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1ZTU3MjI0Zjc3ZjQ0OWVkYjEzMzU5YjAyMTMzN2IzMiIsImlhdCI6MTc3NTQ4MjM0NiwiZXhwIjoyMDkwODQyMzQ2fQ.EzuPwl8JfzUFkWQIczcKGc_bUEfKKzXfday8t7EB93M' http://10.8.100.5:8123/api/states/media_player.video_output_kantoor)",
10
+ "Bash(git pull *)"
11
+ ]
12
+ }
13
+ }
@@ -2,3 +2,4 @@ __pycache__
2
2
  /build
3
3
  /dist
4
4
  *.egg-info
5
+ *.pyi
@@ -0,0 +1,515 @@
1
+ Metadata-Version: 2.4
2
+ Name: mx_remote
3
+ Version: 4.7.3
4
+ Summary: Python 3 library for interfacing with MX Remote compatible devices
5
+ Project-URL: Homepage, https://github.com/opdenkamp/mx-remote/
6
+ Project-URL: Documentation, https://github.com/opdenkamp/mx-remote/
7
+ Project-URL: Repository, https://github.com/opdenkamp/mx-remote.git
8
+ Project-URL: Bug Tracker, https://github.com/opdenkamp/mx-remote/issues
9
+ Author-email: Lars Op den Kamp <lars@opdenkamp.eu>
10
+ Maintainer-email: Lars Op den Kamp <lars@opdenkamp.eu>
11
+ License: Copyright 2024 Lars Op den Kamp <lars@opdenkamp.eu>
12
+
13
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
14
+
15
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
16
+
17
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
18
+
19
+ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
+ License-File: LICENSE
23
+ Keywords: ampos,matrixos,oneip,pulse-eight
24
+ Classifier: Development Status :: 3 - Alpha
25
+ Classifier: Programming Language :: Python
26
+ Classifier: Topic :: System :: Networking :: Monitoring
27
+ Requires-Python: >=3.11
28
+ Requires-Dist: aiofiles>=24.1.0
29
+ Requires-Dist: aiohttp>=3.10.5
30
+ Requires-Dist: netifaces>=0.11.0
31
+ Description-Content-Type: text/markdown
32
+
33
+ # MX Remote Interface
34
+
35
+ Python 3 library for interfacing with [MX Remote](https://github.com/opdenkamp/mx-remote/) compatible devices over a local network. Supports device discovery, video/audio routing, volume control, remote control key passthrough, V2IP (OneIP) streaming, and more.
36
+
37
+ ## Requirements
38
+
39
+ - Python 3.11 or later
40
+ - Network access to MX Remote compatible devices (multicast or broadcast)
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install .
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ The minimum code to discover devices on the network:
51
+
52
+ ```python
53
+ import asyncio
54
+ import mx_remote
55
+
56
+ async def main():
57
+ mx = mx_remote.Remote()
58
+ await mx.start_async()
59
+
60
+ # wait for devices to be discovered
61
+ await asyncio.sleep(5)
62
+
63
+ for uid, device in mx.remotes.items():
64
+ print(f"{device.serial} ({device.name}) - {device.model_name} - {device.status}")
65
+ for port, bay in device.bays.items():
66
+ print(f" {bay.bay_label} [{bay.mode}] signal={bay.signal_detected}")
67
+
68
+ await mx.close()
69
+
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ ## Core Concepts
74
+
75
+ ### Remote
76
+
77
+ `Remote` is the main entry point. It manages the UDP connection (multicast or broadcast), handles device discovery, and maintains a registry of all discovered devices.
78
+
79
+ ```python
80
+ # default: multicast on 224.8.8.8:8812
81
+ mx = mx_remote.Remote()
82
+
83
+ # use broadcast instead
84
+ mx = mx_remote.Remote(broadcast=True)
85
+
86
+ # bind to a specific network interface
87
+ mx = mx_remote.Remote(local_ip="192.168.1.100")
88
+
89
+ # custom target address and port
90
+ mx = mx_remote.Remote(target_ip="10.8.8.255", port=8811)
91
+
92
+ # offline mode for processing capture files
93
+ mx = mx_remote.Remote(open_connection=False)
94
+ ```
95
+
96
+ ### Device
97
+
98
+ A `DeviceBase` represents a physical device on the network (matrix, OneIP unit, amplifier). Devices are automatically registered when they respond to discovery requests.
99
+
100
+ ```python
101
+ # look up a device by serial number or unique ID
102
+ device = mx.get_by_serial("AB1234")
103
+ device = mx.get_by_uid(uid)
104
+
105
+ # device properties
106
+ device.serial # serial number
107
+ device.name # device name
108
+ device.model_name # model (e.g. "neo:8", "OneIP Transmitter")
109
+ device.address # IP address
110
+ device.version # firmware version
111
+ device.online # True if responding
112
+ device.status # DeviceStatus enum (ONLINE, OFFLINE, REBOOTING, BOOTING, INACTIVE)
113
+ device.features # DeviceFeatures bitmask
114
+ device.temperatures # dict of temperature sensor readings
115
+
116
+ # device type checks
117
+ device.is_v2ip # OneIP device
118
+ device.is_video_matrix # video matrix
119
+ device.is_audio_matrix # audio-only matrix
120
+ device.is_amp # audio amplifier
121
+ device.is_oneip_tx # OneIP transmitter
122
+ device.is_oneip_rx # OneIP receiver
123
+ device.is_oneip_tz # OneIP transceiver
124
+ device.is_oneip_multiviewer # OneIP multiviewer
125
+
126
+ # iterate bays
127
+ for port, bay in device.bays.items():
128
+ print(bay)
129
+ for name, bay in device.inputs.items():
130
+ print(f"Input: {name}")
131
+ for name, bay in device.outputs.items():
132
+ print(f"Output: {name}")
133
+ ```
134
+
135
+ ### Bay
136
+
137
+ A `BayBase` represents a single input or output on a device (e.g. "Input 1", "Output 3").
138
+
139
+ ```python
140
+ bay.bay_name # port name (e.g. "Input 1")
141
+ bay.user_name # user-assigned name
142
+ bay.is_input # True if source/input
143
+ bay.is_output # True if sink/output
144
+ bay.is_hdmi # True if HDMI
145
+ bay.is_audio # True if audio-only
146
+ bay.is_hdbaset # True if HDBaseT
147
+ bay.signal_detected # video/audio signal present
148
+ bay.power_status # PowerStatus enum (ON, OFF, UNKNOWN)
149
+ bay.faulty # fault detected
150
+ bay.hidden # hidden from UI
151
+ bay.online # device is online
152
+ bay.features # BayFeaturesMask
153
+ bay.status # DeviceStatus enum
154
+
155
+ # video/audio routing (output bays)
156
+ bay.video_source # currently selected video source bay
157
+ bay.audio_source # currently selected audio source bay
158
+ bay.available_video_sources # list of selectable video sources
159
+ bay.available_audio_sources # list of selectable audio sources
160
+
161
+ # volume (bays with volume control)
162
+ bay.volume # current volume percentage (or None)
163
+ bay.muted # True if muted (or None)
164
+
165
+ # EDID and remote control (input bays)
166
+ bay.edid_profile # EdidProfile enum
167
+ bay.rc_type # RCType enum (IR, CEC, Sky, TiVo, etc.)
168
+ ```
169
+
170
+ ## Callbacks
171
+
172
+ Subclass `MxrCallbacks` to receive notifications when device or bay state changes:
173
+
174
+ ```python
175
+ class MyCallbacks(mx_remote.MxrCallbacks):
176
+ def on_device_config_complete(self, dev):
177
+ print(f"Device ready: {dev.serial} ({dev.name})")
178
+
179
+ def on_bay_registered(self, bay):
180
+ print(f"Bay found: {bay.bay_label}")
181
+
182
+ def on_video_source_changed(self, bay, video_source):
183
+ print(f"{bay.user_name} video source -> {video_source.user_name}")
184
+
185
+ def on_audio_source_changed(self, bay, audio_source):
186
+ print(f"{bay.user_name} audio source -> {audio_source.user_name}")
187
+
188
+ def on_volume_changed(self, bay, volume):
189
+ print(f"{bay.user_name} volume: {volume}")
190
+
191
+ def on_power_changed(self, bay, power):
192
+ print(f"{bay.user_name} power: {power}")
193
+
194
+ def on_device_online_status_changed(self, dev, online):
195
+ print(f"{dev.serial} {'online' if online else 'offline'}")
196
+
197
+ mx = mx_remote.Remote(callbacks=MyCallbacks())
198
+ ```
199
+
200
+ Available callback methods:
201
+
202
+ | Method | Trigger |
203
+ |---|---|
204
+ | `on_device_update` | any device property changed |
205
+ | `on_bay_update` | any bay property changed |
206
+ | `on_device_config_changed` | device configuration updated |
207
+ | `on_device_config_complete` | all device configuration received |
208
+ | `on_device_online_status_changed` | device went online/offline |
209
+ | `on_device_temperature_changed` | temperature readings changed |
210
+ | `on_bay_registered` | new bay discovered |
211
+ | `on_video_source_changed` | video routing changed |
212
+ | `on_audio_source_changed` | audio routing changed |
213
+ | `on_volume_changed` | volume or mute status changed |
214
+ | `on_power_changed` | CEC power status changed |
215
+ | `on_name_changed` | user-assigned bay name changed |
216
+ | `on_status_signal_detected_changed` | signal detect status changed |
217
+ | `on_status_faulty_changed` | fault status changed |
218
+ | `on_status_hidden_changed` | hidden status changed |
219
+ | `on_status_poe_powered_changed` | PoE power status changed |
220
+ | `on_status_hdbt_connected_changed` | HDBaseT link status changed |
221
+ | `on_status_signal_type_changed` | signal type changed |
222
+ | `on_status_hpd_detected_changed` | hotplug detect changed |
223
+ | `on_status_cec_detected_changed` | CEC device detected/lost |
224
+ | `on_status_arc_changed` | audio return channel status changed |
225
+ | `on_key_pressed` | remote control key press received |
226
+ | `on_action_received` | remote control action received |
227
+ | `on_bay_linked` | virtual link created |
228
+ | `on_bay_unlinked` | virtual link removed |
229
+ | `on_mirror_status_changed` | bay mirroring changed |
230
+ | `on_filter_status_changed` | bay filtering changed |
231
+ | `on_edid_profile_changed` | EDID profile changed |
232
+ | `on_rc_type_changed` | remote control type changed |
233
+ | `on_amp_zone_settings_changed` | amplifier zone settings changed |
234
+ | `on_amp_dolby_settings_changed` | amplifier Dolby settings changed |
235
+
236
+ You can also register per-device and per-bay callbacks:
237
+
238
+ ```python
239
+ def on_device_changed(device):
240
+ print(f"{device.serial} updated")
241
+
242
+ def on_bay_changed(bay):
243
+ print(f"{bay.bay_label} updated")
244
+
245
+ device.register_callback(on_device_changed)
246
+ bay.register_callback(on_bay_changed)
247
+
248
+ # to unregister:
249
+ device.unregister_callback(on_device_changed)
250
+ bay.unregister_callback(on_bay_changed)
251
+ ```
252
+
253
+ ## Video and Audio Routing
254
+
255
+ Change video and audio sources on output bays:
256
+
257
+ ```python
258
+ output = device.get_by_portname("Output 1")
259
+
260
+ # switch video source by port number
261
+ await output.select_video_source(port=0)
262
+
263
+ # switch video source by user-assigned name
264
+ await output.select_video_source_by_user_name("Blu-ray")
265
+
266
+ # switch audio source
267
+ await output.select_audio_source(source=0)
268
+ ```
269
+
270
+ ## Volume Control
271
+
272
+ ```python
273
+ bay.volume_up()
274
+ bay.volume_down()
275
+ bay.volume_set(volume=50) # set to 50%
276
+ bay.volume_set(volume=50, muted=False)
277
+ bay.mute_set(mute=True)
278
+ ```
279
+
280
+ ## Remote Control
281
+
282
+ Send remote control key presses and actions:
283
+
284
+ ```python
285
+ from mx_remote import RCKey, RCAction
286
+
287
+ # send a key press
288
+ await bay.send_key(RCKey.KEY_SELECT)
289
+ await bay.send_key(RCKey.KEY_UP)
290
+
291
+ # send a remote control action
292
+ await bay.tx_action(RCAction.ACTION_POWER_ON)
293
+ await bay.tx_action(RCAction.ACTION_POWER_OFF)
294
+ await bay.tx_action(RCAction.ACTION_POWER_TOGGLE)
295
+ await bay.tx_action(RCAction.ACTION_VOLUME_UP)
296
+ await bay.tx_action(RCAction.ACTION_VOLUME_DOWN)
297
+ ```
298
+
299
+ ## EDID Profiles
300
+
301
+ Change the EDID profile on input bays:
302
+
303
+ ```python
304
+ from mx_remote import EdidProfile
305
+
306
+ await bay.select_edid_profile(EdidProfile.TEMPLATE_1080P_STEREO)
307
+ await bay.select_edid_profile(EdidProfile.TEMPLATE_4K_HDR_7_1)
308
+ await bay.select_edid_profile(EdidProfile.LOWEST_COMMON_DENOMINATOR)
309
+ ```
310
+
311
+ ## Bay Visibility
312
+
313
+ Hide or show bays:
314
+
315
+ ```python
316
+ await bay.set_hidden(True) # hide
317
+ await bay.set_hidden(False) # show
318
+ ```
319
+
320
+ ## Bay Naming
321
+
322
+ ```python
323
+ await bay.set_name("Living Room TV")
324
+ ```
325
+
326
+ ## Device Management
327
+
328
+ ```python
329
+ # reboot a device
330
+ await device.reboot()
331
+
332
+ # read the device log
333
+ log = await device.get_log()
334
+
335
+ # call an HTTP API endpoint on the device
336
+ result = await device.get_api("system/status")
337
+ ```
338
+
339
+ ## OneIP (V2IP) Devices
340
+
341
+ OneIP devices expose additional streaming properties:
342
+
343
+ ```python
344
+ # V2IP stream source addresses
345
+ if device.is_v2ip and device.v2ip_sources:
346
+ for source in device.v2ip_sources:
347
+ print(f"Video: {source.video.ip}:{source.video.port}")
348
+ print(f"Audio: {source.audio.ip}:{source.audio.port}")
349
+
350
+ # V2IP device details (encoder/decoder config)
351
+ if device.v2ip_details:
352
+ details = device.v2ip_details
353
+ print(f"Video: {details.video}")
354
+ print(f"TX rate: {details.tx_rate}")
355
+
356
+ # V2IP statistics
357
+ await device.read_stats(enable=True) # start collecting
358
+ # ... later ...
359
+ stats = device.v2ip_stats
360
+
361
+ # mesh operations
362
+ await device.mesh_promote() # promote to mesh master
363
+ await device.mesh_remove() # remove from mesh
364
+
365
+ # firmware versions
366
+ if device.v2ip_firmware_versions:
367
+ for fw_type, fw in device.v2ip_firmware_versions.items():
368
+ print(f"{fw_type}: {fw.version}")
369
+ ```
370
+
371
+ ## OneIP Multiviewer
372
+
373
+ Control multiviewer-specific settings:
374
+
375
+ ```python
376
+ from mx_remote import (
377
+ MultiviewerViewMode,
378
+ MultiviewerSource,
379
+ MultiviewerEDIDTemplate,
380
+ MultiviewerPipSize,
381
+ MultiviewerPipPosition,
382
+ MultiviewerAspectRatio,
383
+ MultiviewerOutputMode,
384
+ )
385
+
386
+ mv = device.multiviewer
387
+
388
+ # view mode
389
+ await mv.set_view_mode(MultiviewerViewMode.QUAD)
390
+
391
+ # video sources per screen
392
+ await mv.set_video_source(screen=0, source=MultiviewerSource.INPUT_1)
393
+
394
+ # audio
395
+ await mv.set_audio_source(source=MultiviewerSource.INPUT_1)
396
+ await mv.set_audio_volume(volume=80, muted=False)
397
+
398
+ # picture-in-picture
399
+ await mv.set_pip_size(MultiviewerPipSize.MEDIUM)
400
+ await mv.set_pip_position(MultiviewerPipPosition.BOTTOM_RIGHT)
401
+
402
+ # output settings
403
+ await mv.set_screen_aspect(MultiviewerAspectRatio.AR_16_9)
404
+ await mv.set_output_mode(MultiviewerOutputMode.MODE_1080P_60)
405
+ await mv.set_edid_template(MultiviewerEDIDTemplate.TEMPLATE_1080P)
406
+
407
+ # auto switching and HDCP
408
+ await mv.set_auto_switch(enable=True)
409
+ await mv.set_hdcp_mode(MultiviewerHDCPMode.AUTO)
410
+
411
+ # source mapping
412
+ await mv.set_connected_source(input=0, source=some_device_uid)
413
+ await mv.auto_route()
414
+ ```
415
+
416
+ ## Network Status
417
+
418
+ Inspect network port details on supported devices:
419
+
420
+ ```python
421
+ for port_id, port_status in device.network_status.items():
422
+ print(f"Port {port_status.name}: {port_status.link_speed} "
423
+ f"{'full' if port_status.link_full_duplex else 'half'} duplex")
424
+ if port_status.ip:
425
+ print(f" IP: {port_status.ip}")
426
+ if port_status.mac_address:
427
+ print(f" MAC: {port_status.mac_address}")
428
+ ```
429
+
430
+ ## Configuration Updates
431
+
432
+ Update connection settings at runtime:
433
+
434
+ ```python
435
+ await mx.update_config(
436
+ target_ip="10.8.8.255",
437
+ port=8811,
438
+ local_ip="192.168.1.100",
439
+ broadcast=True,
440
+ callbacks=MyCallbacks(),
441
+ name="My Application",
442
+ )
443
+ ```
444
+
445
+ ## CLI Application
446
+
447
+ The `mxr` console application is installed with the package. It discovers devices and logs all received frames in human-readable form.
448
+
449
+ ```
450
+ usage: mxr [-h] [-i INPUT] [-f FILTER] [-o OUTPUT] [-l LOCAL_IP] [-b]
451
+
452
+ MX Remote Manager / Debugger
453
+
454
+ options:
455
+ -h, --help show this help message and exit
456
+ -i INPUT capture file to process
457
+ -f FILTER only log frames from this ip address
458
+ -o OUTPUT write output to a file
459
+ -l LOCAL_IP local ip address of the network interface to use
460
+ -b use broadcast mode instead of multicast
461
+ ```
462
+
463
+ ### Examples
464
+
465
+ ```bash
466
+ # discover devices and log frames to console
467
+ mxr
468
+
469
+ # bind to a specific network interface
470
+ mxr -l 192.168.1.100
471
+
472
+ # use broadcast mode
473
+ mxr -b
474
+
475
+ # log output to a file
476
+ mxr -o /path/to/output.txt
477
+
478
+ # process a capture file from MatrixOS
479
+ mxr -i /path/to/capture.bin
480
+
481
+ # process a capture file, filtering by IP address
482
+ mxr -i /path/to/capture.bin -f 10.8.8.1
483
+ ```
484
+
485
+ ## Programmatic Capture Processing
486
+
487
+ Process captured frames without a network connection:
488
+
489
+ ```python
490
+ import mx_remote
491
+
492
+ mx_remote.proto_parser(
493
+ logger=my_logger,
494
+ file="/path/to/capture.bin",
495
+ filter="10.8.8.1", # optional IP filter
496
+ )
497
+ ```
498
+
499
+ ## API Documentation
500
+
501
+ Documentation is embedded in the Python code via docstrings. Most IDEs will display it automatically.
502
+
503
+ You can also use Python to browse the documentation:
504
+
505
+ ```python
506
+ import mx_remote
507
+ help(mx_remote.Remote)
508
+ help(mx_remote.BayBase)
509
+ help(mx_remote.DeviceBase)
510
+ help(mx_remote.MxrCallbacks)
511
+ ```
512
+
513
+ ## License
514
+
515
+ BSD 3-Clause License. See [LICENSE](LICENSE) for details.