Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
d4682dd
Fix JsonSession.toggle_ir raising ValueError on every call
DevLn Jun 13, 2026
93ecf48
Make Session.stop() idempotent
DevLn Jun 13, 2026
5905408
Don't swallow CancelledError in MJPEG stream handler
DevLn Jun 13, 2026
45ed578
Wrap outgoing command index at 16 bits
DevLn Jun 13, 2026
efff761
Import VideoRotate so set_video_param('rotate', ...) works
DevLn Jun 13, 2026
8497c6e
Don't swallow CancelledError in find_device
DevLn Jun 13, 2026
8c80ea0
Guard new-device future against double/None set_result
DevLn Jun 13, 2026
428608b
Vectorize XOR1 decode (~28x faster on the video hot path)
DevLn Jun 13, 2026
bd5fd40
Bound video reassembly buffers and cut per-chunk work
DevLn Jun 13, 2026
b33efd1
Bind discovery to an OS-assigned local port by default
DevLn Jun 13, 2026
1c3cfcc
Wire --local-discovery-port through to Discovery
DevLn Jun 13, 2026
f8d5c76
Add on_video_state_change callback for streaming state
DevLn Jun 13, 2026
2aa8e8b
Detect dead connections via a receive timeout
DevLn Jun 14, 2026
f573aca
Don't recreate a session for an already-connected camera
DevLn Jun 14, 2026
1a23481
Don't crash the process on a P2pRdy timeout or session error
DevLn Jun 15, 2026
59daef7
Re-assert binary video resolution after stream start to lock it
DevLn Jun 15, 2026
d7b5426
Merge branch 'fix/dead-connection-detection'
DevLn Jul 4, 2026
ffc5f0b
Merge branch 'experiment/lock-video-resolution'
DevLn Jul 4, 2026
a7a390d
Fix binary-protocol correctness bugs in the session/packet layer
DevLn Jul 4, 2026
04b14bf
Merge branch 'fix/binary-protocol-core'
DevLn Jul 4, 2026
f15bac5
Split BinaryCommands into unambiguous enums
DevLn Jul 4, 2026
11ae651
Merge branch 'fix/binary-command-enum'
DevLn Jul 4, 2026
3d12585
Make video reassembly incremental (drop per-chunk O(frame^2) work)
DevLn Jul 4, 2026
0c6f52f
Merge branch 'perf/video-reassembly'
DevLn Jul 4, 2026
576f620
Detect video-only stalls on binary (and all) sessions
DevLn Jul 4, 2026
03839b0
Merge branch 'feature/binary-video-stall'
DevLn Jul 4, 2026
f8800ed
Binary: explicit IR/light control, snapshot, factory reset, lamp
DevLn Jul 4, 2026
437d296
Merge branch 'feature/binary-explicit-controls'
DevLn Jul 4, 2026
9a0862b
Binary: add PTZ preset goto/save
DevLn Jul 4, 2026
1df8fb2
Merge branch 'feature/binary-ptz-presets'
DevLn Jul 4, 2026
bf3cd11
Binary: expose full video-parameter surface
DevLn Jul 4, 2026
813c517
Merge branch 'feature/binary-video-params'
DevLn Jul 4, 2026
c3e2f8b
Binary: add system and network commands
DevLn Jul 4, 2026
7ff9bb6
Merge branch 'feature/binary-system-network'
DevLn Jul 4, 2026
f633385
Binary: add SD card listing and playback control
DevLn Jul 4, 2026
a548e73
Merge branch 'feature/binary-sd-playback'
DevLn Jul 4, 2026
d3e0fce
Binary: two-way audio (G.711 listen + talk-back)
DevLn Jul 4, 2026
ae7895f
Merge branch 'feature/binary-audio'
DevLn Jul 4, 2026
ff7b758
Binary: experimental CGI command vocabulary support
DevLn Jul 4, 2026
4e78e5b
Merge branch 'feature/cgi-vocabulary'
DevLn Jul 4, 2026
34b3c28
Implement Device auto-reconnect with backoff
DevLn Jul 4, 2026
3b51b74
Merge branch 'feature/device-reconnect'
DevLn Jul 4, 2026
d068112
Fix lost command result when the ACK arrives before the awaiter
DevLn Jul 4, 2026
61515ad
Merge branch 'fix/cmd-result-race'
DevLn Jul 4, 2026
039c1c1
Extend the binary camera simulator for end-to-end testing
DevLn Jul 4, 2026
74964e9
Merge branch 'test/binary-simulator'
DevLn Jul 4, 2026
5634343
Release 0.3.0
DevLn Jul 4, 2026
c362929
Merge branch 'chore/release-0.3.0'
DevLn Jul 4, 2026
7ee46e6
Add a transparent DID-rewriting proxy camera (binary protocol)
DevLn Jul 4, 2026
aedad92
Merge branch 'feature/proxy-camera'
DevLn Jul 4, 2026
dc51518
Rework test web UI: per-camera pages + full binary control surface
DevLn Aug 23, 2026
62db192
Merge branch 'feature/webui-per-camera'
DevLn Aug 23, 2026
2ff4394
Tag every session log line with its device ID + no-boundary probe
DevLn Aug 23, 2026
acd2bd7
Merge branch 'fix/session-log-device-id'
DevLn Aug 23, 2026
35cb355
Fix set_datetime timezone + decode datetime/wifi blocks (PTZA-confirmed)
DevLn Aug 23, 2026
90f1cfa
Merge branch 'fix/datetime-tz'
DevLn Aug 23, 2026
6bd241c
Web UI: decode info blocks, param-table read-back, raw as tooltip
DevLn Aug 23, 2026
99ac6af
Merge branch 'fix/webui-info-decode'
DevLn Aug 23, 2026
5c3966b
Don't let late pre-wrap video chunks re-arm the epoch detector
DevLn Aug 23, 2026
2b2bc2b
Merge branch 'fix/video-epoch-late-chunks'
DevLn Aug 23, 2026
e973bfa
Web UI: snapshot falls back to the latest video frame
DevLn Aug 23, 2026
0a49c8a
Merge branch 'fix/webui-snapshot-fallback'
DevLn Aug 23, 2026
62e0aa4
Never publish empty video frames (fixes FTYC one-frame freeze)
DevLn Aug 23, 2026
318fa23
Merge branch 'fix/ftyc-frame-mux'
DevLn Aug 23, 2026
d8d5806
set_datetime: send the full 80-byte struct, preserving the NTP server
DevLn Aug 23, 2026
48b9072
Merge branch 'fix/datetime-full-struct'
DevLn Aug 23, 2026
34ebf55
Route FTYC's muxed audio off the video channel (fixes one-frame freeze)
DevLn Aug 23, 2026
3b9b8c3
Merge branch 'fix/ftyc-audio-mux'
DevLn Aug 23, 2026
b6980f2
parse_datetime_block: handle both firmware layouts (PTZA vs FTYC)
DevLn Aug 23, 2026
17b1e35
Merge branch 'fix/datetime-decode-variants'
DevLn Aug 23, 2026
a7d1004
Web UI: low-latency audio player + honest rotate read-back
DevLn Aug 23, 2026
d1c1c21
Merge branch 'fix/webui-low-latency-audio'
DevLn Aug 23, 2026
a2dcc8e
Refcount /audio listeners; only the last one out stops the camera
DevLn Aug 23, 2026
1729438
Merge branch 'fix/webui-audio-refcount'
DevLn Aug 23, 2026
61a2caf
Frame outgoing talk audio with the camera's 0x20 stream header
DevLn Aug 23, 2026
1462568
Merge branch 'fix/talk-audio-framing'
DevLn Aug 23, 2026
3e3c056
Friendly status fields per the vendor app's own semantics
DevLn Aug 23, 2026
38284ee
Merge branch 'feature/status-friendly-fields'
DevLn Aug 23, 2026
6328f7c
Web UI: Wi-Fi scan and device-users endpoints + buttons
DevLn Aug 23, 2026
690f8eb
Merge branch 'feature/webui-wifi-users'
DevLn Aug 23, 2026
bf3746a
README: document device-tested features, protocol findings, tooling
DevLn Aug 23, 2026
794d958
Merge branch 'docs/readme-update'
DevLn Aug 23, 2026
4c75c78
PTZ presets: use the PREFAB param type the vendor app actually sends
DevLn Aug 23, 2026
f990b47
Merge branch 'fix/ptz-presets-prefab'
DevLn Aug 23, 2026
9c01926
README: presets now use the YsxLite PREFAB scheme (retest pending)
DevLn Aug 23, 2026
2dd9ee9
README: presets not supported by tested cameras (PREFAB scheme retested)
DevLn Aug 23, 2026
aa9e199
Merge branch 'docs/presets-not-supported'
DevLn Aug 23, 2026
4ee98d1
Discovery: also broadcast LanSearchExt (0x32), not just LanSearch (0x30)
DevLn Aug 23, 2026
7534364
Merge branch 'feature/discovery-lansearchext'
DevLn Aug 23, 2026
0dfce74
Bump version to 0.4.0
DevLn Aug 23, 2026
22b9d8b
Merge branch 'chore/version-0.4.0'
DevLn Aug 23, 2026
564eaff
Don't render a timezone from firmwares that don't store one
DevLn Aug 24, 2026
66f9a25
Merge branch 'fix/status-tz-and-param-decode'
DevLn Aug 24, 2026
c276f08
Derive battery percent from a LiPo curve, not the app's icon buckets
DevLn Aug 25, 2026
02b17fe
Merge branch 'fix/battery-lipo-curve'
DevLn Aug 25, 2026
456eccc
Number this release 0.3.0, not 0.4.0
DevLn Aug 25, 2026
160cdb8
Merge branch 'chore/version-0.3.0'
DevLn Aug 25, 2026
caf81c6
README: correct the battery note, discovery probes, time-sync column
DevLn Aug 25, 2026
4ee59ee
Merge branch 'docs/readme-refresh'
DevLn Aug 25, 2026
681a6ed
README: record the HD-on-stream-start resolution limitation
DevLn Aug 25, 2026
6793560
Merge branch 'docs/known-issue-resolution'
DevLn Aug 25, 2026
fb9f6b3
Report the status field the SDK calls sysUptime as Wi-Fi dBm
DevLn Aug 25, 2026
970a9ad
Merge branch 'fix/dev-status-wifi-dbm'
DevLn Aug 25, 2026
92f9830
Name the packed status fields, and decode them only where populated
DevLn Aug 25, 2026
f6d81ff
Merge branch 'feature/devinfo-enums-and-presets'
DevLn Aug 25, 2026
fc6d5a8
Decode the result code cameras return in a reply's token field
DevLn Aug 25, 2026
3fd6184
Merge branch 'feature/decode-result-codes'
DevLn Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 157 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
# 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.)
**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.
audio, capturing snapshots, or configuring camera settings, all using asyncio for efficient performance.

