mx-remote 12.0.0__tar.gz → 13.0.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-12.0.0 → mx_remote-13.0.0}/PKG-INFO +1 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/api.md +62 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/configuration.md +23 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/devices-and-bays.md +5 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/oneip.md +193 -3
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/Interface.py +259 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/Interface.pyi +94 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/compat.py +9 -1
- mx_remote-13.0.0/mx_remote/compat.pyi +3 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/const.py +1 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Constants.py +66 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Constants.pyi +22 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Factory.py +9 -0
- mx_remote-13.0.0/mx_remote/proto/FrameControllerState.py +151 -0
- mx_remote-13.0.0/mx_remote/proto/FrameControllerState.pyi +43 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameHello.py +11 -5
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameHello.pyi +1 -1
- mx_remote-13.0.0/mx_remote/proto/FrameMeshConfig.py +239 -0
- mx_remote-13.0.0/mx_remote/proto/FrameMeshConfig.pyi +59 -0
- mx_remote-13.0.0/mx_remote/proto/FrameMeshReplace.py +178 -0
- mx_remote-13.0.0/mx_remote/proto/FrameMeshReplace.pyi +44 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUnitStatus.py +25 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUnitStatus.pyi +5 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPAudio.py +1 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPOsdSync.py +33 -4
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPOsdSync.pyi +4 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Bay.py +8 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/ConnectionAsync.py +142 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/ConnectionAsync.pyi +14 -0
- mx_remote-13.0.0/mx_remote/remote/Controller.py +150 -0
- mx_remote-13.0.0/mx_remote/remote/Controller.pyi +37 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Device.py +39 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Device.pyi +11 -1
- mx_remote-13.0.0/mx_remote/remote/Mesh.py +156 -0
- mx_remote-13.0.0/mx_remote/remote/Mesh.pyi +26 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/OsdSync.py +26 -5
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/OsdSync.pyi +4 -1
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Remote.py +684 -22
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Remote.pyi +49 -5
- mx_remote-13.0.0/tests/controllerstate.py +560 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/endpoints.py +213 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/handlers.py +3 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/meshcontrol.py +37 -1
- mx_remote-13.0.0/tests/meshmodule.py +515 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/osdsync.py +181 -3
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/proto_stamp.py +15 -2
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/registry.py +38 -7
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/run.py +2 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/unit.py +44 -0
- mx_remote-12.0.0/mx_remote/compat.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/.gitignore +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/AGENTS.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/CLAUDE.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/LICENSE +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/README.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/README.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/_static/brand.css +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/_static/favicon.svg +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/_static/logo-dark.svg +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/_static/logo.svg +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/audio.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/callbacks.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/conf.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/diagnostics.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/index.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/multiviewer.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/requirements.txt +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/docs/routing.md +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/hatch_build.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/Uid.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/Uid.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/__init__.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/__init__.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/const.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/deprecated.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/deprecated.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/main.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/main.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/BayConfig.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/BayConfig.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Data.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Data.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Factory.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAmpDolbySettings.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAmpDolbySettings.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAmpZoneSettings.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAmpZoneSettings.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAudioClip.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAudioClip.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAudioSetRoute.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameAudioSetRoute.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBase.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBase.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayConfig.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayConfig.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayConfigSecondary.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayConfigSecondary.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayContent.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayContent.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayHide.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayHide.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameBayStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameConnectStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameConnectStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameDebug.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameDebug.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameDiscover.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameDiscover.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameEDID.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameEDID.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameEDIDProfile.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameEDIDProfile.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFactoryReset.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFactoryReset.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFilterStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFilterStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFirmwareVersion.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameFirmwareVersion.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameHeader.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameHeader.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameLinks.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameLinks.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMeshOperation.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMeshOperation.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMirrorStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMirrorStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMonitoringPulse.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameMonitoringPulse.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameNetworkStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameNetworkStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FramePing.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FramePing.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FramePowerChange.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FramePowerChange.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCAction.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCAction.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCIr.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCIr.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCKey.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCKey.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCSettings.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRCSettings.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameReboot.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameReboot.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRoutingChange.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameRoutingChange.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetInstaller.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetInstaller.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetName.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetName.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetRoute.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetRoute.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetupStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSetupStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSignalStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSignalStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSignalStatusNew.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSignalStatusNew.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSysTemperature.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSysTemperature.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSystemStatus.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameSystemStatus.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTXRCAction.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTXRCAction.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTXRCKey.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTXRCKey.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameThirdParty.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameThirdParty.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTime.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTime.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTimeZone.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTimeZone.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTopology.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTopology.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTxIR.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameTxIR.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUnitCommand.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUnitCommand.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUpgradeFPGA.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameUpgradeFPGA.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPAudio.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPBayMapping.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPBayMapping.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPDetectBays.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPDetectBays.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPDeviceConfiguration.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPLink.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPLink.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPManualSourceSwitch.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPMultiviewer.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPMultiviewer.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPPowerSave.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPPowerSave.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPPrivacy.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPPrivacy.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSetMaster.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSetMaster.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSettingsAll.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSettingsAll.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSinkSdp.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSinkSdp.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSourceSwitch.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSourceSwitch.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSources.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPSources.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPStats.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPStats.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPTestcard.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPTestcard.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPTiling.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPTiling.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPVideoWall.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameV2IPVideoWall.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolume.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolume.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeDown.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeDown.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeSet.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeSet.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeUp.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/FrameVolumeUp.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/LinkConfig.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/LinkConfig.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Multiviewer.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Multiviewer.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Svd.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/Svd.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/V2IPConfig.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/V2IPConfig.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/V2IPStats.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/V2IPStats.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/__init__.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/__init__.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/proto/svd.csv +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/py.typed +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/AudioRoute.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/AudioRoute.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Bay.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Link.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Link.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/State.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/State.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Tree.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/Tree.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/V2IP.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/mx_remote/remote/V2IP.pyi +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/pyproject.toml +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/audio_ir.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/audiolock.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/audioroute.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/baycontent.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/capture.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/complete.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/connect.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/controllerset.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/deprecated.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/downmix.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/e2e.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/entry.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/handlers_cover.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/hello.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/idempotent.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/lengths.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/merge.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/mesh.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/meshbays.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/newops.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/offline.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/offsets.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/oneiproute.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/osdmessage.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/ping.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/preview.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/privacy.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/protogate.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/rcsettings.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/roundtrip.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/routes.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/smoke.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/sources.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/staterequest.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/stats.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/structs.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/thirdparty.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/txresult.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/uid.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/unknowns.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipptp.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipscaling.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipsdp.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipsettings.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipsubject.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2iptestcard.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/v2ipvlan.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/vdetails.py +0 -0
- {mx_remote-12.0.0 → mx_remote-13.0.0}/tests/wirefix.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: mx_remote
|
|
3
|
-
Version:
|
|
3
|
+
Version: 13.0.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/
|
|
@@ -74,6 +74,8 @@ place, backgrounds and logo images.
|
|
|
74
74
|
|
|
75
75
|
.. autodata:: mx_remote.proto.Constants.OSD_SYNC_RECORDS_MAX
|
|
76
76
|
|
|
77
|
+
.. autodata:: mx_remote.proto.Constants.OSD_SETTINGS_ASKED
|
|
78
|
+
|
|
77
79
|
.. autodata:: mx_remote.proto.Constants.OSD_SYNC_FONT_MAX
|
|
78
80
|
|
|
79
81
|
.. autodata:: mx_remote.proto.Constants.OSD_SYNC_TEXT_MAX
|
|
@@ -409,6 +411,66 @@ The operations a mesh controller sends, and what a controller announces.
|
|
|
409
411
|
.. autodata:: mx_remote.proto.FrameV2IPSources.ONEIP_SOURCE_LIST_MAX
|
|
410
412
|
```
|
|
411
413
|
|
|
414
|
+
## Mesh replacement and kept settings
|
|
415
|
+
|
|
416
|
+
Replacing an offline unit of a mesh, the settings each unit keeps for its mesh,
|
|
417
|
+
and the numbering of a controller's bays.
|
|
418
|
+
|
|
419
|
+
```{eval-rst}
|
|
420
|
+
.. autoclass:: mx_remote.MeshReplaceUnit
|
|
421
|
+
:members:
|
|
422
|
+
|
|
423
|
+
.. autoclass:: mx_remote.MeshReplaceUnits
|
|
424
|
+
:members:
|
|
425
|
+
|
|
426
|
+
.. autoclass:: mx_remote.MeshReplaceable
|
|
427
|
+
:members:
|
|
428
|
+
|
|
429
|
+
.. autoclass:: mx_remote.proto.Constants.MeshReplaceResult
|
|
430
|
+
:members:
|
|
431
|
+
|
|
432
|
+
.. autoclass:: mx_remote.MeshSetting
|
|
433
|
+
:members:
|
|
434
|
+
|
|
435
|
+
.. autoclass:: mx_remote.MeshConfigDigest
|
|
436
|
+
:members:
|
|
437
|
+
|
|
438
|
+
.. autoclass:: mx_remote.MeshConfig
|
|
439
|
+
:members:
|
|
440
|
+
|
|
441
|
+
.. autodata:: mx_remote.proto.Constants.MESH_REPLACE_UNITS_MAX
|
|
442
|
+
|
|
443
|
+
.. autodata:: mx_remote.proto.Constants.MESH_REPLACE_NAME_MAX
|
|
444
|
+
|
|
445
|
+
.. autodata:: mx_remote.proto.Constants.MESH_CONFIG_MAX
|
|
446
|
+
|
|
447
|
+
.. autoclass:: mx_remote.MeshBay
|
|
448
|
+
:members:
|
|
449
|
+
|
|
450
|
+
.. autoclass:: mx_remote.MeshBays
|
|
451
|
+
:members:
|
|
452
|
+
|
|
453
|
+
.. autodata:: mx_remote.proto.Constants.MESH_BAYS_MAX
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Dedicated controllers
|
|
457
|
+
|
|
458
|
+
What a dedicated mesh controller, such as a router, announces of itself and its
|
|
459
|
+
state.
|
|
460
|
+
|
|
461
|
+
```{eval-rst}
|
|
462
|
+
.. autoclass:: mx_remote.ControllerHello
|
|
463
|
+
:members:
|
|
464
|
+
|
|
465
|
+
.. autoclass:: mx_remote.ControllerPart
|
|
466
|
+
:members:
|
|
467
|
+
|
|
468
|
+
.. autoclass:: mx_remote.proto.Constants.ControllerRole
|
|
469
|
+
:members:
|
|
470
|
+
|
|
471
|
+
.. autodata:: mx_remote.proto.Constants.CONTROLLER_PARTS_MAX
|
|
472
|
+
```
|
|
473
|
+
|
|
412
474
|
## Names from before OneIP
|
|
413
475
|
|
|
414
476
|
Releases up to 5.11 used the firmware's internal names in the public API: V2IP
|
|
@@ -28,6 +28,29 @@ mx = mx_remote.Remote(uid_path="/var/lib/myapp/.mxr-uid")
|
|
|
28
28
|
mx = mx_remote.Remote(mesh_device=True, serial="P9SN66660600", version="1.2.3")
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
A client confined to one interface is invisible on every other, so a dedicated
|
|
32
|
+
controller speaking the protocol on its mesh link alone is not listed by the
|
|
33
|
+
units on its uplink LAN. `announce_interfaces` names interfaces that get each
|
|
34
|
+
hello, and a dedicated controller's `CONTROLLER_STATE` hello, from a send-only
|
|
35
|
+
socket bound to the interface's current address:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
mx = mx_remote.Remote(local_ip="10.8.80.30", dedicated_controller=True, announce_interfaces=["eth1"])
|
|
39
|
+
mx.set_announce_interfaces(["eth1", "wlan0"]) # while running, announced at once
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The socket is rebound when that address changes and skipped while there is
|
|
43
|
+
none, as on a DHCP uplink; nothing arriving there is taken. The hello there
|
|
44
|
+
leaves out `MANAGER` (a unit takes a promotion to controller from a manager),
|
|
45
|
+
`MESH_MASTER` (a unit joining a mesh joins it) and `OSD_SYNC` (a source syncs
|
|
46
|
+
every device with it, in any mesh). `MESH_MEMBER` stays, so no unit takes the
|
|
47
|
+
client for one free to join.
|
|
48
|
+
|
|
49
|
+
On Linux, the interface `local_ip` selects is the only one datagrams are taken
|
|
50
|
+
from, so a device reachable only by another interface stays unknown, and
|
|
51
|
+
starting fails when no interface holds the address. Elsewhere, broadcasts on
|
|
52
|
+
every interface still arrive.
|
|
53
|
+
|
|
31
54
|
Each frame leaves by the endpoints a unit picks for it:
|
|
32
55
|
|
|
33
56
|
- a frame for every unit at once goes to both: a discover, reboot or factory
|
|
@@ -43,6 +43,11 @@ await bay.set_hidden(True) # hide
|
|
|
43
43
|
await bay.set_hidden(False) # show
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
A device that lost its settings reports its bays' default names and hidden
|
|
47
|
+
flags, with `BayStatusMask.SETTINGS_LOST` set. A bay keeps the name and hidden
|
|
48
|
+
flag it had until the bit clears; a bay first heard while it is set takes what
|
|
49
|
+
it is sent.
|
|
50
|
+
|
|
46
51
|
## EDID Profiles
|
|
47
52
|
|
|
48
53
|
Change the EDID profile on input bays:
|
|
@@ -533,9 +533,49 @@ Each unit asks for the settings it lacks and takes only those, so this client
|
|
|
533
533
|
holds the content and answers until it is replaced or cleared, announcing
|
|
534
534
|
itself meanwhile as the mesh's overlay sync manager: a unit waking from power
|
|
535
535
|
save then takes this content rather than the controller's. Logo images are
|
|
536
|
-
served over HTTP from this client, on `logo_port` or a free port
|
|
536
|
+
served over HTTP from this client, on `logo_port` or a free port, at `local_ip`
|
|
537
|
+
when one is given and on every address otherwise; a changed `local_ip` moves
|
|
538
|
+
the server there on the same port. Content a unit
|
|
537
539
|
would refuse is refused before anything is sent; see `send_osd_sync`.
|
|
538
540
|
|
|
541
|
+
A mesh controller holding the sync its units already took from another source
|
|
542
|
+
keeps it without sending it again, and sends it to a unit that joins:
|
|
543
|
+
|
|
544
|
+
```python
|
|
545
|
+
await mx.keep_osd_sync(content) # held and served, sent to no unit
|
|
546
|
+
await mx.resend_osd_sync(joined)
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
A client made with `Remote(osd_sync=True)` takes a sync the way a unit does,
|
|
550
|
+
which a dedicated controller needs to hold the mesh's overlays. Its hello
|
|
551
|
+
announces `DeviceFeature.OSD_SYNC`, so a source sends it a sync of its own:
|
|
552
|
+
|
|
553
|
+
```python
|
|
554
|
+
await mx.request_osd_sync(OsdSyncWhat.CAPTIONS | OsdSyncWhat.LOGO_SLOTS)
|
|
555
|
+
# MxrCallbacks.on_osd_sync(dev, sync): the sync naming this client
|
|
556
|
+
await mx.request_osd_settings(dev, sync.seq, sync.what, missing=list(range(sync.records)))
|
|
557
|
+
# MxrCallbacks.on_osd_sync_setting(dev, setting), once per setting
|
|
558
|
+
url = sync.logo_url(sender_address, 1) # where slot 1's PNG is fetched
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
A sync naming this client is read from any device for 10 s after it asked for
|
|
562
|
+
one, and a setting naming it from the source of one of the last
|
|
563
|
+
`OSD_SETTINGS_ASKED` (8) syncs it asked the settings of. A source sends a few
|
|
564
|
+
settings at a time; a unit asks again for those still missing a second after
|
|
565
|
+
the last one came. `setting.entry` converts a setting into the `OsdSyncEntry`
|
|
566
|
+
that `send_osd_sync()` and `keep_osd_sync()` take, so the client can serve the
|
|
567
|
+
sync it took. Fetching the logos is the caller's.
|
|
568
|
+
|
|
569
|
+
Like a unit, it reports to the source at each stage, so the source lists it
|
|
570
|
+
with the units that took the sync:
|
|
571
|
+
|
|
572
|
+
```python
|
|
573
|
+
await mx.send_osd_report(dev, OsdSyncReport(seq=sync.seq, state=OsdSyncState.DONE, written=3, refused=0,
|
|
574
|
+
reason=''))
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
The reason is cut to 63 bytes at a character boundary.
|
|
578
|
+
|
|
539
579
|
A caption setting with `OsdCaptionField.DEFAULT_TEXT` in place of
|
|
540
580
|
`OsdCaptionField.TEXT`, and no text, sends a unit back to its layout's default
|
|
541
581
|
caption, drawn in its own locale. A unit whose firmware predates it keeps the
|
|
@@ -654,6 +694,20 @@ waits. Each command returns False without sending for a device that is not a
|
|
|
654
694
|
OneIP unit, one below 0x2C, or an address and netmask a unit cannot hold.
|
|
655
695
|
Nothing acknowledges a command: `unit_status` reads what the unit reports next.
|
|
656
696
|
|
|
697
|
+
This client reports its own status the way a unit does, to every device:
|
|
698
|
+
|
|
699
|
+
```python
|
|
700
|
+
from mx_remote import UnitStatus
|
|
701
|
+
|
|
702
|
+
await mx.send_unit_status(UnitStatus(flags=UnitFlag.FIRMWARE_UPGRADE, uptime=3600))
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
A mesh controller that runs no update checks of its own passes its members'
|
|
706
|
+
upgrade flags on this way: a member that sees `UnitFlag.FIRMWARE_UPGRADE` or
|
|
707
|
+
`UnitFlag.VIDEO_PROCESSOR_UPGRADE` appear in its controller's report checks
|
|
708
|
+
for the upgrade itself. More than six temperatures, or a status message over
|
|
709
|
+
48 bytes or holding a NUL, is refused before anything is sent.
|
|
710
|
+
|
|
657
711
|
## Mesh and firmware
|
|
658
712
|
|
|
659
713
|
```python
|
|
@@ -691,7 +745,9 @@ mx.set_mesh_bays_mapped(True) # the role is announced only with bays mappe
|
|
|
691
745
|
await mx.send_mesh_operation(MeshOperationMessage.report_controller(mx.uid, priority=1, installer=0x1234))
|
|
692
746
|
await mx.send_mesh_operation(MeshOperationMessage.register(unit.remote_id, mx.uid))
|
|
693
747
|
await mx.send_oneip_source_list(sources) # the mesh's whole source list
|
|
694
|
-
await mx.set_mesh_setup_completed(True)
|
|
748
|
+
await mx.set_mesh_setup_completed(True) # every unit that hears it
|
|
749
|
+
mx.set_setup_completed(True) # this client's own, in its hello
|
|
750
|
+
await mx.set_member_setup_completed(unit, True) # one member, 0x33 or later
|
|
695
751
|
await mx.set_mesh_installer(0x1234)
|
|
696
752
|
|
|
697
753
|
await output.set_oneip_mirroring(other_output) # None to stop
|
|
@@ -702,6 +758,13 @@ await unit.set_rc_settings(rc_target=RCType.CEC, ip=None, cec_enabled=True, cec_
|
|
|
702
758
|
await unit.set_rc_settings(forward_ir=True) # the rest as the unit reported
|
|
703
759
|
```
|
|
704
760
|
|
|
761
|
+
`set_mesh_setup_completed()` names no unit, so every unit that hears it takes
|
|
762
|
+
it. `set_member_setup_completed()` reaches one member alone: a controller marks
|
|
763
|
+
the members of the moment its setup completes, and sends it again to one that
|
|
764
|
+
missed it until that member's hello carries `DeviceFeature.SETUP_COMPLETED`; a
|
|
765
|
+
replacement takes the mark of the unit it replaced. A member takes it only from
|
|
766
|
+
its own controller, and one whose mesh module predates it drops it.
|
|
767
|
+
|
|
705
768
|
The tiling window is in pixels of the decoded source picture: the output crops
|
|
706
769
|
it out and scales it up. A width or height of 0 shows the whole picture. An
|
|
707
770
|
output ignores, without a word, a window whose `pos_x` is not a multiple of
|
|
@@ -763,10 +826,137 @@ input of its own or has not reported its stream addresses, or the other unit has
|
|
|
763
826
|
not reported a usable audio return group.
|
|
764
827
|
|
|
765
828
|
A unit's controller report is kept as `device.mesh_controller_report`, and its
|
|
766
|
-
membership report as `mesh_master`. Every other mesh operation a device sends
|
|
829
|
+
membership report as `mesh_master` and `mesh_membership_lost`. Every other mesh operation a device sends
|
|
767
830
|
arrives at `MxrCallbacks.on_mesh_operation()`, one this library has no name for
|
|
768
831
|
with its raw value.
|
|
769
832
|
|
|
833
|
+
### Replacing a unit, and kept settings
|
|
834
|
+
|
|
835
|
+
Units with the mesh module (protocol 0x32 for replacing, 0x33 for kept
|
|
836
|
+
settings) let a unit outside any mesh take the place of an offline one. A
|
|
837
|
+
device without the module answers nothing, and the library sends neither
|
|
838
|
+
opcode to a unit below its version.
|
|
839
|
+
|
|
840
|
+
```python
|
|
841
|
+
await mx.query_mesh_replaceable() # every device; at most every 2 s
|
|
842
|
+
for r in mx.mesh_replaceable: # listed in the last 30 s, each unit once
|
|
843
|
+
print(r.lister, r.offline_controller, r.unit.uid, r.unit.input_name)
|
|
844
|
+
await mx.request_mesh_replace(lister, r.unit.uid) # answered at on_mesh_replace_answered()
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
Each controller lists its own offline units, once it has been up 120 s, and a
|
|
848
|
+
member whose controller is offline lists that controller. The device asked
|
|
849
|
+
takes the replacing unit in: the unit's bays, their names and routes, and its
|
|
850
|
+
kept settings. A member asked to replace its offline controller sends this
|
|
851
|
+
client the controller's kept settings instead, and taking over is then this
|
|
852
|
+
client's own: promoting itself to controller and having the members replace
|
|
853
|
+
the old one with `send_mesh_operation()`. A request is refused before sending
|
|
854
|
+
where the device would refuse it: the unit was not listed by that device in the
|
|
855
|
+
last 30 s, this client follows a mesh controller or is on a default serial
|
|
856
|
+
(one starting `P9SN0000` other than `P9SN00000000`), or the unit has a
|
|
857
|
+
`ONEIP_SOURCE`, `ONEIP_SINK` or `MULTIVIEWER` feature this client lacks. As a
|
|
858
|
+
controller this client answers with `send_mesh_replaceable()` and
|
|
859
|
+
`send_mesh_replace_result()`.
|
|
860
|
+
|
|
861
|
+
Every unit in a mesh keeps settings of its own, such as `led.status`, and
|
|
862
|
+
announces their length and crc32 as `device.mesh_config_digest`. The controller
|
|
863
|
+
keeps a copy of every member's, and every member one of its controller's, so a
|
|
864
|
+
replacing unit inherits them:
|
|
865
|
+
|
|
866
|
+
```python
|
|
867
|
+
await mx.request_mesh_config(holder, subject.remote_id) # holder's copy, or its own
|
|
868
|
+
config = mx.mesh_config(subject.remote_id) # once every frame has arrived
|
|
869
|
+
await mx.send_mesh_config_hello(settings) # this client's own, in a mesh
|
|
870
|
+
await mx.send_mesh_config(to, subject_uid, settings) # the answer to a request
|
|
871
|
+
await mx.send_mesh_config_set(member, settings) # a member takes these, resets the rest
|
|
872
|
+
```
|
|
873
|
+
|
|
874
|
+
Settings are taken only once every frame has arrived, in order, from one
|
|
875
|
+
sender, and their crc32 matches. A set reaches `on_mesh_config_set_requested()`
|
|
876
|
+
only from the controller this client follows; `send_mesh_config_set()` is
|
|
877
|
+
refused unless the member reports this client as its controller, and a member
|
|
878
|
+
whose settings changed restarts 3 s later. Names and values are at most 255
|
|
879
|
+
bytes with no NUL, and all of them at most `MESH_CONFIG_MAX` (1984) bytes.
|
|
880
|
+
|
|
881
|
+
A unit that lost its settings says so, and announces its defaults: `lost` is set
|
|
882
|
+
on its `mesh_config_digest`, and on a `MeshConfig` of its own settings (never on
|
|
883
|
+
a copy). A controller that keeps a record of it sends that record back as a
|
|
884
|
+
set. Its membership report flags the same, as `device.mesh_membership_lost`:
|
|
885
|
+
a controller that has it as a member adds it back rather than drop it for
|
|
886
|
+
naming no master. Units that predate the flags never set them.
|
|
887
|
+
|
|
888
|
+
A unit that takes over from a controller numbers its bays as that controller
|
|
889
|
+
did, so drivers keep addressing the same ports. A controller answers for its
|
|
890
|
+
own numbering, and a member with the copy it keeps of its controller's, also
|
|
891
|
+
once that controller is offline:
|
|
892
|
+
|
|
893
|
+
```python
|
|
894
|
+
await mx.request_mesh_bays(member, controller.remote_id)
|
|
895
|
+
bays = mx.mesh_bays(controller.remote_id) # MeshBays, None until it arrived whole
|
|
896
|
+
for bay in bays.bays:
|
|
897
|
+
print('input' if bay.input else 'output', bay.bay, bay.unit)
|
|
898
|
+
|
|
899
|
+
# answering a request, MxrCallbacks.on_mesh_bays_requested(dev, subject)
|
|
900
|
+
await mx.send_mesh_bays(dev, mx.uid, [MeshBay(input=True, bay=1, features=DeviceFeature.ONEIP_SOURCE,
|
|
901
|
+
unit=source.remote_id)])
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
A numbering arrives at `on_mesh_bays_received()`, put together as a dump is;
|
|
905
|
+
bay 0 is the controller's own. It is asked only of a unit at 0x33 or later,
|
|
906
|
+
and holds at most `MESH_BAYS_MAX` (512) bays.
|
|
907
|
+
|
|
908
|
+
### Dedicated controllers
|
|
909
|
+
|
|
910
|
+
A mesh controller without bays of its own, such as a router, marks itself as
|
|
911
|
+
dedicated with a `CONTROLLER_STATE` (0x58) hello. A OneIP unit at protocol 0x34
|
|
912
|
+
or later then takes the controller role from none while one it follows is
|
|
913
|
+
online.
|
|
914
|
+
|
|
915
|
+
```python
|
|
916
|
+
print(device.dedicated_controller) # True once it has sent such a hello
|
|
917
|
+
print(device.controller_hello) # ControllerHello: role, generation, primary, parts
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
`MxrCallbacks.on_controller_hello_changed(dev, hello)` reports each hello that
|
|
921
|
+
differs from that device's last.
|
|
922
|
+
|
|
923
|
+
A client made with `Remote(dedicated_controller=True)` sends one itself, right
|
|
924
|
+
after its hello to every unit, at most every 10 s, in a mesh or not; its own
|
|
925
|
+
hello stays at the 54 bytes every unit takes.
|
|
926
|
+
|
|
927
|
+
```python
|
|
928
|
+
mx = Remote(dedicated_controller=True)
|
|
929
|
+
mx.set_controller_role(ControllerRole.PRIMARY, primary=mx.uid) # sent at once when it changed
|
|
930
|
+
```
|
|
931
|
+
|
|
932
|
+
It starts as `ControllerRole.NONE` with no primary, and any other client is
|
|
933
|
+
refused.
|
|
934
|
+
|
|
935
|
+
Dedicated controllers replicate their state between themselves: the library
|
|
936
|
+
does the transfer, and the application only gives and takes part bytes.
|
|
937
|
+
|
|
938
|
+
```python
|
|
939
|
+
# serving: the hello lists each part's length and crc32 under the generation
|
|
940
|
+
mx.set_controller_parts(generation=3, parts=[(0, state_bytes), (1, logo_png)])
|
|
941
|
+
|
|
942
|
+
# pulling a part another controller's hello lists
|
|
943
|
+
part = router.controller_hello.parts[0]
|
|
944
|
+
await mx.pull_controller_part(router, part.part, router.controller_hello.generation, part.length, part.crc)
|
|
945
|
+
# arrives at MxrCallbacks.on_controller_part_received(dev, part, generation, data),
|
|
946
|
+
# or ends at on_controller_part_failed(dev, part, generation)
|
|
947
|
+
|
|
948
|
+
mx.allow_controller_state(new_router.remote_id) # also a controller of no mesh of this client's
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
A request is answered with the window it asks, at most 8192 bytes, in frames of
|
|
952
|
+
at most 1024. A pull asks from the first byte it lacks, again after 2 s without
|
|
953
|
+
data and once on a frame out of order, and ends on a generation no longer held,
|
|
954
|
+
a part other than the one its hello described, the device going offline, or
|
|
955
|
+
ten asks without progress. Requests and data are taken only from a dedicated
|
|
956
|
+
controller of this client's mesh, or the one `allow_controller_state()` names,
|
|
957
|
+
and never from a sender that sent no hello. More than five parts, or one listed
|
|
958
|
+
twice, is refused.
|
|
959
|
+
|
|
770
960
|
### Time zone and time
|
|
771
961
|
|
|
772
962
|
The mesh controller announces its time zone and clock with every periodic
|
|
@@ -2549,6 +2549,16 @@ class OsdSync:
|
|
|
2549
2549
|
CRC differs from its own from http://source_ip:http_port/osd-sync/slotN.png,
|
|
2550
2550
|
N being 1 to 4."""
|
|
2551
2551
|
|
|
2552
|
+
def logo_url(self, sender:str, slot:int) -> str|None:
|
|
2553
|
+
"""Where a unit fetches the logo of slot, 1 to 4, of this sync sent from
|
|
2554
|
+
sender, the sender's address: source_ip, or sender when it is
|
|
2555
|
+
unspecified, at http_port, or 80 when it is zero. None for a slot
|
|
2556
|
+
outside 1 to 4."""
|
|
2557
|
+
if not (1 <= slot <= OSD_SYNC_SLOTS):
|
|
2558
|
+
return None
|
|
2559
|
+
host = sender if (self.source_ip == '0.0.0.0') else self.source_ip
|
|
2560
|
+
return f"http://{host}:{self.http_port or 80}/osd-sync/slot{slot}.png"
|
|
2561
|
+
|
|
2552
2562
|
@dataclass(frozen=True)
|
|
2553
2563
|
class OsdSyncRequest:
|
|
2554
2564
|
"""A unit asking for an overlay sync, or for settings of one it is taking,
|
|
@@ -2621,6 +2631,12 @@ class OsdSyncSetting:
|
|
|
2621
2631
|
bits for a logo, and bit 0 for a background's colour."""
|
|
2622
2632
|
value: OsdSyncValue
|
|
2623
2633
|
|
|
2634
|
+
@property
|
|
2635
|
+
def entry(self) -> 'OsdSyncEntry':
|
|
2636
|
+
"""The setting as this client sends it on, holding the sync it took
|
|
2637
|
+
with Remote.send_osd_sync() or keep_osd_sync()."""
|
|
2638
|
+
return OsdSyncEntry(value=self.value, set=self.set, size=self.size, layers=self.layers)
|
|
2639
|
+
|
|
2624
2640
|
@dataclass(frozen=True)
|
|
2625
2641
|
class OsdSyncReport:
|
|
2626
2642
|
"""
|
|
@@ -2907,6 +2923,14 @@ class MeshOperationMessage:
|
|
|
2907
2923
|
"""The installer id a controller report carries."""
|
|
2908
2924
|
return int.from_bytes(self.param.byte_value[4:6], 'little')
|
|
2909
2925
|
|
|
2926
|
+
@property
|
|
2927
|
+
def membership_lost(self) -> bool:
|
|
2928
|
+
"""Whether a membership report flags that its sender lost its
|
|
2929
|
+
settings, and its membership possibly with them: bit 0 of the
|
|
2930
|
+
parameter's first 32-bit word. Senders that predate the flag leave it
|
|
2931
|
+
clear."""
|
|
2932
|
+
return bool(int.from_bytes(self.param.byte_value[0:4], 'little') & 1)
|
|
2933
|
+
|
|
2910
2934
|
def __str__(self) -> str:
|
|
2911
2935
|
return f"{self.operation} target={self.target} param={self.param}"
|
|
2912
2936
|
|
|
@@ -2918,6 +2942,145 @@ class MeshControllerReport:
|
|
|
2918
2942
|
installer: int
|
|
2919
2943
|
"""The installer id its members take, 0 for none."""
|
|
2920
2944
|
|
|
2945
|
+
@dataclass(frozen=True)
|
|
2946
|
+
class MeshReplaceUnit:
|
|
2947
|
+
"""A unit a controller can have replaced: it has bays on the controller, it
|
|
2948
|
+
is not the controller, and it is offline."""
|
|
2949
|
+
uid: MxrDeviceUid
|
|
2950
|
+
"""The unit."""
|
|
2951
|
+
features: DeviceFeature|int = DeviceFeature(0)
|
|
2952
|
+
"""Its features. A unit replacing it must have its ONEIP_SOURCE, ONEIP_SINK
|
|
2953
|
+
and MULTIVIEWER too."""
|
|
2954
|
+
input: int = 0
|
|
2955
|
+
"""Its first input bay on the controller, 0 when it has none."""
|
|
2956
|
+
output: int = 0
|
|
2957
|
+
"""Its first output bay on the controller, 0 when it has none."""
|
|
2958
|
+
input_name: str = ''
|
|
2959
|
+
"""The name of that input, at most MESH_REPLACE_NAME_MAX bytes."""
|
|
2960
|
+
output_name: str = ''
|
|
2961
|
+
"""The name of that output, at most MESH_REPLACE_NAME_MAX bytes."""
|
|
2962
|
+
|
|
2963
|
+
@dataclass(frozen=True)
|
|
2964
|
+
class MeshReplaceUnits:
|
|
2965
|
+
"""The units one device listed as replaceable."""
|
|
2966
|
+
offline_controller: bool
|
|
2967
|
+
"""The units are the sender's own controller, which is offline. A member
|
|
2968
|
+
lists its controller this way; a controller lists its own offline units."""
|
|
2969
|
+
units: tuple[MeshReplaceUnit, ...]
|
|
2970
|
+
"""The units, as many of the list as has arrived."""
|
|
2971
|
+
total: int
|
|
2972
|
+
"""How many units the whole list holds."""
|
|
2973
|
+
|
|
2974
|
+
@dataclass(frozen=True)
|
|
2975
|
+
class MeshReplaceable:
|
|
2976
|
+
"""A unit this client can ask to replace, and who to ask."""
|
|
2977
|
+
lister: MxrDeviceUid
|
|
2978
|
+
"""The device that listed it, which a request to replace it goes to."""
|
|
2979
|
+
offline_controller: bool
|
|
2980
|
+
"""The unit is the lister's own controller, which is offline."""
|
|
2981
|
+
unit: MeshReplaceUnit
|
|
2982
|
+
"""The unit."""
|
|
2983
|
+
|
|
2984
|
+
@dataclass(frozen=True)
|
|
2985
|
+
class MeshSetting:
|
|
2986
|
+
"""One setting a unit keeps for its mesh: an application configuration name
|
|
2987
|
+
and its value, each at most 255 bytes. A unit carries only the settings
|
|
2988
|
+
that differ from their default."""
|
|
2989
|
+
name: str
|
|
2990
|
+
"""The configuration name, such as led.status."""
|
|
2991
|
+
value: str
|
|
2992
|
+
"""The value, as text."""
|
|
2993
|
+
|
|
2994
|
+
@dataclass(frozen=True)
|
|
2995
|
+
class MeshConfigDigest:
|
|
2996
|
+
"""The length and crc32 of the settings a unit keeps for its mesh, as the
|
|
2997
|
+
unit announces them: every 60 seconds while it is in a mesh, and shortly
|
|
2998
|
+
after one of them changes."""
|
|
2999
|
+
length: int
|
|
3000
|
+
"""The settings' length in bytes, as they are carried."""
|
|
3001
|
+
crc32: int
|
|
3002
|
+
"""The crc32 of those bytes."""
|
|
3003
|
+
lost: bool = False
|
|
3004
|
+
"""The unit lost its settings and announces defaults: a controller that
|
|
3005
|
+
keeps a record of it restores that record, whatever the length and crc32
|
|
3006
|
+
say. Never set by a unit that predates the flag."""
|
|
3007
|
+
|
|
3008
|
+
@dataclass(frozen=True)
|
|
3009
|
+
class MeshConfig:
|
|
3010
|
+
"""A unit's kept settings, as a device sent them."""
|
|
3011
|
+
subject: MxrDeviceUid
|
|
3012
|
+
"""The unit the settings belong to."""
|
|
3013
|
+
holder: MxrDeviceUid
|
|
3014
|
+
"""The device that sent them."""
|
|
3015
|
+
copy: bool
|
|
3016
|
+
"""They are a copy holder keeps of subject, not its own: the controller
|
|
3017
|
+
keeps one of every member, and a member one of its controller."""
|
|
3018
|
+
settings: tuple[MeshSetting, ...]
|
|
3019
|
+
"""The settings, in the order they were sent."""
|
|
3020
|
+
lost: bool = False
|
|
3021
|
+
"""The unit lost its settings, and these are its defaults: a controller
|
|
3022
|
+
that keeps a record of it drops them. Only ever set on a unit's own
|
|
3023
|
+
settings, never on a copy."""
|
|
3024
|
+
|
|
3025
|
+
@dataclass(frozen=True)
|
|
3026
|
+
class MeshBay:
|
|
3027
|
+
"""One bay of a controller's numbering: the unit that owns it."""
|
|
3028
|
+
input: bool
|
|
3029
|
+
"""An input, or else an output."""
|
|
3030
|
+
bay: int
|
|
3031
|
+
"""The bay number the controller gives it, as its /port/list Bay; 0 is the
|
|
3032
|
+
controller's own."""
|
|
3033
|
+
features: DeviceFeature
|
|
3034
|
+
"""The unit's ONEIP_SOURCE, ONEIP_SINK and MULTIVIEWER features as the
|
|
3035
|
+
sender knows them, none when it doesn't."""
|
|
3036
|
+
unit: MxrDeviceUid
|
|
3037
|
+
"""The unit that owns the bay."""
|
|
3038
|
+
|
|
3039
|
+
@dataclass(frozen=True)
|
|
3040
|
+
class MeshBays:
|
|
3041
|
+
"""A controller's numbering, as a device sent it: the controller its own, a
|
|
3042
|
+
member the copy it keeps of its controller's. A unit that takes over from
|
|
3043
|
+
a controller numbers its bays the same, so drivers keep addressing the
|
|
3044
|
+
same ports."""
|
|
3045
|
+
subject: MxrDeviceUid
|
|
3046
|
+
"""The controller the numbering is of."""
|
|
3047
|
+
holder: MxrDeviceUid
|
|
3048
|
+
"""The device that sent it."""
|
|
3049
|
+
copy: bool
|
|
3050
|
+
"""It is a copy holder keeps of subject's numbering."""
|
|
3051
|
+
bays: tuple[MeshBay, ...]
|
|
3052
|
+
"""The bays that name a unit, inputs first, each mode by bay number; a bay
|
|
3053
|
+
naming none is left out."""
|
|
3054
|
+
|
|
3055
|
+
@dataclass(frozen=True)
|
|
3056
|
+
class ControllerPart:
|
|
3057
|
+
"""One part of a dedicated controller's state, as its hello lists it."""
|
|
3058
|
+
part: int
|
|
3059
|
+
"""Which part: 0 the state, 1 to 4 the PNG of that overlay logo slot."""
|
|
3060
|
+
length: int
|
|
3061
|
+
"""The part's length in bytes."""
|
|
3062
|
+
crc: int
|
|
3063
|
+
"""The crc32 of the whole part."""
|
|
3064
|
+
|
|
3065
|
+
@dataclass(frozen=True)
|
|
3066
|
+
class ControllerHello:
|
|
3067
|
+
"""
|
|
3068
|
+
A dedicated controller's CONTROLLER_STATE hello: its role, its state's
|
|
3069
|
+
generation, the primary in its state and the parts its state is made of.
|
|
3070
|
+
|
|
3071
|
+
Sending one marks the sender as a dedicated controller, such as a router,
|
|
3072
|
+
to every unit from protocol 0x34 on, which then lets no OneIP take the
|
|
3073
|
+
controller role from it while it is online.
|
|
3074
|
+
"""
|
|
3075
|
+
role: ControllerRole|int = ControllerRole.NONE
|
|
3076
|
+
"""Primary, failsafe or neither; a plain int where it has no name."""
|
|
3077
|
+
generation: int = 0
|
|
3078
|
+
"""Raised on every change of the sender's state."""
|
|
3079
|
+
primary: MxrDeviceUid|None = None
|
|
3080
|
+
"""The primary in the sender's state, None for none."""
|
|
3081
|
+
parts: tuple[ControllerPart, ...] = ()
|
|
3082
|
+
"""The parts, at most CONTROLLER_PARTS_MAX."""
|
|
3083
|
+
|
|
2921
3084
|
@dataclass(frozen=True)
|
|
2922
3085
|
class ThirdPartyMessage:
|
|
2923
3086
|
"""
|
|
@@ -3809,6 +3972,24 @@ class DeviceBase(ABC):
|
|
|
3809
3972
|
'''What this device last announced about itself as a mesh controller,
|
|
3810
3973
|
None until it has.'''
|
|
3811
3974
|
|
|
3975
|
+
@property
|
|
3976
|
+
@abstractmethod
|
|
3977
|
+
def mesh_config_digest(self) -> MeshConfigDigest|None:
|
|
3978
|
+
'''The length and crc32 of this unit's kept settings, as it last
|
|
3979
|
+
announced them, None until it has.'''
|
|
3980
|
+
|
|
3981
|
+
@property
|
|
3982
|
+
@abstractmethod
|
|
3983
|
+
def controller_hello(self) -> ControllerHello|None:
|
|
3984
|
+
'''The CONTROLLER_STATE hello this device last sent, None until it
|
|
3985
|
+
has sent one.'''
|
|
3986
|
+
|
|
3987
|
+
@property
|
|
3988
|
+
def dedicated_controller(self) -> bool:
|
|
3989
|
+
'''This device is a dedicated mesh controller, such as a router: it has
|
|
3990
|
+
sent a CONTROLLER_STATE hello, which controller_hello reads.'''
|
|
3991
|
+
return (self.controller_hello is not None)
|
|
3992
|
+
|
|
3812
3993
|
@property
|
|
3813
3994
|
@abstractmethod
|
|
3814
3995
|
def is_mesh_master(self) -> bool:
|
|
@@ -4571,6 +4752,16 @@ class BayLinks:
|
|
|
4571
4752
|
class DeviceRegistry(ABC):
|
|
4572
4753
|
''' all mx_remote devices on the network '''
|
|
4573
4754
|
|
|
4755
|
+
def osd_sync_asked(self, at:float) -> bool:
|
|
4756
|
+
'''Whether a sync naming this client, arriving at at, answers its own
|
|
4757
|
+
request for one.'''
|
|
4758
|
+
return False
|
|
4759
|
+
|
|
4760
|
+
def osd_settings_asked(self, source:MxrDeviceUid, seq:int) -> bool:
|
|
4761
|
+
'''Whether a setting naming this client is of sync seq, which it asked
|
|
4762
|
+
source the settings of.'''
|
|
4763
|
+
return False
|
|
4764
|
+
|
|
4574
4765
|
@property
|
|
4575
4766
|
@abstractmethod
|
|
4576
4767
|
def local_ip(self) -> str|None:
|
|
@@ -4914,6 +5105,74 @@ class MxrCallbacks:
|
|
|
4914
5105
|
An operation this library has no name for arrives with its raw value. '''
|
|
4915
5106
|
pass
|
|
4916
5107
|
|
|
5108
|
+
def on_mesh_replace_queried(self, dev:DeviceBase) -> None:
|
|
5109
|
+
''' called when 'dev', a unit outside any mesh, asked which units it can
|
|
5110
|
+
replace. A controller answers with its offline units, and a member
|
|
5111
|
+
whose controller is offline with that controller; see
|
|
5112
|
+
Remote.send_mesh_replaceable(). '''
|
|
5113
|
+
pass
|
|
5114
|
+
|
|
5115
|
+
def on_mesh_replace_units_received(self, dev:DeviceBase, units:MeshReplaceUnits) -> None:
|
|
5116
|
+
''' called when 'dev' listed units this client can ask it to have
|
|
5117
|
+
replaced: the whole list it has sent so far, which
|
|
5118
|
+
Remote.mesh_replaceable also reads. '''
|
|
5119
|
+
pass
|
|
5120
|
+
|
|
5121
|
+
def on_mesh_replace_requested(self, dev:DeviceBase, unit:MxrDeviceUid) -> None:
|
|
5122
|
+
''' called when 'dev', a unit outside any mesh, asked to replace 'unit'
|
|
5123
|
+
with it; see Remote.send_mesh_replace_result(). '''
|
|
5124
|
+
pass
|
|
5125
|
+
|
|
5126
|
+
def on_mesh_replace_answered(self, dev:DeviceBase, unit:MxrDeviceUid, result:MeshReplaceResult|int) -> None:
|
|
5127
|
+
''' called when 'dev' answered this client's request to replace 'unit'.
|
|
5128
|
+
A result this library has no name for arrives as a plain int. '''
|
|
5129
|
+
pass
|
|
5130
|
+
|
|
5131
|
+
def on_mesh_config_requested(self, dev:DeviceBase, subject:MxrDeviceUid) -> None:
|
|
5132
|
+
''' called when 'dev' asked for the kept settings of 'subject': the
|
|
5133
|
+
addressee's own when it is 'subject', otherwise the copy the addressee
|
|
5134
|
+
keeps; see Remote.send_mesh_config(). '''
|
|
5135
|
+
pass
|
|
5136
|
+
|
|
5137
|
+
def on_mesh_config_received(self, dev:DeviceBase, config:MeshConfig) -> None:
|
|
5138
|
+
''' called when 'dev' sent a unit's kept settings whole, which
|
|
5139
|
+
Remote.mesh_config() also reads. '''
|
|
5140
|
+
pass
|
|
5141
|
+
|
|
5142
|
+
def on_mesh_config_set_requested(self, dev:DeviceBase, settings:tuple[MeshSetting, ...]) -> None:
|
|
5143
|
+
''' called when 'dev', the controller this client follows, told it to
|
|
5144
|
+
take these kept settings and reset every other one to its default. '''
|
|
5145
|
+
pass
|
|
5146
|
+
|
|
5147
|
+
def on_mesh_bays_requested(self, dev:DeviceBase, subject:MxrDeviceUid) -> None:
|
|
5148
|
+
''' called when 'dev' asked for the numbering of controller 'subject':
|
|
5149
|
+
this client's own when it is that controller, otherwise the copy it
|
|
5150
|
+
keeps. Answer with Remote.send_mesh_bays(). '''
|
|
5151
|
+
pass
|
|
5152
|
+
|
|
5153
|
+
def on_mesh_bays_received(self, dev:DeviceBase, bays:MeshBays) -> None:
|
|
5154
|
+
''' called when 'dev' sent a controller's numbering whole, which
|
|
5155
|
+
Remote.mesh_bays() also reads. '''
|
|
5156
|
+
pass
|
|
5157
|
+
|
|
5158
|
+
def on_controller_part_received(self, dev:DeviceBase, part:int, generation:int, data:bytes) -> None:
|
|
5159
|
+
''' called when a part this client pulled from 'dev' with
|
|
5160
|
+
Remote.pull_controller_part() arrived whole, its crc32 matching. '''
|
|
5161
|
+
pass
|
|
5162
|
+
|
|
5163
|
+
def on_controller_part_failed(self, dev:DeviceBase, part:int, generation:int) -> None:
|
|
5164
|
+
''' called when a pull of a part from 'dev' ended without it: the
|
|
5165
|
+
generation is no longer held, the part is not the one its hello
|
|
5166
|
+
described, 'dev' went offline, or ten asks went without progress. '''
|
|
5167
|
+
pass
|
|
5168
|
+
|
|
5169
|
+
def on_controller_hello_changed(self, dev:DeviceBase, hello:ControllerHello) -> None:
|
|
5170
|
+
''' called when 'dev' sent a CONTROLLER_STATE hello other than its last:
|
|
5171
|
+
it is a dedicated controller, such as a router, which
|
|
5172
|
+
DeviceBase.dedicated_controller says from then on, and
|
|
5173
|
+
DeviceBase.controller_hello reads. '''
|
|
5174
|
+
pass
|
|
5175
|
+
|
|
4917
5176
|
def on_third_party_message(self, dev:DeviceBase, message:ThirdPartyMessage) -> None:
|
|
4918
5177
|
''' called when the application on 'dev' sent a message under its own
|
|
4919
5178
|
vendor id. A message from a sender this client has not yet heard
|