使用python-onvif-zeep或valkka向IPcamera发送VISCA命令,并从DeviceIO发送rec



问题

我最近获得了一个活跃的硅ip摄像机,我一直试图使用python-onvif-zeep或valkka来控制它。摄像机实现ONVIF Profile S标准。我想使用DeviceIO wsdl中描述的SendReceiveSerialData服务向相机发送缩放/我们的,焦点和其他基本的VISCA命令,但是我似乎无法让它工作。我在ONVIF, SOAP和zeep方面的知识相当有限,所以如果它太明显,请原谅我!

最小可复制示例和所需更改

<编辑>绝笔

这是我的python代码(我已经用valkka替换了原来的python-onvif-zeep代码,因为它使一切都更整洁):

#! /usr/bin/env python3
from valkka.onvif import OnVif, DeviceManagement, Media, DeviceIO, PTZ, getWSDLPath
from zeep import Client
import zeep.helpers
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)
# element = deviceIO_service.zeep_client.get_element('ns10:SendReceiveSerialCommand')
# print(element)
ports = deviceIO_service.ws_client.GetSerialPorts()
# print (ports)
serial_token = ports[0].token
# print(serial_token)
zoomin = bytes.fromhex('81 01 04 07 02 FF')
#zoomout = bytes.fromhex('81 01 04 07 03 FF')
#zoomin = b'x81x01x04x07x02xff'
data = {
'SerialData': zoomin
}
ack = deviceIO_service.ws_client.SendReceiveSerialCommand(serial_token, data)
print(ack)
time.sleep(3)

我遇到的第一个问题是SendReceiveSerialCommand服务不工作,发生了以下错误:

raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
<编辑>需要修改

背后的原因是deviceIO。库的WSDL文件。它不包含"记号"。元素,不像DeviceIO wsdl,因此我必须在SendReceiveSerialCommand元素下手动添加它:

<xs:element name="SendReceiveSerialCommand">
<xs:annotation>
<xs:documentation>Transmitting arbitrary data to the connected serial device and then receiving its response data.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Token" type="tt:ReferenceToken" minOccurs="0">
<xs:annotation>
<xs:documentation>The physical serial port reference to be used when this request is invoked.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="SerialData" type="tmd:SerialData" minOccurs="0">
<xs:annotation>
<xs:documentation>The serial port data.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="TimeOut" type="xs:duration" minOccurs="0">
<xs:annotation>
<xs:documentation>Indicates that the command should be responded back within the specified period of time.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="DataLength" type="xs:integer" minOccurs="0">
<xs:annotation>
<xs:documentation>This element may be put in the case that data length returned from the connected serial device is already determined as some fixed bytes length. It indicates the length of received data which can be regarded as available.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Delimiter" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>This element may be put in the case that the delimiter codes returned from the connected serial device is already known. It indicates the termination data sequence of the responded data. In case the string has more than one character a device shall interpret the whole string as a single delimiter. Furthermore a device shall return the delimiter character(s) to the client.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SendReceiveSerialCommandResponse">
<xs:annotation>
<xs:documentation>Receiving the response data.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="SerialData" type="tmd:SerialData" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>

这部分修复后,错误消失,但相机不能放大/缩小(取决于传递的是哪个VISCA命令)。此外,确认返回为"none"。

如果我用SendReceiveSerialCommand服务中的所有字段填充字典,则没有任何变化,如下所示:

serial_data = {
'SerialData': zoomin,
'TimeOut': "PT0M0.1S",
'DataLength': "100",
'Delimiter': "",
}

置>我在Ubuntu 20.04和python 3.8上运行这个python脚本。设置是相机和笔记本电脑之间的网络,并分配静态IP地址。

请注意,相机正在工作,因为我可以通过web界面成功地向相机发送命令,并且当在Windows机器上运行它附带的c#示例(可以在下载->software中找到)时。

提前感谢您的时间和精力来帮助我!

我设法让你的例子工作使用以下代码。数据没有以正确的格式传递给函数,因此SOAP消息是不完整的。

关于传递SOAP数据结构的详细信息,请查看zeep文档。

deviceio_type_factory = deviceIO_service.zeep_client.type_factory("http://www.onvif.org/ver10/deviceIO/wsdl")
serial_data = deviceio_type_factory.SerialData(Binary=zoomin)
ack = deviceIO_service.ws_client.SendReceiveSerialCommand(Token= ports[0].token, SerialData=serial_data, TimeOut='PT0M6S', DataLength='100', Delimiter='')
visca_ack_comp = ack['Binary'].hex()
print(visca_ack_comp )

这是我从相机得到的:9041ff9051ff (ACK + COMP)。

注意,您可以使用来自ONVIF的WDSL文件,而不是创建您自己的文件,因为那个文件是正确的。

class MyDeviceIO(OnVif):
wsdl_file = "https://www.onvif.org/ver10/deviceio.wsdl"
namespace = "http://www.onvif.org/ver10/deviceIO/wsdl"
sub_xaddr = "DeviceIO"
port      = "DeviceIOBinding"

最新更新