## Features

- Initial camera discovery (plain and encoded (not all keys))
- Camera discovery: both `LanSearch` and `LanSearchExt` probes, plain and
encoded (not all keys) — some firmwares only answer the extended variant
- 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.
- Live MJPEG video streaming, including cameras that mux audio into the video channel (FTYC)
- **Two-way audio** on binary cameras: G.711 (A-law/µ-law) listening and talk-back to the camera speaker
- PTZ movement (up/down/left/right, step and continuous)
- White light / IR light control, image flip/mirror (camera-dependent)
- Video parameters: resolution, bitrate, etc. — set and read-back
- Snapshots (via `CMD_SNAPSHOT_GET` where supported, otherwise from the live video frame buffer)
- System commands: reboot, device status (battery, power source, Wi-Fi signal), date/time sync
(both known firmware layouts), device info, Wi-Fi settings read-out
- Automatic reconnection with backoff (`Device` high-level API)
- SD card listing and playback control *(implemented, untested on hardware)*
- Test web server with a per-camera control page, plus a protocol simulator and a
transparent DID-rewriting proxy for debugging
- Lightweight: Python 3.7+, depends only on `aiohttp`

## Tested Devices

| Prefix | Protocol | Video | [Audio<sup>*</sup>](https://github.com/devbis/aiopppp/issues/6) | PTZ | White Light | IR Light | Reboot | Resolution |
|:---------|:---------|:-----:|:---------------------------------------------------------------:|:---:|:-----------:|:--------:|:------:|:----------:|
| **DGOK** | 📜 JSON | ✅ | ✖️ | ✅ | ✅ | ✅ | ✅ | ✖️ |
| **PTZA** | 🔢 Binary| ✅ | ✖️ | ✅ | ✅ | 🚫 | ✅ | ✅ |
| **FTYC** | 🔢 Binary| [❌<sup>*</sup>](https://github.com/devbis/aiopppp/issues/8)| ✖️ | 🚫 | 🚫 | ✅ | ✅ | ✅ |
| [**BATE**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/4) | 🔢 Binary|❔ |✖️ | ❔ | ❔ | ❔ | ❔ | ❔ |
| [**DGB**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/2) | 📜 JSON |⚠️ |✖️ | ❔ | ❔ | ❔ | ❔ | ❔ |
| [**ACCQ**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/1) | ❔ Unknown|✖️|✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ |
| Prefix | Protocol | Video | Audio (listen) | Talk | PTZ | White Light | IR Light | Reboot | Resolution | Flip/Mirror | Time sync |
|:---------|:---------|:-----:|:--------------:|:----:|:---:|:-----------:|:--------:|:------:|:----------:|:-----------:|:---------:|
| **DGOK** | 📜 JSON | ✅ | ✖️ | ✖️ | ✅ | ✅ | ✅ | ✅ | ✖️ | ❔ | ✖️ |
| **PTZA** | 🔢 Binary| ✅ | | ✅ | ✅ | ✅ | 🚫 | ✅ | ✅ | 🚫 | ✅ |
| **FTYC** | 🔢 Binary| ✅ | ✅ | 🚫 | 🚫 | 🚫 | ✅ | ✅ | ✅ | ✅ | ⚠️ |
| [**BATE**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/4) | 🔢 Binary|❔ |❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ |
| [**DGB**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/2) | 📜 JSON |⚠️ |✖️ | ✖️ | ❔ | ❔ | ❔ | ❔ | ❔ | ❔ | ✖️ |
| [**ACCQ**<sup>*</sup>](https://github.com/devbis/pppp_camera/issues/1) | ❔ Unknown|✖️|✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ | ✖️ |

**Legend:**
- &nbsp;✅&nbsp; **Working**: Feature is fully functional.
Expand All @@ -34,6 +43,83 @@ capturing snapshots, or configuring camera settings, all using asyncio for effic
- &nbsp;🚫&nbsp; **Not supported**: Feature is not supported by the device.
- &ensp;❔ &nbsp; **Not tested**: Feature has not been tested on the device.

Notes: FTYC has no speaker, hence no talk-back. Time sync sets the clock on
both binary firmwares (verified within a couple of seconds of the host), but
FTYC has no timezone field to write, so its offset stays whatever the vendor
app configured — hence ⚠️ rather than ✅. JSON cameras expose no set-time
command at all. Device alias is not supported
by the tested firmwares (the vendor app doesn't implement it either).
Flip/mirror (`rotate` video param) works on FTYC, is ACKed but ignored by
PTZA. PTZ presets are implemented with the PREFAB scheme found in YsxLite
(`ptz_set_preset` / `ptz_goto_preset` / `ptz_delete_preset` /
`ptz_query_presets`) but appear **not supported by the tested cameras** — the
camera does not act on them. Left in as best-effort in case other firmwares
honor it.

## Hardware-confirmed protocol notes

These were established against real PTZA/FTYC cameras and the decompiled
vendor apps, and are encoded in the library:

- **FTYC muxes audio into the video DRW channel.** Both share the
`55 aa 15 a8` stream header; byte 4 is the stream type (`0x03` = JPEG frame
header packet, `0x06` = audio). Video frames arrive as
`[audio pkt][32-byte frame-header pkt][raw JPEG chunks…]`. The library
demuxes automatically; FTYC audio flows whenever video streams.
- **Talk-back audio must be framed** with the same 32-byte stream header
(type `0x06`, payload length at offset 16) — bare G.711 is ignored.
- **`VIDEOPARAM_GET` returns a table** of all params 1..12 (u32 each)
regardless of the requested id; the value is at `table[param_id - 1]`.
- **Two DATETIME layouts** exist: PTZA stores `(UTC epoch, tz seconds west of
UTC, ntp[64])`; FTYC has no tz field and stores a timestamp that renders as
local time (it adds its own configured offset to the UTC epoch you set).
`parse_datetime_block` auto-detects the layout; `set_datetime()` works on
both (send UTC, preserve the NTP server).
- **Status block semantics** (per the vendor SDK parser): `batLevel` is the
battery voltage in mV, and bit 0 of `powerSupply` is `externalPower`.
- **The field the SDK calls `sysUptime` is actually the Wi-Fi RSSI**, exposed
as `dbm`. The name is the only thing about it that suggests a duration: in
both vendor apps every read of it goes straight to `setWifidbm()` and is
rendered by `wlanSigGet()`, whose buckets are RSSI ranges
(−100/−85/−70/−55). There is no uptime display anywhere in either app.
Values outside a plausible −127…−1 are reported as `None`. No `uptime` key
is published.
- **`batPercent` is derived from a single-cell LiPo discharge curve**, not
from the vendor thresholds. Those thresholds only choose one of five
battery *icons* (≥4350/4200/4100/3950/3900 mV); read as percentages they
pin a fully-charged camera resting at 4195 mV to "60%" indefinitely.
`None` is returned when the field isn't a battery reading at all —
mains-only cameras park it at 8000.
- **`CMD_SNAPSHOT_GET` is not answered** by any tested camera; use the video
frame buffer for stills (the test web server does this automatically).

## Known issues

- **`start_video()` always requests HD, ignoring any resolution set
beforehand.** `_request_video(1)` sends a hardcoded HD parameter and then
re-asserts it ~5 s later, because the cameras self-downgrade and ignore the
value set at stream start. The re-assert is what makes a resolution chosen
*while streaming* stick — but it also means a resolution set while idle is
discarded, and the stall-recovery path (`_request_video(1)` again after
`VIDEO_REREQUEST_SEC` without frames) can revert a running stream to HD.

The fix is a per-session preferred resolution that `set_resolution()`
records and `_request_video()` prefers over the constant, falling back to
today's behaviour when unset. Not implemented yet.

## Untested / experimental

- **SD card & playback** (`get_sd_info`, `list_recordings`, `playback_*`):
implemented from the decompiled apps, not yet verified on hardware.
- **Wi-Fi scan / device users** (`scan_wifi`, `get_users`): return empty data
on already-configured cameras; probably only answered in AP/setup mode.
- **`set_wifi` — do not use**: the write layout very likely doesn't match the
(confirmed) 264-byte read layout and could mis-provision the camera.
- **CGI command vocabulary** (`send_cgi_command`): experimental hook for
firmwares speaking the CB_* command set; untested.
- **JSON-protocol cameras** (DGOK): functional but none of the recent fixes
were exercised against one.

## Installation

To install the library, run:
Expand All @@ -54,14 +140,17 @@ pip install aiopppp

### 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.
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.
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.

Only one client can talk to a camera at a time — close the vendor app before
connecting.

### Usage

Here’s an example of how to use the library:
Expand All @@ -79,15 +168,15 @@ async def main():
await asyncio.sleep(10)
await device.stop_video()
print("Disconnected from the device")
# or

# or

device = Device("192.168.1.2")
await device.connect()
print("Device info:", device.properties)
await device.close()


asyncio.run(main())

```
Expand All @@ -108,16 +197,16 @@ async def main():
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
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())
```

Expand All @@ -138,28 +227,59 @@ async def main():
discovery = Discovery(remote_addr='255.255.255.255')
await discovery.discover(on_device_found)


asyncio.run(main())
```

## Running test web server
## Running the 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.
The bundled web server discovers cameras and gives each one a full control page.

```bash
python -m aiopppp -u admin -p 6666
python -m aiopppp -u admin -p admin # binary cameras (PTZA/FTYC default creds)
python -m aiopppp -u admin -p 6666 # JSON cameras
python -m aiopppp -a 192.168.1.255 # directed broadcast for your camera LAN
```

Then, visit `http://localhost:4000` in your browser to view the camera feed.
Visit `http://localhost:4000` — the index lists discovered cameras; each links
to `/camera/{dev_id}` with:

- live MJPEG stream, start/stop, snapshot button
- PTZ arrows (+ preset buttons — unsupported by tested firmwares)
- white light / IR buttons
- video parameters with read-back (current values pre-select the dropdowns;
raw payload in the tooltip)
- audio: low-latency listen (Web Audio, ~0.1–0.5 s behind live), a buffered
`<audio>` fallback, and a talk-back test tone (the **camera** beeps)
- system: decoded status/device info/date-time/Wi-Fi readouts, date/time
sync, Wi-Fi scan, device users, reboot

HTTP endpoints, if you want them directly: `/{dev_id}/v` (MJPEG),
`/{dev_id}/snapshot`, `/{dev_id}/audio` (streaming WAV), `/{dev_id}/params`,
`/{dev_id}/info`, `/{dev_id}/wifi-scan`, `/{dev_id}/users`, and
`POST /{dev_id}/c/{command}`.

## Development tools

- **`binary_camera.py`** — a local protocol simulator: answers discovery,
login, video (synthetic JPEG frames), snapshots, video params, date/time,
Wi-Fi and user blocks on UDP 32108 without any hardware.
`python binary_camera.py [port]`
- **`proxy_camera.py`** — a transparent DID-rewriting relay: advertise a fake
DID to the vendor app and forward everything to a real camera, logging each
decoded control packet in both directions (video/audio never logged).
`python proxy_camera.py --did PROX-000001-CAMERA --target-ip 192.168.1.50`

## Troubleshooting

If you encounter issues:
1. Verify that your camera supports the PPPP protocol. The tested cameras had prefix DGOK, BATE, PTZA, FTYC, ...
1. 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.
2. Check credential for the camera. Use -u and -p flags to specify username and password.
3. Check your camera in the same subnet as the machine with the script running.
4. Only one client at a time: if the vendor app is connected, the library cannot connect (and vice versa).
5. Run with `--log-level DEBUG` — every session line is tagged with the device
ID, and the video path logs stream-header samples and reassembly state.

## Contributing

Expand Down
24 changes: 19 additions & 5 deletions aiopppp/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,39 @@
def get_new_device_fut():
return new_device_fut


def notify_new_device():
# The future is recreated on every main-loop iteration and is None before
# the loop starts, so guard against missing/already-resolved futures.
fut = get_new_device_fut()
if fut is not None and not fut.done():
fut.set_result(None)


def on_device_found(device, login, password):
dev_id = device.dev_id.dev_id
if dev_id in SESSIONS:
# Discovery re-finds already-connected cameras every cycle; creating a
# new session here would leak the previous one's running tasks.
return
session = make_session(device, on_device_lost=on_device_lost, login=login, password=password)
SESSIONS[device.dev_id.dev_id] = session
SESSIONS[dev_id] = session
session.start()
tasks[device.dev_id.dev_id] = session.running_tasks()
get_new_device_fut().set_result(None)
tasks[dev_id] = session.running_tasks()
notify_new_device()


def on_device_lost(device):
logger.warning('Device %s lost', device.dev_id)
SESSIONS.pop(device.dev_id.dev_id, None)
tasks.pop(device.dev_id.dev_id, None)
get_new_device_fut().set_result(None)
notify_new_device()


async def amain(remote_addr, local_port, username, password):
global discovery
global new_device_fut
discovery = Discovery(remote_addr=remote_addr)
discovery = Discovery(remote_addr=remote_addr, local_port=local_port)

discovery_task = asyncio.create_task(discovery.discover(lambda d: on_device_found(d, username, password)))
webserver_task = asyncio.create_task(start_web_server())
Expand Down
3 changes: 1 addition & 2 deletions aiopppp/__version__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
__version_tuple__ = version_tuple = (0, 2, 3)
__version__ = version = '.'.join(map(str, version_tuple))
__version__ = '0.3.0'
Loading