Skip to main content

The wire protocol UniFi Protect cameras and controllers speak — measured, not guessed

Project description

pyunifiwire

The wire protocol UniFi Protect cameras and controllers speak to each other. Measured off a real controller and a real camera, not guessed.

from unifiwire import envelope, flv, hevc, ws

message = envelope.decode(frame_payload)      # what the camera just said
message.function_name                          # 'ubnt_avclient_hello'

for tag in flv.Deframer().feed(chunk):         # the push stream, tag by tag
    if tag.kind is flv.TagType.VIDEO and tag.is_keyframe:
        units = hevc.split_nalus(hevc.video_packet(tag.body).payload)

This is the part that is identical whichever end you are building. It has no opinion about adoption, settings, or what a camera should do when told to move — those belong to the thing you are writing. What is here is what the bytes mean.

Why it exists

UniFi cameras do not speak ONVIF or RTSP to their controller. They speak a private protocol: a JSON envelope over a TLS WebSocket, and video pushed over plain TCP in an FLV variant with 20 bytes between tags instead of 4 and HEVC under codec id 8, which no standard demuxer maps. Every project that has needed to talk to one has re-derived that from scratch.

Two implementations use this package as their only shared code — a controller that isn't there and a camera that isn't there — and their test suites read each other's output through it. Anything wrong here fails on both sides at once.

Install

pip install pyunifiwire

Python 3.13+. No dependencies — standard library only, and typed throughout (py.typed, mypy --strict clean).

What's in it

Module What it covers
envelope The JSON envelope every control message rides in: functionName, messageId, inResponseTo, sender and recipient
ws RFC 6455 framing and the server side of the upgrade — enough to accept a camera without a WebSocket library
wsclient The dialling side: the handshake a camera sends, header for header, and masked frames
flv The extendedFlv container — flags 0x07, the 16-byte inter-tag trailer, tag parsing that survives split reads
hevc hvcC parameter sets, length-prefixed NAL units, and the AAC AudioSpecificConfig
annexb Annex B ↔ hvcC, for turning an ordinary .h265 file into something a controller accepts
amf Enough AMF0 to write the metadata tag that identifies a stream
discovery The UDP 10001 probe and the TLV answer a device gives before adoption
certs A self-signed certificate, which both ends need and neither validates

SPEC.md writes out the format itself: the envelope, the framing, the container, and the metadata — with the parts that trip people up called out.

What it is not

  • Not a UniFi Protect API client. For the controller's HTTP API see uiprotect or pyunifi — different protocol entirely.
  • Not a way to get a third-party camera into Protect. See unifi-cam-proxy.
  • Not affiliated with or endorsed by Ubiquiti Inc.

Testing

./test.sh          # mypy --strict, then pytest. No network, no hardware.

Licence

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyunifiwire-0.1.0.tar.gz (30.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyunifiwire-0.1.0-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file pyunifiwire-0.1.0.tar.gz.

File metadata

  • Download URL: pyunifiwire-0.1.0.tar.gz
  • Upload date:
  • Size: 30.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyunifiwire-0.1.0.tar.gz
Algorithm Hash digest
SHA256 eb9d1dc5fb0d4b32e51273cba97da2b5ea577219add9ad04e27440765ff100ca
MD5 c683a1c82dd89465df5f4d416415071a
BLAKE2b-256 733b85f44b58ed96613c198b6d56cc40a90bace8e294e0d48a830fdb1a4ab54e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyunifiwire-0.1.0.tar.gz:

Publisher: publish.yml on rjmotion/pyunifiwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyunifiwire-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyunifiwire-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pyunifiwire-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f917aabb831a78e92428094807aeca656401bf37fdd28a59f008e54971ec4177
MD5 6c1972f6867dff439ba338fdcd3c4fde
BLAKE2b-256 19269bc17aedc5aff6cb1a7e2ce8e6690df4c399ab04473c53d80424d7700f4e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyunifiwire-0.1.0-py3-none-any.whl:

Publisher: publish.yml on rjmotion/pyunifiwire

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page