Browse Source

dvrip: add Detect (motion detection) config wrappers

Thin wrappers `get_detect_info()` / `set_detect_info(data)` in both the
sync (`dvrip.py`) and async (`asyncio_dvrip.py`) clients for the
top-level `Detect` config path — per-channel MotionDetect /
HumanDetection (and, on multi-channel NVRs, BlindDetect / LossDetect).

The library already supported this via the generic `get_info("Detect")` /
`set_info("Detect", …)`, but the path and payload shape were undocumented.
README now carries a worked example showing the per-channel-array schema
and the sparse-merge semantics (fields omitted from a SET payload retain
their current value), plus a caveat that AlarmInfo push behaviour is
firmware-dependent — some XM builds emit events to the existing TCP
session, others only to a separately-configured `AlarmServer`, and some
do neither.

Verified on a live XM IPC unit (single-channel, hostname
IVG85HG50PYA-S-2): the canonical OpenIPC "turn motion detection on"
snippet returns `Ret: 100`, round-trip GET shows the change, sparse merge
works (`{"MotionDetect":[{"Level":4}]}` flips only `Level`).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
pull/7/head
Dmitry Ilyin 5 days ago
parent
commit
578985c46b
  1. 37
      README.md
  2. 8
      asyncio_dvrip.py
  3. 7
      connect.py
  4. 8
      dvrip.py

37
README.md

@ -460,6 +460,43 @@ cloudEnabled = False
cam.set_info("NetWork.Nat", { "NatEnable" : cloudEnabled }) cam.set_info("NetWork.Nat", { "NatEnable" : cloudEnabled })
``` ```
## Motion detection
Xiongmai cameras typically do **not** expose ONVIF `AnalyticsService`, so
motion detection cannot be configured through ONVIF. On some firmwares it
is also off by default. Configure it directly over the native protocol via
the `Detect` config path:
```python
# Inspect current config (per-channel arrays)
print(cam.get_detect_info())
# {'HumanDetection': [{'Enable': False, ...}],
# 'MotionDetect': [{'Enable': True,
# 'EventHandler': {'RecordEnable': True,
# 'AlarmOutEnable': False, ...},
# 'Level': 5}]}
# Enable motion detection at sensitivity 5 with event-triggered recording.
# Sparse payloads are merged — fields you omit keep their current values.
cam.set_detect_info({
"MotionDetect": [{"Enable": True,
"EventHandler": {"RecordEnable": True},
"Level": 5}],
"HumanDetection": [{"Enable": False}],
})
```
The equivalent low-level call is `cam.set_info("Detect", ...)` — both
shapes work; the wrapper just documents the path.
Receiving the events is a separate problem. Some XM firmwares push
`AlarmInfo` packets over the existing TCP session, so registering
`setAlarm()` + `alarmStart()` is enough; on others the camera only emits
to a separately-configured alarm server (see `AlarmServer.py` and the
`EventHandler.AlarmInfo` / `MsgtoNetEnable` fields). If `setAlarm()`
silently produces no callbacks even while recordings show motion is
detected, the camera is likely in the latter group.
## Add user and change password ## Add user and change password
```python ```python

8
asyncio_dvrip.py

@ -580,6 +580,14 @@ class DVRIPCam(object):
code = 1042 code = 1042
return await self.get_command("Simplify.Encode", code) return await self.get_command("Simplify.Encode", code)
async def get_detect_info(self):
"""Read 'Detect' config: per-channel MotionDetect / HumanDetection / etc."""
return await self.get_info("Detect")
async def set_detect_info(self, data):
"""Update 'Detect' config. Sparse payloads are merged with current state."""
return await self.set_info("Detect", data)
async def recv_json(self, buf=bytearray()): async def recv_json(self, buf=bytearray()):
p = compile(b".*({.*})") p = compile(b".*({.*})")

7
connect.py

@ -27,6 +27,13 @@ info["OSDInfo"][0]["OSDInfoWidget"]["PreviewBlend"] = True
# info["OSDInfo"][0]["OSDInfoWidget"]["RelativePos"] = [6144,6144,8192,8192] # info["OSDInfo"][0]["OSDInfoWidget"]["RelativePos"] = [6144,6144,8192,8192]
cam.set_info("fVideo.OSDInfo", info) cam.set_info("fVideo.OSDInfo", info)
# enc_info = cam.get_info("Simplify.Encode") # enc_info = cam.get_info("Simplify.Encode")
# Motion detection: turn it on and route events into recording.
# cam.set_detect_info({
# "MotionDetect": [{"Enable": True,
# "EventHandler": {"RecordEnable": True},
# "Level": 5}],
# "HumanDetection": [{"Enable": False}],
# })
# Alarm example # Alarm example
def alarm(content, ids): def alarm(content, ids):
print(content) print(content)

8
dvrip.py

@ -703,6 +703,14 @@ class DVRIPCam(object):
code = 1042 code = 1042
return self.get_command("Simplify.Encode", code) return self.get_command("Simplify.Encode", code)
def get_detect_info(self):
"""Read 'Detect' config: per-channel MotionDetect / HumanDetection / etc."""
return self.get_info("Detect")
def set_detect_info(self, data):
"""Update 'Detect' config. Sparse payloads are merged with current state."""
return self.set_info("Detect", data)
def recv_json(self, buf=bytearray()): def recv_json(self, buf=bytearray()):
p = compile(b".*({.*})") p = compile(b".*({.*})")

Loading…
Cancel
Save