This release is a pre-release and may not be stable for production use.
videohubwire
videohubwire is a small, dependency-free Python client for Blackmagic Videohub routers speaking the Videohub Ethernet Protocol on TCP 9990. It connects, parses the router's state dump into a snapshot (device info, input and output labels, output locks, routing), routes a source to a destination with ACK/NAK handling, renames ports, and keeps the snapshot current by applying the update blocks the router pushes when any client changes something. It is synchronous and single-socket by design: open, read, act, close, in milliseconds on a LAN, which suits per-request use from a web backend or a script.
Features
Videohubcontext manager:connect()parses the preamble,close()shuts the socket,state()returns a UI-ready dict.route(dest, src)sends oneVIDEO OUTPUT ROUTINGchange, waits forACK/NAK, and applies any pushed blocks that arrive in between.set_input_label()/set_output_label()with newline collapsing and a 64-character cap before anything hits the wire.ping()liveness check.- Output lock states (
U/O/L) surfaced per destination; the client never takes locks. - Bounds checks against the router's own port counts; a
NAKor timeout raisesVideohubError. - Works with and without the
END PRELUDE:marker, so old and new firmware both connect. - One connect retry for cold-ARP first-packet loss; malformed lines are logged and skipped, not fatal.
- Pure standard library; a
socket_factoryhook lets the whole suite run without hardware.
Install
pip install "git+https://github.com/lucas-romanenko/videohubwire.git@v0.1.0.dev0"
Python 3.10 or newer. To run the tests from a checkout:
pip install ".[test]"
python -m pytest
Usage
from videohubwire import Videohub, VideohubError
with Videohub('192.0.2.31') as vh:
snap = vh.state()
print(snap['device']['model_name'], snap['device']['video_inputs'], 'x',
snap['device']['video_outputs'])
for out in snap['outputs']:
print(out['index'], out['label'], '<-', out['source'], out['lock'])
try:
vh.route(dest=3, src=12) # 0-based, like the wire
except VideohubError as e:
print('refused:', e) # locked destination, NAK, or timeout
vh.set_output_label(3, 'Wall Monitor 1')
Protocol notes
Blackmagic documents the block format, the block names and the ACK / NAK
replies in the Videohub Ethernet Protocol document that ships with the
Videohub SDK; this section covers only what that document does not settle
or what this client does on top of it.
- Preamble end detection. Newer firmware ends the initial state dump with an
END PRELUDE:block; older firmware simply stops sending. The client accepts either: it returns as soon as the marker arrives, or once aVIDEOHUB DEVICE:block and aVIDEO OUTPUT ROUTING:block have both been seen and the wire has been quiet for 0.3 s. A router that sends neither the marker nor a routing block is reported as "no state preamble"; that is a known limitation for an unusual device rather than a supported case. - Pushed updates interleave with replies. After the preamble the router pushes the same block shapes whenever state changes from any client. Those pushes can land between a command and its
ACK/NAK, soroute(), the label setters andping()apply any non-reply block they read and keep waiting for the reply.state()drains pending pushes with a short non-blocking read before building the snapshot. - Optimistic routing apply. On
ACKthe client records the new route immediately instead of waiting for the router's ownVIDEO OUTPUT ROUTING:broadcast, so astate()call right afterroute()is already correct. - Lock letters.
VIDEO OUTPUT LOCKSreportsU(unlocked),O(locked by this connection) andL(locked by another client). This client never sends a lock command; it reports the letters so a caller can render locked destinations read-only. Routing a destination locked elsewhere returnsNAK, which is raised asVideohubError. - Labels with spaces and empty labels. Indexed body lines are
<index> <value>; only the first token is the index and the rest, spaces included, is the value. A line such as3(index and nothing else) is a cleared label;state()substitutesInput N/Output N(1-based) for display. - Label limits. The router rejects labels containing newlines because they break the block framing, and caps labels at roughly 64 characters. The client collapses all whitespace runs to single spaces and refuses labels longer than 64 characters before sending.
- Port counts.
video_inputs/video_outputscome from theVIDEOHUB DEVICE:block. If those keys are absent the snapshot sizes itself from the highest label index seen. A non-numeric count in that block raisesValueErrorrather thanVideohubError. - Ignored blocks.
CONFIGURATION:,SERIAL PORT ...,MONITORING OUTPUT ...,VIDEO INPUT STATUS, and any other block the client does not model are parsed past and dropped. OnlyPROTOCOL PREAMBLE,VIDEOHUB DEVICE,INPUT LABELS,OUTPUT LABELS,VIDEO OUTPUT ROUTINGandVIDEO OUTPUT LOCKSupdate state. - Connect retry. The first TCP connect to a router the host has not spoken to recently is sometimes lost to ARP resolution.
connect()retries once after 0.3 s on anyOSError; a second failure propagates unchanged. - Timeouts. Connect and read timeouts default to 3 s. A read timeout while waiting for a reply raises
VideohubError; the router closing the connection raises it too, rather than looping. - What the test fixture reflects. The canned preamble in the tests has the shape of a Smart Videohub 40 x 40 reporting protocol version 2.7 (device block, labels, locks, routing, optional marker). Other models were not exercised.
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file videohubwire-0.1.0.dev0.tar.gz.
File metadata
- Download URL: videohubwire-0.1.0.dev0.tar.gz
- Upload date:
- Size: 11.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54a69db5590a1b66d83dbcece5bb42b4ba641cc4263b00a1a37189aa5b2bb70f
|
|
| MD5 |
493a2aa966366994bae0197a958dc2c9
|
|
| BLAKE2b-256 |
459e26fbf0bc13de5da66d67685de687f6d04a34e9e35ca47a0dccad008983f3
|
Provenance
The following attestation bundles were made for videohubwire-0.1.0.dev0.tar.gz:
Publisher:
publish.yml on lucas-romanenko/videohubwire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
videohubwire-0.1.0.dev0.tar.gz -
Subject digest:
54a69db5590a1b66d83dbcece5bb42b4ba641cc4263b00a1a37189aa5b2bb70f - Sigstore transparency entry: 2796339980
- Sigstore integration time:
-
Permalink:
lucas-romanenko/videohubwire@caede74ca0ff1ba470bace5a01da9142e5c5ddce -
Branch / Tag:
refs/heads/main - Owner: https://github.com/lucas-romanenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@caede74ca0ff1ba470bace5a01da9142e5c5ddce -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file videohubwire-0.1.0.dev0-py3-none-any.whl.
File metadata
- Download URL: videohubwire-0.1.0.dev0-py3-none-any.whl
- Upload date:
- Size: 10.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
797d0386f108e47c0192f1e8c8e3c9521de20221b891061517534ad44aec1681
|
|
| MD5 |
1771e5daa1330400ff80c6803a891c75
|
|
| BLAKE2b-256 |
8df8a7279f2150543f576ae7362ec83c48d6c35c7c6d0cdff5182abaeb1f1589
|
Provenance
The following attestation bundles were made for videohubwire-0.1.0.dev0-py3-none-any.whl:
Publisher:
publish.yml on lucas-romanenko/videohubwire
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
videohubwire-0.1.0.dev0-py3-none-any.whl -
Subject digest:
797d0386f108e47c0192f1e8c8e3c9521de20221b891061517534ad44aec1681 - Sigstore transparency entry: 2796340042
- Sigstore integration time:
-
Permalink:
lucas-romanenko/videohubwire@caede74ca0ff1ba470bace5a01da9142e5c5ddce -
Branch / Tag:
refs/heads/main - Owner: https://github.com/lucas-romanenko
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@caede74ca0ff1ba470bace5a01da9142e5c5ddce -
Trigger Event:
workflow_dispatch
-
Statement type: