mx-remote 5.11.0__tar.gz → 6.2.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.
- {mx_remote-5.11.0 → mx_remote-6.2.0}/AGENTS.md +11 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/PKG-INFO +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/README.md +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/README.md +1 -1
- mx_remote-6.2.0/docs/api.md +167 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/audio.md +20 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/configuration.md +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/oneip.md +113 -38
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/Interface.py +442 -160
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/Interface.pyi +158 -72
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/__init__.py +8 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/const.py +4 -4
- mx_remote-6.2.0/mx_remote/deprecated.py +80 -0
- mx_remote-6.2.0/mx_remote/deprecated.pyi +16 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Constants.py +186 -58
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Constants.pyi +77 -21
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Factory.py +3 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayStatus.py +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMeshOperation.py +11 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMeshOperation.pyi +3 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMirrorStatus.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTimeZone.py +12 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTimeZone.pyi +2 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameUpgradeFPGA.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPAudio.py +66 -12
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPAudio.pyi +25 -5
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPBayMapping.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPDetectBays.py +4 -4
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +99 -41
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +15 -11
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPLink.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +9 -9
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +4 -4
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPMultiviewer.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPPowerSave.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSetMaster.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSettingsAll.py +6 -6
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSettingsAll.pyi +3 -3
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSourceSwitch.py +10 -10
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSources.py +8 -8
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSources.pyi +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPStats.py +6 -6
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPStats.pyi +2 -2
- mx_remote-6.2.0/mx_remote/proto/FrameV2IPTestcard.py +107 -0
- mx_remote-6.2.0/mx_remote/proto/FrameV2IPTestcard.pyi +28 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPTiling.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPVideoWall.py +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/V2IPConfig.py +19 -19
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/V2IPConfig.pyi +12 -12
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/V2IPStats.py +11 -5
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/V2IPStats.pyi +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Bay.py +38 -38
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Bay.pyi +11 -11
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Device.py +316 -138
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Device.pyi +49 -34
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Remote.py +29 -18
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Remote.pyi +4 -3
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/V2IP.py +13 -13
- mx_remote-6.2.0/mx_remote/remote/V2IP.pyi +28 -0
- mx_remote-6.2.0/tests/audiolock.py +119 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/complete.py +7 -7
- mx_remote-6.2.0/tests/deprecated.py +205 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/e2e.py +4 -4
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/handlers.py +2 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/handlers_cover.py +16 -16
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/merge.py +16 -10
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/mesh.py +74 -21
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/ping.py +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/proto_stamp.py +1 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/run.py +4 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/smoke.py +8 -8
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/sources.py +2 -2
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/stats.py +3 -3
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/txresult.py +7 -7
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/unknowns.py +1 -1
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/v2ipscaling.py +76 -25
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/v2ipsettings.py +54 -54
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/v2ipsubject.py +36 -36
- mx_remote-6.2.0/tests/v2iptestcard.py +179 -0
- mx_remote-6.2.0/tests/v2ipvlan.py +152 -0
- mx_remote-5.11.0/docs/api.md +0 -95
- mx_remote-5.11.0/mx_remote/remote/V2IP.pyi +0 -28
- {mx_remote-5.11.0 → mx_remote-6.2.0}/.gitignore +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/CLAUDE.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/LICENSE +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/_static/brand.css +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/_static/favicon.svg +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/_static/logo-dark.svg +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/_static/logo.svg +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/callbacks.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/conf.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/devices-and-bays.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/diagnostics.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/index.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/multiviewer.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/requirements.txt +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/docs/routing.md +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/hatch_build.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/Uid.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/Uid.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/__init__.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/compat.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/compat.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/const.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/main.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/main.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/BayConfig.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/BayConfig.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Data.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Data.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Factory.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAudioClip.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAudioClip.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAudioSetRoute.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameAudioSetRoute.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBase.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBase.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayConfig.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayConfig.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayHide.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayHide.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameBayStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameConnectStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameDebug.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameDebug.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameDiscover.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameDiscover.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameEDID.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameEDID.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameEDIDProfile.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFactoryReset.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFactoryReset.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFilterStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFirmwareVersion.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameFirmwareVersion.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameHeader.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameHeader.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameHello.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameHello.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameLinks.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameLinks.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMonitoringPulse.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameNetworkStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FramePing.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FramePing.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FramePowerChange.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FramePowerChange.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCAction.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCAction.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCIr.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCIr.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCKey.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCKey.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCSettings.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRCSettings.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameReboot.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameReboot.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRoutingChange.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetInstaller.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetName.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetName.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetRoute.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetRoute.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetupStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSignalStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSignalStatusNew.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSysTemperature.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSystemStatus.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTXRCAction.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTXRCKey.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTime.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTime.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTopology.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTopology.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTxIR.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameTxIR.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolume.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolume.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeDown.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeSet.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeUp.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/LinkConfig.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/LinkConfig.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Multiviewer.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Multiviewer.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Svd.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/Svd.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/__init__.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/__init__.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/proto/svd.csv +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/py.typed +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/ConnectionAsync.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/ConnectionAsync.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Link.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/Link.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/State.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/mx_remote/remote/State.pyi +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/pyproject.toml +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/audio_ir.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/capture.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/entry.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/hello.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/idempotent.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/lengths.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/newops.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/offline.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/offsets.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/protogate.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/rcsettings.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/roundtrip.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/structs.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/vdetails.py +0 -0
- {mx_remote-5.11.0 → mx_remote-6.2.0}/tests/wirefix.py +0 -0
|
@@ -163,6 +163,17 @@ A 24-byte header, then the payload:
|
|
|
163
163
|
|
|
164
164
|
Built by `proto/Factory.py::create_mxr_frame`, decoded by `proto/FrameHeader.py`.
|
|
165
165
|
|
|
166
|
+
## Public names
|
|
167
|
+
|
|
168
|
+
V2IP and FPGA are the firmware's internal names. What a user reads - API
|
|
169
|
+
names, docstrings, log messages, console output, docs - says OneIP and video
|
|
170
|
+
processor instead (`oneip_settings`, `OneIPVideoProcessorFeature`), including
|
|
171
|
+
for a name ported from the firmware or the Rust crate, which keep the internal
|
|
172
|
+
spelling. Wire-level code under `proto/` that mirrors a firmware struct may keep
|
|
173
|
+
it too. The names released before the rename resolve through
|
|
174
|
+
`mx_remote/deprecated.py`, and `tests/deprecated.py` fails on any new public
|
|
175
|
+
name spelled V2IP or FPGA.
|
|
176
|
+
|
|
166
177
|
## Working on the protocol
|
|
167
178
|
|
|
168
179
|
When adding or editing a `Frame*` class, byte layouts **must match the MatrixOS firmware C
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mx_remote
|
|
3
|
-
Version:
|
|
3
|
+
Version: 6.2.0
|
|
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/
|
|
@@ -112,7 +112,7 @@ API reference generated from the docstrings, and are readable here in
|
|
|
112
112
|
| [Routing](docs/routing.md) | Selecting video and audio sources for an output. |
|
|
113
113
|
| [Callbacks](docs/callbacks.md) | Reacting to state changes rather than polling for them. |
|
|
114
114
|
| [Audio](docs/audio.md) | Volume, mute and remote-control passthrough. |
|
|
115
|
-
| [OneIP
|
|
115
|
+
| [OneIP](docs/oneip.md) | Streaming endpoints, stream sources and statistics. |
|
|
116
116
|
| [Multiviewer](docs/multiviewer.md) | Layout, sources and output configuration. |
|
|
117
117
|
| [Diagnostics](docs/diagnostics.md) | Network status, the mxr console app and capture replay. |
|
|
118
118
|
|
|
@@ -79,7 +79,7 @@ API reference generated from the docstrings, and are readable here in
|
|
|
79
79
|
| [Routing](docs/routing.md) | Selecting video and audio sources for an output. |
|
|
80
80
|
| [Callbacks](docs/callbacks.md) | Reacting to state changes rather than polling for them. |
|
|
81
81
|
| [Audio](docs/audio.md) | Volume, mute and remote-control passthrough. |
|
|
82
|
-
| [OneIP
|
|
82
|
+
| [OneIP](docs/oneip.md) | Streaming endpoints, stream sources and statistics. |
|
|
83
83
|
| [Multiviewer](docs/multiviewer.md) | Layout, sources and output configuration. |
|
|
84
84
|
| [Diagnostics](docs/diagnostics.md) | Network status, the mxr console app and capture replay. |
|
|
85
85
|
|
|
@@ -9,6 +9,6 @@ The API reference for `mx_remote`. Start at the [project README](https://github.
|
|
|
9
9
|
| [Routing](routing.md) | Selecting video and audio sources for an output. |
|
|
10
10
|
| [Callbacks](callbacks.md) | Reacting to state changes rather than polling for them. |
|
|
11
11
|
| [Audio](audio.md) | Volume, mute and remote-control passthrough. |
|
|
12
|
-
| [OneIP
|
|
12
|
+
| [OneIP](oneip.md) | Streaming endpoints, stream sources and statistics. |
|
|
13
13
|
| [Multiviewer](multiviewer.md) | Layout, sources and output configuration. |
|
|
14
14
|
| [Diagnostics](diagnostics.md) | Network status, the mxr console app and capture replay. |
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# API reference
|
|
2
|
+
|
|
3
|
+
Generated from the docstrings in the package. The guides cover how these fit
|
|
4
|
+
together; this page is the exhaustive list.
|
|
5
|
+
|
|
6
|
+
Autodoc emits reStructuredText, which the markdown parser does not read, so
|
|
7
|
+
every directive below sits in an `eval-rst` block. Without it the page renders
|
|
8
|
+
the directive source as prose and the build still succeeds.
|
|
9
|
+
|
|
10
|
+
```{eval-rst}
|
|
11
|
+
.. automodule:: mx_remote
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Client
|
|
15
|
+
|
|
16
|
+
`Remote` owns the socket, the device registry and the background probe that
|
|
17
|
+
keeps both in step with the mesh.
|
|
18
|
+
|
|
19
|
+
```{eval-rst}
|
|
20
|
+
.. automodule:: mx_remote.remote.Remote
|
|
21
|
+
:members:
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Devices, bays and callbacks
|
|
25
|
+
|
|
26
|
+
A client works against these types rather than the classes implementing them:
|
|
27
|
+
they are what the registry hands out and what a callback receives.
|
|
28
|
+
|
|
29
|
+
```{eval-rst}
|
|
30
|
+
.. automodule:: mx_remote.Interface
|
|
31
|
+
:members:
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Device identity
|
|
35
|
+
|
|
36
|
+
```{eval-rst}
|
|
37
|
+
.. automodule:: mx_remote.Uid
|
|
38
|
+
:members:
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Remote-control keys and actions
|
|
42
|
+
|
|
43
|
+
The key and action codes a bay reports, and the target a key was aimed at.
|
|
44
|
+
|
|
45
|
+
```{eval-rst}
|
|
46
|
+
.. autoclass:: mx_remote.proto.Constants.RCKey
|
|
47
|
+
:members:
|
|
48
|
+
:undoc-members:
|
|
49
|
+
|
|
50
|
+
.. autoclass:: mx_remote.proto.Constants.RCAction
|
|
51
|
+
:members:
|
|
52
|
+
:undoc-members:
|
|
53
|
+
|
|
54
|
+
.. autoclass:: mx_remote.proto.Constants.RCType
|
|
55
|
+
:members:
|
|
56
|
+
:undoc-members:
|
|
57
|
+
|
|
58
|
+
.. autodata:: mx_remote.proto.Constants.MXR_PROTOCOL_VERSION
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## OneIP device settings
|
|
62
|
+
|
|
63
|
+
The settings a OneIP device reports and a controller writes, each behind its own
|
|
64
|
+
bit, and the range of the infrared profiles.
|
|
65
|
+
|
|
66
|
+
```{eval-rst}
|
|
67
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPDeviceSetting
|
|
68
|
+
:members:
|
|
69
|
+
:undoc-members:
|
|
70
|
+
|
|
71
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_DEVICE_SETTING_SWITCHES
|
|
72
|
+
|
|
73
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_IR_PROFILE_NOT_SET
|
|
74
|
+
|
|
75
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_IR_PROFILE_MAX
|
|
76
|
+
|
|
77
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_DEVICE_SETTINGS_REPORTED_ONLY
|
|
78
|
+
|
|
79
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_MINUTES_PER_DAY
|
|
80
|
+
|
|
81
|
+
.. autoclass:: mx_remote.OneIPPowerSaveSchedule
|
|
82
|
+
:members:
|
|
83
|
+
|
|
84
|
+
.. autoclass:: mx_remote.OneIPVlan
|
|
85
|
+
:members:
|
|
86
|
+
|
|
87
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPVlanFlag
|
|
88
|
+
:members:
|
|
89
|
+
|
|
90
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_PORTS
|
|
91
|
+
|
|
92
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_PORT_SFP
|
|
93
|
+
|
|
94
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_VLAN_ID_MAX
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## OneIP test card
|
|
98
|
+
|
|
99
|
+
A sink's test pattern, tone and lip-sync flash, and the ranges it accepts.
|
|
100
|
+
|
|
101
|
+
```{eval-rst}
|
|
102
|
+
.. autoclass:: mx_remote.OneIPTestcard
|
|
103
|
+
:members:
|
|
104
|
+
|
|
105
|
+
.. autoclass:: mx_remote.OneIPTestTone
|
|
106
|
+
:members:
|
|
107
|
+
|
|
108
|
+
.. autoclass:: mx_remote.OneIPTestSync
|
|
109
|
+
:members:
|
|
110
|
+
|
|
111
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPTestPattern
|
|
112
|
+
:members:
|
|
113
|
+
|
|
114
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPToneMode
|
|
115
|
+
:members:
|
|
116
|
+
|
|
117
|
+
.. autoclass:: mx_remote.proto.Constants.OneIPTestcardFlag
|
|
118
|
+
:members:
|
|
119
|
+
|
|
120
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_TONE_FREQ_MIN
|
|
121
|
+
|
|
122
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_TONE_FREQ_MAX
|
|
123
|
+
|
|
124
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_TONE_LEVEL_MIN
|
|
125
|
+
|
|
126
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_TONE_CHANNELS_MAX
|
|
127
|
+
|
|
128
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_TONE_RATES
|
|
129
|
+
|
|
130
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_SYNC_OFFSET_MAX
|
|
131
|
+
|
|
132
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_SYNC_BEEP_MS_MIN
|
|
133
|
+
|
|
134
|
+
.. autodata:: mx_remote.proto.Constants.ONEIP_SYNC_BEEP_MS_MAX
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Mesh time
|
|
138
|
+
|
|
139
|
+
The time zone and clock a mesh controller announces.
|
|
140
|
+
|
|
141
|
+
```{eval-rst}
|
|
142
|
+
.. autoclass:: mx_remote.TimeZone
|
|
143
|
+
:members:
|
|
144
|
+
|
|
145
|
+
.. autoclass:: mx_remote.DeviceClock
|
|
146
|
+
:members:
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Names from before OneIP
|
|
150
|
+
|
|
151
|
+
Releases up to 5.11 used the firmware's internal names in the public API: V2IP
|
|
152
|
+
for OneIP and FPGA for the video processor. Each old name maps to the new one
|
|
153
|
+
by spelling alone - `V2IP` becomes `OneIP` (`ONEIP` in a constant, `oneip` in
|
|
154
|
+
a member), and `Fpga` or `FPGA` becomes `VideoProcessor` or `VIDEO_PROCESSOR`:
|
|
155
|
+
`device.v2ip_settings` is `device.oneip_settings`, `V2IPFpgaFeature` is
|
|
156
|
+
`OneIPVideoProcessorFeature`, `FirmwareType.FPGA` is
|
|
157
|
+
`FirmwareType.VIDEO_PROCESSOR`.
|
|
158
|
+
|
|
159
|
+
The old names still resolve. A module-level name or a class member raises a
|
|
160
|
+
`DeprecationWarning` naming its replacement; an enum member and an
|
|
161
|
+
`AudioFeatures` bit constant are plain aliases, since those cannot warn. The old
|
|
162
|
+
names are left out of `from mx_remote import *` and out of the type stubs, so a
|
|
163
|
+
type checker reports them, and they will be removed in a future major release.
|
|
164
|
+
|
|
165
|
+
One rename has no alias: a OneIP device's `temperatures` dict reports the video
|
|
166
|
+
processor's sensor under `'Video Processor'`, where it used `'FPGA'`.
|
|
167
|
+
|
|
@@ -12,6 +12,26 @@ bay.volume_set(volume=50, muted=False)
|
|
|
12
12
|
bay.mute_set(mute=True)
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
## Audio endpoints
|
|
16
|
+
|
|
17
|
+
A OneIP device reports its audio endpoints, each with its features and a status
|
|
18
|
+
word on the same bits: `FEATURE_MUTE` while it is muted, `FEATURE_TRIGGER`
|
|
19
|
+
while its trigger is active, and `FEATURE_AUDIO_LOCK` while its audio source is
|
|
20
|
+
locked.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
ep = device.audio_endpoint_by_id(1)
|
|
24
|
+
print(ep.features, ep.status, ep.audio_locked)
|
|
25
|
+
|
|
26
|
+
# keep the endpoint's audio source when the video route changes
|
|
27
|
+
await device.set_audio_endpoint_locked(1, True)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Only an endpoint whose features include `FEATURE_AUDIO_LOCK` is written, since
|
|
31
|
+
the device ignores the rest. The device answers by reporting its endpoints
|
|
32
|
+
again, so `audio_locked` reads the lock once that report arrives, and a report
|
|
33
|
+
whose only change is a status fires the device's callbacks.
|
|
34
|
+
|
|
15
35
|
## Remote Control
|
|
16
36
|
|
|
17
37
|
Send remote control key presses and actions:
|
|
@@ -57,7 +57,7 @@ device.config_initialised # False if the device broadcasts config blocks built
|
|
|
57
57
|
device.temperatures # dict of temperature sensor readings
|
|
58
58
|
|
|
59
59
|
# device type checks
|
|
60
|
-
device.
|
|
60
|
+
device.is_oneip # Pulse-Eight OneIP HDMI-over-IP device
|
|
61
61
|
device.is_video_matrix # neo video matrix
|
|
62
62
|
device.is_audio_matrix # audio-only matrix
|
|
63
63
|
device.is_amp # ProAmp8 audio amplifier
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
# OneIP
|
|
1
|
+
# OneIP
|
|
2
2
|
|
|
3
3
|
Streaming endpoints, stream sources and statistics.
|
|
4
4
|
|
|
5
|
+
Releases up to 5.11 named this API after the firmware's internal names: V2IP
|
|
6
|
+
for OneIP and FPGA for the video processor, as in `device.v2ip_settings` or
|
|
7
|
+
`V2IPFpgaFeature`. Those spellings still work, with a `DeprecationWarning`,
|
|
8
|
+
and will be removed in a future major release; see
|
|
9
|
+
[the API reference](api.md#names-from-before-oneip).
|
|
10
|
+
|
|
5
11
|
## Pulse-Eight OneIP Devices
|
|
6
12
|
|
|
7
13
|
[Pulse-Eight OneIP](https://www.pulse-eight.com/p/248/oneip-tx) HDMI-over-IP devices expose additional streaming properties:
|
|
8
14
|
|
|
9
15
|
```python
|
|
10
16
|
# stream source addresses
|
|
11
|
-
if device.
|
|
12
|
-
for source in device.
|
|
17
|
+
if device.is_oneip and device.oneip_sources:
|
|
18
|
+
for source in device.oneip_sources:
|
|
13
19
|
print(f"Video: {source.video.ip}:{source.video.port}")
|
|
14
20
|
print(f"Audio: {source.audio.ip}:{source.audio.port}")
|
|
15
21
|
|
|
@@ -17,8 +23,8 @@ if device.is_v2ip and device.v2ip_sources:
|
|
|
17
23
|
# A configuration frame names its subject in the payload, so a controller's
|
|
18
24
|
# write for a transceiver reaches the transceiver's record - the controller's
|
|
19
25
|
# own stays empty, which is what the device always meant.
|
|
20
|
-
if device.
|
|
21
|
-
details = device.
|
|
26
|
+
if device.oneip_details:
|
|
27
|
+
details = device.oneip_details
|
|
22
28
|
print(f"Video: {details.video}")
|
|
23
29
|
print(f"TX rate: {details.tx_rate}") # None when the sender offered no rate
|
|
24
30
|
|
|
@@ -31,7 +37,7 @@ if device.v2ip_details:
|
|
|
31
37
|
# mode, so call this again inside the minute to keep the 1Hz reports coming.
|
|
32
38
|
await device.read_stats(enable=True) # start collecting
|
|
33
39
|
# ... later ...
|
|
34
|
-
stats = device.
|
|
40
|
+
stats = device.oneip_stats
|
|
35
41
|
|
|
36
42
|
# what the sink's decoder recovered from the codestream it is being given.
|
|
37
43
|
# Three answers, and they mean different things:
|
|
@@ -69,7 +75,7 @@ the query is sent, so a single tick can carry an answer read fractionally
|
|
|
69
75
|
before the switch.
|
|
70
76
|
|
|
71
77
|
```python
|
|
72
|
-
before = device.
|
|
78
|
+
before = device.oneip_stats.decoder.reading.updates
|
|
73
79
|
await sink.switch_source(...)
|
|
74
80
|
# ... wait until reading.updates - before >= 2 (mod 65536) ...
|
|
75
81
|
```
|
|
@@ -104,21 +110,21 @@ the other where it is.
|
|
|
104
110
|
# what the sink reports. Trust this block only from a device whose hello carries
|
|
105
111
|
# CONFIG_INITIALISED - firmware without it builds the block over uninitialised
|
|
106
112
|
# stack, where the valid bit itself is noise.
|
|
107
|
-
scaling = device.
|
|
113
|
+
scaling = device.oneip_details.scaling
|
|
108
114
|
print(scaling.auto_scaling) # None when the sender did not say
|
|
109
115
|
print(scaling.configured_mode) # (signal type, refresh), None when it has none
|
|
110
116
|
|
|
111
117
|
# a mode is given as a depth and a colour space, never as a packed signal-type
|
|
112
118
|
# word read back off the wire: a sink with no mode reports the word carrying the
|
|
113
119
|
# index for "no depth", which a receiver decodes to zero and drops in silence.
|
|
114
|
-
mode = mx_remote.
|
|
120
|
+
mode = mx_remote.OneIPOutputMode(svd=16, depth=12,
|
|
115
121
|
colour=mx_remote.VideoColourSpace.YUV422, refresh=60)
|
|
116
122
|
|
|
117
|
-
await device.
|
|
118
|
-
await device.
|
|
119
|
-
await device.
|
|
123
|
+
await device.set_oneip_auto_scaling(False) # turn it off before setting a mode
|
|
124
|
+
await device.set_oneip_output_mode(mode)
|
|
125
|
+
await device.set_oneip_auto_scaling(True) # back on, if that is what you want
|
|
120
126
|
|
|
121
|
-
await device.
|
|
127
|
+
await device.clear_oneip_output_mode() # the only way to say "no mode"
|
|
122
128
|
```
|
|
123
129
|
|
|
124
130
|
**Set the mode with automatic scaling off.** A sink scaling automatically
|
|
@@ -127,19 +133,19 @@ in silence. Setting the mode first and turning automatic scaling back on
|
|
|
127
133
|
afterwards is the order that survives, because the mode is checked while
|
|
128
134
|
automatic scaling is still off.
|
|
129
135
|
|
|
130
|
-
Nothing acknowledges any of these. `
|
|
136
|
+
Nothing acknowledges any of these. `set_oneip_output_mode` returns False for a
|
|
131
137
|
mode no sink would take, but a True only says the frame went out: the sink
|
|
132
138
|
weighs the format against the display's EDID and against what its own output
|
|
133
|
-
stage can produce, and refuses silently either way. Read `
|
|
139
|
+
stage can produce, and refuses silently either way. Read `oneip_details.scaling`
|
|
134
140
|
back on the device's next report to learn what it did.
|
|
135
141
|
|
|
136
142
|
A scaling change makes the device rebuild and rebroadcast its sink block, so
|
|
137
|
-
expect `device.
|
|
143
|
+
expect `device.oneip_sink` to read empty for a moment afterwards - see
|
|
138
144
|
[what an empty sink block means](#what-an-empty-sink-block-means).
|
|
139
145
|
|
|
140
146
|
## What an empty sink block means
|
|
141
147
|
|
|
142
|
-
`device.
|
|
148
|
+
`device.oneip_sink` addresses that read as unset mean "no route, or the sink
|
|
143
149
|
could not work one out", never "definitely not subscribed". This is the one part
|
|
144
150
|
of a device configuration with no validity marker of its own, so a sink with
|
|
145
151
|
nothing to say sends zeros and the library stores them. A sender leaves it
|
|
@@ -163,29 +169,29 @@ device's configuration sends it zeroed, and the library ignores that copy.
|
|
|
163
169
|
|
|
164
170
|
## Device settings
|
|
165
171
|
|
|
166
|
-
A
|
|
172
|
+
A OneIP device reports its settings in its configuration: decoder auto-disable,
|
|
167
173
|
HDMI off without signal, IR modulation, the status and network LEDs, quiet fan,
|
|
168
174
|
CEC combo keys, and the infrared profiles. Each sits behind its own bit, so a
|
|
169
175
|
device reports only the settings it has, and a write changes one without
|
|
170
176
|
restating the rest.
|
|
171
177
|
|
|
172
178
|
```python
|
|
173
|
-
from mx_remote import
|
|
179
|
+
from mx_remote import OneIPDeviceSetting
|
|
174
180
|
|
|
175
|
-
settings = device.
|
|
176
|
-
print(settings.get(
|
|
181
|
+
settings = device.oneip_settings # None until the device has reported
|
|
182
|
+
print(settings.get(OneIPDeviceSetting.FAN_QUIET)) # None: the device lacks it
|
|
177
183
|
print(settings.ir_profile, settings.ir_profile_sink)
|
|
178
184
|
|
|
179
|
-
await device.
|
|
180
|
-
await device.
|
|
181
|
-
await device.
|
|
185
|
+
await device.set_oneip_setting(OneIPDeviceSetting.STATUS_LED, False)
|
|
186
|
+
await device.set_oneip_ir_profile(2)
|
|
187
|
+
await device.set_oneip_sink_ir_profile(mx_remote.ONEIP_IR_PROFILE_NOT_SET) # follow the global port
|
|
182
188
|
```
|
|
183
189
|
|
|
184
190
|
A write returns False, without sending anything, for whatever the device would
|
|
185
191
|
ignore in silence: a setting it has not reported, a profile out of range, or a
|
|
186
192
|
device that has reported no settings at all. So a True is never a change that
|
|
187
193
|
does not happen, though nothing acknowledges it either: the device answers by
|
|
188
|
-
reporting its settings, and until then `
|
|
194
|
+
reporting its settings, and until then `oneip_settings` reads back what was
|
|
189
195
|
written.
|
|
190
196
|
|
|
191
197
|
A write from another controller is cached only as far as the device takes it.
|
|
@@ -200,14 +206,14 @@ after midnight, Monday first; a window that ends before it starts runs past
|
|
|
200
206
|
midnight, and one that ends where it starts means none that day.
|
|
201
207
|
|
|
202
208
|
```python
|
|
203
|
-
from mx_remote import
|
|
209
|
+
from mx_remote import OneIPPowerSaveSchedule
|
|
204
210
|
|
|
205
211
|
print(settings.auto_power_save) # idle minutes, 0 for never
|
|
206
212
|
print(settings.power_save_schedule) # e.g. "mon 22:00-07:00, ..."
|
|
207
|
-
print(settings.get(
|
|
213
|
+
print(settings.get(OneIPDeviceSetting.CLOCK_SET))
|
|
208
214
|
|
|
209
|
-
await device.
|
|
210
|
-
await device.
|
|
215
|
+
await device.set_oneip_auto_power_save(30)
|
|
216
|
+
await device.set_oneip_power_save_schedule(OneIPPowerSaveSchedule(
|
|
211
217
|
start=(22 * 60,) * 5 + (0, 0), end=(7 * 60,) * 5 + (0, 0))) # weeknights
|
|
212
218
|
```
|
|
213
219
|
|
|
@@ -216,23 +222,83 @@ goes out at 176 bytes: a receiver with the schedule ignores the settings of a
|
|
|
216
222
|
shorter frame, and one whose settings end at the idle minutes takes it all the
|
|
217
223
|
same.
|
|
218
224
|
|
|
225
|
+
### VLAN
|
|
226
|
+
|
|
227
|
+
A device that announces `DeviceFeature.VLAN` tags its uplink by a VLAN
|
|
228
|
+
configuration: its own VLAN id, one per external port (the SFP port, the UTP
|
|
229
|
+
port with PoE, then the UTP port), and the port pinned as the uplink. Ids run
|
|
230
|
+
0 to `ONEIP_VLAN_ID_MAX`, 0 meaning untagged; ports are numbered from 1 on the
|
|
231
|
+
wire, 0 meaning detect the uplink.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from mx_remote import OneIPVlan
|
|
235
|
+
|
|
236
|
+
vlan = device.oneip_vlan # None until the device reports one
|
|
237
|
+
print(vlan.device, vlan.port, vlan.pinned_uplink_port, vlan.active_uplink_port)
|
|
238
|
+
print(vlan.is_pending, vlan.revert_s)
|
|
239
|
+
|
|
240
|
+
await device.set_oneip_vlan(OneIPVlan(device=10, port=(0, 20, 0), uplink=2))
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Only the device knows what it runs, so `oneip_vlan` is read only from the device
|
|
244
|
+
describing itself, and a write is not cached. The device applies a change at
|
|
245
|
+
once and reverts it after `revert_s` seconds unless the mesh controller, hearing
|
|
246
|
+
it report the change as pending, confirms it.
|
|
247
|
+
|
|
248
|
+
Only the ids, the uplink and the trunk bit are written. Refused before sending:
|
|
249
|
+
a device without the VLAN feature or that has not reported its configuration, an
|
|
250
|
+
id above `ONEIP_VLAN_ID_MAX`, an uplink that names no port, and an SFP uplink on
|
|
251
|
+
a device that reports no SFP port. The write goes out as a settings write that
|
|
252
|
+
carries no setting plus the block, so a receiver that predates the block sees a
|
|
253
|
+
frame it already understood.
|
|
254
|
+
|
|
255
|
+
### Test pattern, tone and lip-sync
|
|
256
|
+
|
|
257
|
+
A sink whose video processor reports `OneIPVideoProcessorFeature.SINK_TEST_PATTERN` draws a
|
|
258
|
+
test card on its output: a pattern, a test tone, and a lip-sync flash that marks
|
|
259
|
+
a frame and beeps a set number of sample periods after it.
|
|
260
|
+
|
|
261
|
+
```python
|
|
262
|
+
from mx_remote import OneIPTestPattern, OneIPTestSync, OneIPTestTone, OneIPToneMode
|
|
263
|
+
|
|
264
|
+
await sink.request_oneip_testcard() # the sink reports straight back
|
|
265
|
+
await sink.set_oneip_test_pattern(OneIPTestPattern.FLAT, 0x3050A0)
|
|
266
|
+
await sink.set_oneip_test_tone(OneIPTestTone(mode=OneIPToneMode.CONTINUOUS,
|
|
267
|
+
freq=1000, level=-20, channels=2, rate=48000))
|
|
268
|
+
await sink.set_oneip_test_sync(OneIPTestSync(period=60, lead=0, offset=0, beep_ms=40))
|
|
269
|
+
await sink.set_oneip_test_pattern(OneIPTestPattern.OFF)
|
|
270
|
+
|
|
271
|
+
print(sink.oneip_testcard) # None until the sink has reported
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
A pattern runs until it is turned off, and holds the output on while it does.
|
|
275
|
+
The sink answers every request and change with its test card, on the group, so
|
|
276
|
+
every client records it against the sink; a write is not cached. A sink with the
|
|
277
|
+
feature but without the module that draws the test card does not answer.
|
|
278
|
+
|
|
279
|
+
Each value is checked against the ranges the sink accepts, since it drops what
|
|
280
|
+
falls outside them in silence: see `OneIPTestTone.is_valid()` and
|
|
281
|
+
`OneIPTestSync.is_valid()`. A tone turned off goes out whatever else it holds,
|
|
282
|
+
as the sink stops it regardless. The frame needs protocol 0x2B, so a sink
|
|
283
|
+
announcing less is refused as well.
|
|
284
|
+
|
|
219
285
|
### Every device at once
|
|
220
286
|
|
|
221
|
-
One broadcast changes settings on every
|
|
287
|
+
One broadcast changes settings on every OneIP device of the mesh. Each device
|
|
222
288
|
applies the settings it has and ignores the rest, and none below protocol 0x2A
|
|
223
289
|
applies any.
|
|
224
290
|
|
|
225
291
|
```python
|
|
226
|
-
from mx_remote import
|
|
292
|
+
from mx_remote import OneIPDeviceSettings
|
|
227
293
|
|
|
228
|
-
await mx.
|
|
229
|
-
valid=
|
|
230
|
-
flags=
|
|
294
|
+
await mx.set_all_oneip_device_settings(OneIPDeviceSettings(
|
|
295
|
+
valid=OneIPDeviceSetting.STATUS_LED | OneIPDeviceSetting.AUTO_POWER_SAVE,
|
|
296
|
+
flags=OneIPDeviceSetting.STATUS_LED, # the LED on
|
|
231
297
|
auto_power_save=30))
|
|
232
298
|
```
|
|
233
299
|
|
|
234
300
|
Nothing is cached from it: each device that applies a change reports its
|
|
235
|
-
settings, and its `
|
|
301
|
+
settings, and its `oneip_settings` reads that. What every device would ignore is
|
|
236
302
|
refused rather than sent - no setting at all, one only a device reports about
|
|
237
303
|
itself, a profile out of range, or a schedule time that is not a time of day.
|
|
238
304
|
|
|
@@ -242,13 +308,20 @@ itself, a profile out of range, or a schedule time that is not a time of day.
|
|
|
242
308
|
# mesh operations
|
|
243
309
|
await device.mesh_promote() # promote to mesh master
|
|
244
310
|
await device.mesh_remove() # remove from mesh
|
|
311
|
+
await source.auto_assign_oneip_source_addresses() # drop addresses set by hand
|
|
245
312
|
|
|
246
313
|
# firmware versions
|
|
247
|
-
if device.
|
|
248
|
-
for fw_type, fw in device.
|
|
314
|
+
if device.oneip_firmware_versions:
|
|
315
|
+
for fw_type, fw in device.oneip_firmware_versions.items():
|
|
249
316
|
print(f"{fw_type}: {fw.version}")
|
|
250
317
|
```
|
|
251
318
|
|
|
319
|
+
A OneIP source acts on `auto_assign_oneip_source_addresses()` only from
|
|
320
|
+
management, which this client announces itself as, and nothing acknowledges it:
|
|
321
|
+
the source's next configuration report carries the addresses it ends up with, in
|
|
322
|
+
`oneip_details`. A device that is not a source, or announces less than protocol
|
|
323
|
+
0x2B, would ignore the operation, so it is refused before anything is sent.
|
|
324
|
+
|
|
252
325
|
### Time zone and time
|
|
253
326
|
|
|
254
327
|
The mesh controller announces its time zone and clock with every periodic
|
|
@@ -260,6 +333,7 @@ print(controller.time_zone) # TimeZone(zone='Europe/Amsterdam', rule='CET-1CES
|
|
|
260
333
|
print(controller.clock) # its clock as of now, None until it has announced one
|
|
261
334
|
|
|
262
335
|
await mx.set_mesh_time_zone('Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3')
|
|
336
|
+
await mx.clear_mesh_time_zone() # no time zone: the devices keep UTC
|
|
263
337
|
await mx.set_mesh_time() # now; or pass a datetime
|
|
264
338
|
```
|
|
265
339
|
|
|
@@ -267,7 +341,8 @@ A device takes either only from the controller or a management application,
|
|
|
267
341
|
which is what this client announces itself as; the controller takes them too
|
|
268
342
|
and announces them from then on. A device keeps its own clock where it is within
|
|
269
343
|
2s of the time sent. A name or rule that is empty, holds a NUL or is too long
|
|
270
|
-
for its field, and a time before 1970 or past 2106, are refused.
|
|
344
|
+
for its field, and a time before 1970 or past 2106, are refused. A controller
|
|
345
|
+
without a time zone announces an empty one.
|
|
271
346
|
|
|
272
347
|
---
|
|
273
348
|
|