简体   繁体   English

使用来自 DeviceIO 的 python-onvif-zeep 或 valkka 和 sendreceiveserialcommand 服务向 IPcamera 发送 VISCA 命令

[英]Send VISCA commands to IPcamera using python-onvif-zeep or valkka and sendreceiveserialcommand service from DeviceIO

The problem问题

I have recently acquired an Active Silicon IP-camera and I have been trying to control it using python-onvif-zeep or valkka .我最近获得了一个有源硅网络摄像机,我一直在尝试使用python-onvif-zeepvalkka来控制它。 The camera implements the ONVIF Profile S standard.该摄像机执行 ONVIF Profile S 标准。 I would like to send zoom in / our, focus and other basic VISCA commands to the camera using the SendReceiveSerialData service as described in the DeviceIO wsdl , however I can not seem to get it to work.我想使用DeviceIO wsdl中所述的 SendReceiveSerialData 服务向相机发送放大/我们、聚焦和其他基本 VISCA 命令,但我似乎无法让它工作。 My knowledge in ONVIF, SOAP, and zeep is quite limited so please forgive me if its something too obvious!我对ONVIF、SOAP和zeep的了解非常有限,如果说的太明显还请见谅!

Minimal reproducible example and needed changes最小的可重现示例和需要的更改

MRE MRE

Here is the python code I have (I have replaced the original python-onvif-zeep code I had with valkka because it makes everything a bit neater):这是我拥有的 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'\x81\x01\x04\x07\x02\xff'

data = {
    'SerialData': zoomin
}

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

The first issue I encountered was that the SendReceiveSerialCommand service was not working and the following error occurred:我遇到的第一个问题是 SendReceiveSerialCommand 服务没有工作,出现了以下错误:

raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))
Needed changes需要的改变

The reason behind that is the deviceIO.wsdl file of the library.其背后的原因是库的 deviceIO.wsdl 文件。 It does not contain the "Token" element, unlike DeviceIO wsdl ,therefore I had to manually add it under the SendReceiveSerialCommand element:它不包含“Token”元素,不像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>

After this part was fixed the errors go away, but the camera does not zoom in/out ( depending on which VISCA command is being passed).修复此部分后,错误 go 消失,但相机不会放大/缩小(取决于传递的 VISCA 命令)。 Additionally, the acknowledgement comes back as "None".此外,确认返回为“无”。

Nothing changes if I fill the dictionary with all the fields from the SendReceiveSerialCommand service like so:如果我用 SendReceiveSerialCommand 服务中的所有字段填充字典,则没有任何变化,如下所示:

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

The setup设置

I am running this python script on Ubuntu 20.04 with python 3.8.我在 Ubuntu 20.04 和 python 3.8 上运行这个 python 脚本。 The setup is a.network between the camera and the laptop with static IP addresses assigned.设置是相机和笔记本电脑之间的网络,分配了 static IP 地址。

Please note that the camera is working as I can successfully send commands to the camera over the web interface and when running the C# example (can be found under downloads->software) it comes with, on a Windows machine.请注意,相机正在工作,因为我可以通过 web 接口成功向相机发送命令,并且在 Windows 机器上运行它附带的C# 示例(可以在下载->软件下找到)。

Thank you in advance for your time and effort to help me out!预先感谢您花时间和精力帮助我!

I managed to get your example to work using the following code.我设法使用以下代码让您的示例正常工作。 The data was not passed in the correct format to the function, so the SOAP message was incomplete.数据未以正确格式传递给 function,因此 SOAP 消息不完整。

Check the zeep documentation for details about passing SOAP datastructures.查看zeep 文档以了解有关传递 SOAP 数据结构的详细信息。

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 )

Here is what I get from the camera: 9041ff9051ff (ACK + COMP).这是我从相机得到的:9041ff9051ff (ACK + COMP)。

Note, you could use the WDSL file from ONVIF instead of creating your own, as that one is correct.请注意,您可以使用来自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"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM