EZVIZ API client for Home Assistant and CLI
Project description
Ezviz PyPi
Overview
Pilot your Ezviz cameras (and light bulbs) with this module. It is used by:
- The official Ezviz integration in Home Assistant
- The EZVIZ (Beta) custom integration for Home Assistant
You can also use it directly from the command line for quick checks and scripting.
Features
- Inspect device and connection status in table or JSON form
- Control cameras: PTZ, privacy/sleep/audio/IR/state LEDs, alarm settings
- Control light bulbs: toggle, status, brightness and color temperature
- Dump raw pagelist and device infos JSON for exploration/debugging
- Reuse a saved session token (no credentials needed after first login)
Install
From PyPI:
pip install pyezvizapi
After installation, a pyezvizapi command is available on your PATH.
Dependencies (development/local usage)
If you are running from a clone of this repository or using the helper scripts directly, ensure these packages are available:
pip install requests paho-mqtt pycryptodome
Quick Start
# See available commands and options
pyezvizapi --help
# First-time login and save token for reuse
pyezvizapi -u YOUR_EZVIZ_USERNAME -p YOUR_EZVIZ_PASSWORD --save-token devices status
# Subsequent runs can reuse the saved token (no credentials needed)
pyezvizapi devices status --json
CLI Authentication
- Username/password:
-u/--usernameand-p/--password - Token file:
--token-file(defaults toezviz_token.jsonin the current directory) - Save token:
--save-tokenwrites the current token after login - MFA: The CLI prompts for a code if required by your account
- Region:
-r/--regionoverrides the default region (apiieu.ezvizlife.com)
Examples:
# First-time login and save token locally
pyezvizapi -u YOUR_EZVIZ_USERNAME -p YOUR_EZVIZ_PASSWORD --save-token devices status
# Reuse saved token (no credentials)
pyezvizapi devices status --json
Output Modes
- Default: human-readable tables (for list/status views)
- JSON: add
--jsonfor easy parsing and editor-friendly exploration
CLI Commands
All commands are subcommands of the module runner:
pyezvizapi <command> [options]
devices
- Actions:
device,status,switch,connection - Examples:
# Table view
pyezvizapi devices status
# JSON view
pyezvizapi devices status --json
Sample table columns include:
name | status | device_category | device_sub_category | sleep | privacy | audio | ir_led | state_led | local_ip | local_rtsp_port | battery_level | alarm_schedules_enabled | alarm_notify | Motion_Trigger
The CLI also computes a switch_flags map for each device (all switch states by name, e.g. privacy, sleep, sound, infrared_light, light, etc.).
stream
Experimental VTM cloud stream helpers. Packet tracing prints sanitized metadata only. Dumping writes VLC-friendly MPEG-TS by default using FFmpeg -c copy remuxing only, with --format raw available for unchanged VTM payloads. Encrypted packets fail unless --allow-encrypted is set. Some battery cameras keep the VTM channel unencrypted but encrypt the video NAL payloads inside MPEG-PS; use --decrypt-video to decrypt those HEVC/H.264 NAL payloads with the camera encrypt key before writing or remuxing.
# Inspect stream packet metadata without printing media bytes
pyezvizapi stream trace --serial ABC123 --channel 1 --max-packets 20 --json-lines
# Dump a VLC-playable MPEG-TS capture to a file
pyezvizapi stream dump --serial ABC123 --channel 1 --duration 1m --output stream.ts
# Decrypt encrypted battery-camera HEVC video while dumping
pyezvizapi stream dump --serial ABC123 --channel 1 --duration 30s --decrypt-video --output stream.ts
# Pipe raw MPEG-PS payloads directly into FFmpeg and remux to MPEG-TS
pyezvizapi stream dump --serial ABC123 --channel 1 --format raw | \
ffmpeg -f mpeg -i pipe:0 -c copy -f mpegts stream.ts
# Serve a local MPEG-TS URL for Home Assistant/FFmpeg clients
pyezvizapi stream proxy --serial ABC123 --channel 1 --listen-port 8558
# Serve a decrypted local MPEG-TS URL for encrypted battery cameras
pyezvizapi stream proxy --serial ABC123 --channel 1 --decrypt-video --listen-port 8558
The dump command captures one minute by default. Use --duration 30s, --duration 2min, or --duration 0 for unlimited capture; --max-packets can still be used as an additional stop limit. MPEG-TS output requires FFmpeg and remuxes the camera payload with codec copy only; it does not transcode video or audio. The proxy serves http://<host>:8558/<serial>.ts by default. Each HTTP client opens a fresh VTM stream and remuxes it through FFmpeg. Keep the proxy bound to loopback unless you put it behind an authenticated reverse proxy or otherwise restrict access; the stream URL is not authenticated by pyezvizapi.
cloud_videos
Fetch cloud clip descriptors used by the EZVIZ app download path. The returned metadata can include seqId, storageVersion, fileSize, crypt, keyChecksum, and the native SDK streamUrl host/port.
# List recent cloud clips
pyezvizapi cloud_videos --serial ABC123 --channel 1 --limit 10
# Hydrate details and emit JSON for further investigation
pyezvizapi --json cloud_videos --serial ABC123 --channel 1 --limit 5 --details
# Download a cloud clip. Direct HTTP(S) URLs are saved as-is; native streamUrl
# clips are fetched through the pure-Python cloud replay protocol and decrypted.
pyezvizapi cloud_video_download --serial ABC123 --channel 1 --seq-id 12345 \
--output clip.ps --encrypted-output clip.tmp
# Decrypt a previously captured native .tmp file locally in Python
pyezvizapi cloud_video_decrypt --serial ABC123 --input clip.tmp --output clip.ps
Some cloud clips only expose the EZVIZ native SDK streamUrl host/port in videoDetails. For regular cloud-storage clips, cloud_video_download now fetches /v3/cameras/ticketInfo, downloads the encrypted cloud replay .tmp stream over TLS, and applies the local Python PS/NAL decrypt transform. --encrypted-output keeps the encrypted .tmp for comparison.
cloud_video_decrypt is the pure-Python transform step for captured cloud .tmp files. Prefer --serial so pyezvizapi fetches the camera encrypt key without putting it in shell history; --key is available for offline/manual experiments. By default, --decrypt-codec auto detects HEVC, H.264 with an encrypted NAL header, or H.264 with a clear one-byte NAL header. You can still force --decrypt-codec hevc, --decrypt-codec h264, --decrypt-codec h264-clear-header, or --decrypt-codec h264-encrypted-header for manual experiments. h264 remains the backwards-compatible alias for clear-header H.264.
sdcard_videos
Fetch SD-card playback record descriptors using the same record-list endpoints exposed by the EZVIZ app.
# List recent SD-card playback records
pyezvizapi sdcard_videos --serial ABC123 --channel 1 \
--start-time "2026-05-10T21:50:00" --stop-time "2026-05-10T21:55:00"
# Try the app's common/intelligent record endpoints when the default v2 path is empty
pyezvizapi --json sdcard_videos --serial ABC123 --source common \
--start-time "2026-05-10T21:50:00" --stop-time "2026-05-10T21:55:00"
SD-card records are descriptors for native playback/download. The public API does not currently expose a direct HTTP media URL for every record; use stream dump for live VTM capture or cloud_video_download when cloud videoDetails includes an HTTP(S) URL.
camera
Requires --serial.
- Actions:
status,move,move_coords,unlock-door,unlock-gate,switch,alarm,select - Examples:
# Camera status
pyezvizapi camera --serial ABC123 status
# PTZ move
pyezvizapi camera --serial ABC123 move --direction up --speed 5
# Move by coordinates
pyezvizapi camera --serial ABC123 move_coords --x 0.4 --y 0.6
# Switch setters
pyezvizapi camera --serial ABC123 switch --switch privacy --enable 1
# Alarm settings (push notify, sound level, do-not-disturb)
pyezvizapi camera --serial ABC123 alarm --notify 1 --sound 2 --do_not_disturb 0
# Battery camera work mode
pyezvizapi camera --serial ABC123 select --battery_work_mode POWER_SAVE
devices_light
- Actions:
status - Example:
pyezvizapi devices_light status
home_defence_mode
Set global defence mode for the account/home.
pyezvizapi home_defence_mode --mode HOME_MODE
mqtt
Connect to Ezviz MQTT push notifications using the current session token. Use --debug to see connection details.
pyezvizapi mqtt
MQTT push test script (standalone)
For quick experimentation, a small helper script is included which can use a saved token file or prompt for credentials with MFA and save the session token:
# With a previously saved token file
python examples/mqtt_listener.py --token-file ezviz_token.json
# Interactive login, then save token for next time
python examples/mqtt_listener.py --save-token
# Explicit credentials (not recommended for shared terminals)
python examples/mqtt_listener.py -u USER -p PASS --save-token
pagelist
Dump the complete raw pagelist JSON. Great for exploring unknown fields in an editor (e.g. Notepad++).
pyezvizapi pagelist > pagelist.json
device_infos
Dump the processed device infos mapping (what the integration consumes). Optionally filter to one serial:
# All devices
pyezvizapi device_infos > device_infos.json
# Single device
pyezvizapi device_infos --serial ABC123 > ABC123.json
Remote door and gate unlock (CS-HPD7)
pyezvizapi camera --serial BAXXXXXXX-BAYYYYYYY unlock-door
pyezvizapi camera --serial BAXXXXXXX-BAYYYYYYY unlock-gate
RTSP authentication test (Basic → Digest)
Validate RTSP credentials by issuing a DESCRIBE request. Falls back from Basic to Digest auth automatically.
python examples/rtsp_auth_test.py <IP> <USER> <PASS> --uri /Streaming/Channels/101
On success, the script prints a confirmation. On failure it raises one of:
InvalidHost: Hostname/IP or port issueAuthTestResultFailed: Invalid credentials
Development
Install the project with development dependencies:
python -m pip install -U pip wheel
python -m pip install -e .[dev]
Run the same local validation used by CI:
ruff check .
codespell pyezvizapi tests README.md pyproject.toml .github
pip-audit --progress-spinner off
mypy --install-types --non-interactive .
pyright pyezvizapi
pytest --cov=pyezvizapi --cov-report=term-missing --cov-report=xml --cov-fail-under=85
python -m build
twine check dist/*
python -m pip check
Run style fixes where possible:
ruff check --fix .
Before committing, remove generated artifacts so they do not leak into PRs:
rm -rf dist build *.egg-info .coverage coverage.xml .pytest_cache .mypy_cache .ruff_cache
find . -type d -name __pycache__ -prune -exec rm -rf {} +
Tests should be offline by default. Do not add tests that require EZVIZ credentials, real cameras, cloud calls, or live network access. Prefer small fixtures and fakes for request builders, status parsing, MQTT payload handling, and Home Assistant integration contracts.
Side Notes
There is no official API documentation. Much of this is based on reverse-engineering the Ezviz mobile app (Android/iOS). Some regions operate on separate endpoints; US example: apiius.ezvizlife.com.
Example:
pyezvizapi -u username@domain.com -p PASS@123 -r apius.ezvizlife.com devices status
For advanced troubleshooting or new feature research, MITM proxy tools like mitmproxy/Charles/Fiddler can be used to inspect traffic from the app (see community guides for SSL unpinning and WSA usage).
Contributing
Contributions are welcome — the API surface is large and there are many improvements possible.
See CONTRIBUTING.md for development setup, local validation, offline-test expectations, and cleanup guidance before opening a PR.
For questions, bug reports, and feature requests, see SUPPORT.md for what to include and what not to post publicly.
For changes that affect Home Assistant integrations, see docs/home-assistant-contract.md before renaming methods, changing status keys, or altering auth/MQTT behavior.
For vulnerability reports or security-sensitive behavior, see SECURITY.md. Please do not post credentials, MFA codes, tokens, or private camera URLs in public issues.
Versioning
We follow SemVer when publishing the library. See CHANGELOG.md and repository tags for released versions.
Release tags should match the package version in pyproject.toml using the form v<version> (for example, v1.0.4.7). The PyPI publish workflow validates this before uploading distributions.
Recommended release flow:
- Bump
project.versioninpyproject.tomland updateCHANGELOG.mdunderUnreleasedduring normal PR work. - Run Prepare Release with the bare version, then review and merge the generated changelog PR.
- Run Upload Python Package manually with the same bare version. That workflow validates the version, builds and smoke-tests the wheel/CLI, publishes to PyPI, then creates the matching GitHub release/tag.
License
Apache 2.0 — see LICENSE.md.
Draft versions: 0.0.x
Project details
Release history Release notifications | RSS feed
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 pyezvizapi-1.0.4.9.tar.gz.
File metadata
- Download URL: pyezvizapi-1.0.4.9.tar.gz
- Upload date:
- Size: 171.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e84eb1250f3937657e03eb9775099375ef3761c720c51472767f2bd6cb427ec
|
|
| MD5 |
a32025a91d25cf0b051ccc031dd3d3d9
|
|
| BLAKE2b-256 |
89641d1f27b9b8a89ba4406dc621ecac1c8cd4b946c0d3d87b679d6147fc12fe
|
Provenance
The following attestation bundles were made for pyezvizapi-1.0.4.9.tar.gz:
Publisher:
python-publish.yml on RenierM26/pyEzvizApi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyezvizapi-1.0.4.9.tar.gz -
Subject digest:
9e84eb1250f3937657e03eb9775099375ef3761c720c51472767f2bd6cb427ec - Sigstore transparency entry: 1497241689
- Sigstore integration time:
-
Permalink:
RenierM26/pyEzvizApi@16e90c0e524838a21084c0926db21822d6e87c89 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/RenierM26
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@16e90c0e524838a21084c0926db21822d6e87c89 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file pyezvizapi-1.0.4.9-py3-none-any.whl.
File metadata
- Download URL: pyezvizapi-1.0.4.9-py3-none-any.whl
- Upload date:
- Size: 122.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc7d11c808f875ef4c41eed3ed6a330ac8c36db7a67c7b9a44110c7a228de0e9
|
|
| MD5 |
67096a02bb123ce0bc61273af7336fcc
|
|
| BLAKE2b-256 |
dfe73c6ba930b0ece1b8eb4cae1c04f28cb4e1a41ebe3fecd33f0f0fd2caa939
|
Provenance
The following attestation bundles were made for pyezvizapi-1.0.4.9-py3-none-any.whl:
Publisher:
python-publish.yml on RenierM26/pyEzvizApi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyezvizapi-1.0.4.9-py3-none-any.whl -
Subject digest:
bc7d11c808f875ef4c41eed3ed6a330ac8c36db7a67c7b9a44110c7a228de0e9 - Sigstore transparency entry: 1497241776
- Sigstore integration time:
-
Permalink:
RenierM26/pyEzvizApi@16e90c0e524838a21084c0926db21822d6e87c89 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/RenierM26
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@16e90c0e524838a21084c0926db21822d6e87c89 -
Trigger Event:
workflow_dispatch
-
Statement type: