* Implement PTZ binary commands - Modified `const.py` to include `IntEnum` and added new PTZ command constants. - Introduced `PtzDirection`, `PtzParamType`, and `PtzPrefab` classes for better type safety. - Updated `CC_DEST` to include `CMD_PASSTHROUGH_STRING_PUT`. - Added `pack_passtrough_cmd` function in `packets.py` for command packing. - Updated `session.py` imports to include new PTZ classes and functions. - Modified `send_command` method in `BinarySession` to accept optional payloads. - Enhanced `reboot`, `toggle_whitelight`, and `toggle_ir` methods to simplify command sending. - Improved `rotate_start` and `rotate_stop` methods to handle PTZ commands. - Added `_pack_ptz_dir_cmd` static method for packing PTZ direction commands. * Adjust DevStatus parsing Introduce `inet_btoa` and `get_dev_version` functions for converting byte arrays to a dot-separated IP address string and a version string, respectively. Update `BinarySession` to unpack a larger data structure from the `data` byte array, including new fields like battery level and device name, while removing outdated fields related to charging and power. * Refactor device status handling in packets and session - Renamed `inet_btoa` to `_inet_btoa` and `get_dev_version` to `_get_dev_version` in `packets.py` to indicate private usage. - Added `parse_dev_status` function in `packets.py` to parse device status data and return a structured dictionary. - Updated imports in `session.py` to include `parse_dev_status` and removed old function imports. - Modified `BinarySession` to call `parse_dev_status` directly, simplifying the code and improving clarity. - Updated `get_status` method to return parsed device status and raw data in hexadecimal format. * Add video parameter handling and UI updates - Introduced `VideoParamType`, `VideoResolution`, and `VideoRotate` classes in `const.py` for managing video settings. - Updated button labels in `http_server.py` for lamp controls. - Enhanced the `index` function in `http_server.py` to include controls for video parameters like resolution, brightness, and more. - Modified `handle_commands` in `http_server.py` to support setting video parameters. - Added a new asynchronous method `set_video_param` in the `Session` class in `session.py`. - Implemented `set_video_param` in the `BinarySession` class to handle video parameter commands. - Updated import statements in `session.py` to include new video-related classes. * Refactor video parameter handling and UI Refactor `_get_video_params` and `_build_video_param` methods in `session.py` to utilize enum values, streamlining video parameter management and improving code clarity. * Improve data parsing and logging in packets and session - Updated `parse_dev_status` to return an empty dict if data length is less than 124 bytes, and changed unpacking format from `5I` to `5i`. - Enhanced logging in `Session` class to include device address for better connection context. * Update README - Add tested devices table.md Add table with working features on tested devices * Update default credentials and authentication logic Changed the `DEFAULT_PASSWORD` for `BinarySession` to `'admin'`. Modified authentication checks to log errors instead of raising exceptions, allowing some camera functions to be accessible without login. Updated `setup_device` to include login status in device properties for better clarity. * Update README.md with new tested devices and info Added PTZA and FTYC to the "Tested Devices" section. Expanded troubleshooting information to include these new camera prefixes for better user guidance. * Change logging level in BinarySession method Modified the `handle_incoming_command_packet` method to replace a warning log with a debug log. This change reflects a shift in the importance of the logged information, making it more suitable for debugging purposes.
6.7 KiB
aiopppp
aiopppp is an asynchronous Python library designed to simplify connecting to and interacting with cameras that utilize the Peer-to-Peer Protocol (PPPP) which is implemented in some cheap cameras (A9, X5, etc.) This library enables seamless communication with compatible cameras for live video streaming, capturing snapshots, or configuring camera settings, all using asyncio for efficient performance.
Features
- Initial camera discovery (plain and encoded (not all keys))
- Asynchronous peer-to-peer connections with PPPP-enabled cameras using both JSON and binary control protocols
- Stream live video feeds directly from the camera.
- Remote camera rotation
- (TBD) Capture snapshots and save them locally.
- (TBD) Configure and manage camera settings.
- Lightweight and easy to integrate into Python applications.
Tested Devices
| Prefix | Protocol | Video | Audio* | PTZ | White Light | IR Light | Reboot | Resolution |
|---|---|---|---|---|---|---|---|---|
| DGOK | 📜 JSON | ✅ | ✖️ | ✅ | ✅ | ✅ | ✅ | ✖️ |
| PTZA | 🔢 Binary | ✅ | ✖️ | ✅ | ✅ | 🚫 | ✅ | ✅ |
| FTYC | 🔢 Binary | ❌* | ✖️ | 🚫 | 🚫 | ✅ | ✅ | ✅ |
| BATE* | 🔢 Binary | ❔ | ✖️ | ❔ | ❔ | ❔ | ❔ | ❔ |
| DGB* | 📜 JSON | ⚠️ | ✖️ | ❔ | ❔ | ❔ | ❔ | ❔ |
| ACCQ* | ❔ Unknown | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ |
Legend:
- ✅ Working: Feature is fully functional.
- ⚠️ Partially working: Feature works with limitations or issues.
- ❌ Not working: Feature is implemented but does not function.
- ✖️ Not implemented: Feature is not implemented in the system.
- 🚫 Not supported: Feature is not supported by the device.
- ❔ Not tested: Feature has not been tested on the device.
Installation
To install the library, run:
pip install aiopppp
Requirements
- Python 3.7 or higher
- Compatible PPPP-enabled cameras
- Required dependencies (automatically installed with
pip):asyncioaiohttp
Quick Start
Prerequisites
The camera must be connected to WiFi using its mobile app. On the first start the camera creates WiFi access
point with the name like DGXX-XXXX or a different name. And it should be used for configuring WiFi settings.
After it is connected to you network you can use its IP address to connect to it.
The camera should use UDP port 32108 for discovery. There are cameras with the same form-factor with open port 20190 which is not supported. It uses either a different protocol or a different encryption.
Usage
Here’s an example of how to use the library:
Using high-level device:
import asyncio
from aiopppp import Device
async def main():
async with Device("192.168.1.2") as device:
print("Connected to the device")
print("Device info:", device.properties)
await device.start_video()
await asyncio.sleep(10)
await device.stop_video()
print("Disconnected from the device")
# or
device = Device("192.168.1.2")
await device.connect()
print("Device info:", device.properties)
await device.close()
asyncio.run(main())
Or low-level session connections:
import asyncio
from aiopppp import find_device
from aiopppp.device import make_session
from contextlib import suppress
async def main():
device = await find_device("192.168.1.2", timeout=20)
disconnected = asyncio.Event()
session = make_session(device, on_device_lost=lambda lost_device: disconnected.set())
session.start()
await asyncio.wait([session.device_is_ready.wait(), session.main_task], return_when=asyncio.FIRST_COMPLETED)
if session.main_task.done():
await session.main_task
return
print("Connected to the device")
print("Device info:", session.dev_properties)
session.stop()
with suppress(asyncio.CancelledError):
await session.main_task
print("Disconnected from the device")
asyncio.run(main())
Or create discovery class and process found devices manually:
import asyncio
from aiopppp import Discovery, JsonSession
def on_disconnect():
print("Disconnected from the device")
def on_device_found(device):
print(f"Found device: {device}")
session = JsonSession(device, on_disconnect=on_disconnect)
session.start()
async def main():
discovery = Discovery(remote_addr='255.255.255.255')
await discovery.discover(on_device_found)
asyncio.run(main())
Running test web server
To test the library, you can run a simple web server that streams the camera feed. The server will automatically discover the camera and start streaming the video feed.
python -m aiopppp -u admin -p 6666
Then, visit http://localhost:4000 in your browser to view the camera feed.
Troubleshooting
If you encounter issues:
- Verify that your camera supports the PPPP protocol. The tested cameras had prefix DGOK, BATE, PTZA, FTYC, ... Little Stars app is not supported yet, as it uses a different protocol with ports 8070, 8080.
- Check credential for the camera. Use -u and -p flags to specify username and password.
- Check your camera in the same subnet as the machine with the script running.
Contributing
Contributions are welcome! Feel free to submit issues or pull requests on GitHub.
License
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Thanks
This library is inspired and used protocol description from the following projects:
Protocol client implementations:
-
WireShark dissector for the PPPP protocol https://github.com/magicus/pppp-dissector
-
Discussion at https://community.home-assistant.io/t/popular-a9-mini-wi-fi-camera-the-ha-challenge/230108