You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python通过ONVIF DeviceIO发送VISCA指令控制IP摄像机?

无法通过ONVIF DeviceIO的SendReceiveSerialCommand发送VISCA指令控制摄像机变焦

问题背景

刚入手一台Active Silicon IP摄像机,设备支持ONVIF Profile S标准。尝试使用python-onvif-zeep或valkka库,通过DeviceIO WSDL定义的SendReceiveSerialCommand服务发送VISCA变焦、对焦等指令,但始终无法成功。

最小复现代码

#! /usr/bin/env python3

from valkka.onvif import DeviceManagement, DeviceIO
from zeep.wsse.username import UsernameToken
import time

try:
    device_service = DeviceManagement(
        ip="10.0.0.250",
        port=8000,
        user="",
        password=""
    )
except Exception as e:
    print(e)

cap = device_service.ws_client.GetCapabilities()
print("CAPABILITIES: \n{}".format(cap))
srv = device_service.ws_client.GetServices(True)
print("SERVICES: \n{}".format(srv))

try:
    deviceIO_service = DeviceIO(
        ip="10.0.0.250",
        port=8000,
        user="",
        password=""
    )
except Exception as e:
    print(e)

ports = deviceIO_service.ws_client.GetSerialPorts()
serial_token = ports[0].token

zoomin = bytes.fromhex('81 01 04 07 02 FF')

data = {
    'SerialData': zoomin
}

ack = deviceIO_service.ws_client.SendReceiveSerialCommand(serial_token, data)
print(ack)
time.sleep(3)

遇到的问题

  1. 初始连接错误:
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))

手动给库中deviceIO.wsdl添加Token元素后,连接错误消失,但摄像机无变焦响应,SendReceiveSerialCommand返回None,补充TimeOut、DataLength等参数也无改善。

  1. 环境信息:Ubuntu 20.04 + Python 3.8,摄像机与笔记本通过静态IP组网,Web界面及官方C#示例可正常控制设备。

排查与修复步骤

1. 修正VISCA指令的编码方式

多数ONVIF设备要求SerialData参数为Base64编码字符串,而非直接传递bytes对象。调整代码中SerialData的处理逻辑:

import base64

zoomin = bytes.fromhex('81 01 04 07 02 FF')
# 将VISCA指令转为Base64编码字符串
serial_data_base64 = base64.b64encode(zoomin).decode('utf-8')

# 构造完整参数(包含设备可能要求的必填项)
params = {
    'SerialPortToken': serial_token,
    'SerialData': serial_data_base64,
    'TimeOut': 5000,  # 超时时间(单位:毫秒,根据设备手册调整)
    'DataLength': len(zoomin)
}

ack = deviceIO_service.ws_client.SendReceiveSerialCommand(**params)

2. 验证WSDL文件的正确性

手动修改库自带的WSDL可能引发参数映射错误:

  • 从摄像机官方获取最新的DeviceIO WSDL文件,替换valkka/python-onvif-zeep库中的对应文件;
  • 用zeep打印WSDL接口定义,确认参数结构与设备要求匹配:
print(deviceIO_service.zeep_client.wsdl.dump())

3. 绕过valkka封装,直接用zeep调用

如果valkka的封装存在兼容性问题,直接使用zeep创建客户端:

from zeep import Client
import base64

# 替换为正确的DeviceIO WSDL路径/URL
wsdl_url = "http://10.0.0.250:8000/onvif/deviceIO?wsdl"
client = Client(
    wsdl_url,
    wsse=UsernameToken("", ""),
    address="http://10.0.0.250:8000/onvif/deviceIO_service"
)

ports = client.service.GetSerialPorts()
serial_token = ports[0].token

zoomin = bytes.fromhex('81 01 04 07 02 FF')
serial_data_base64 = base64.b64encode(zoomin).decode('utf-8')

ack = client.service.SendReceiveSerialCommand(
    SerialPortToken=serial_token,
    SerialData=serial_data_base64,
    TimeOut=5000
)
print(ack)

4. 抓包对比官方请求

用Wireshark抓取官方C#示例的ONVIF请求,与Python代码的请求对比,重点检查:

  • SOAP请求的XML结构是否一致;
  • SerialData的编码格式;
  • 请求头的认证信息、命名空间是否正确。

5. 确认串口配置匹配

调用GetSerialPorts()返回的串口参数,需与VISCA协议要求一致:

  • 波特率:9600;
  • 数据位:8;
  • 停止位:1;
  • 校验方式:无校验。

内容的提问来源于stack exchange,提问作者ekptwtos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:40:43