将 OnVif PullPoint 服务与 Zeep 结合使用
Using OnVif PullPoint Services with Zeep
我很难尝试订阅标准 IP 摄像机中的 OnVif pullpoint 服务。
我使用的 SOAP 客户端是 Zeep https://python-zeep.readthedocs.io/en/master/index.html
Zeep 似乎构建了错误的 xml 数据,但我可能是错的(由于我对 SOAP 的了解有限)。让我们看例子:
from zeep.client import Client, CachingClient, Settings
from zeep.wsse.username import UsernameToken
import zeep.helpers
import logging.config
# # Put Zeep into verbose mode
logging.config.dictConfig({
'version': 1,
'formatters': {
'verbose': {
'format': '%(name)s: %(message)s'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'zeep.transports': {
'level': 'DEBUG',
'propagate': True,
'handlers': ['console'],
},
}
})
ip="192.168.0.134"; user="admin"; passwd="123456"; port=80 # My home cam 1. Now you know its username and password. :)
settings = Settings()
settings.strict = False
settings.xml_huge_tree = True
# # WSDL File
url = "https://www.onvif.org/ver10/events/wsdl/event.wsdl"
# # *** Events Service ***
xaddr = "http://"+ip+"/onvif/events_service"
print("creating a soap client with url = ", url)
zeep_client_events = CachingClient(wsdl=url, wsse=UsernameToken(user, passwd, use_digest=True), settings=settings)
print("soap client created")
print("binding to service")
ws_client_events = zeep_client_events.create_service("{http://www.onvif.org/ver10/events/wsdl}EventBinding", xaddr)
print("service OK")
# # *** PullPoint Service ***
xaddr = "http://"+ip+"/onvif/events_service"
print("creating a soap client with url = ", url)
zeep_client_pp = CachingClient(wsdl=url, wsse=UsernameToken(user, passwd, use_digest=True), settings=settings)
print("soap client created")
print("binding to service")
ws_client_pp = zeep_client_pp.create_service("{http://www.onvif.org/ver10/events/wsdl}PullPointSubscriptionBinding", xaddr)
print("service bound")
res = ws_client_events.CreatePullPointSubscription()
# # could see the namespaces like this:
# zeep_client_pp.namespaces
# # could create PullMessages' parameters like this:
# pm = zeep_client_pp.get_element("ns7:PullMessages")()
# So, this call never works
ws_client_pp.PullMessages(MessageLimit=1, Timeout="PT1S")
根据相机的不同,这总是导致 "Remote end closed connection without response" 否则,服务器会发送一条消息,指出该值无效。
将 Zeep 置于详细模式并检查 SOAP 消息正文时(也用 Wireshark 确认了这一点),它看起来像这样:
<soap-env:Body>
<ns0:PullMessages xmlns:ns0="http://www.onvif.org/ver10/events/wsdl">
<ns0:Timeout>P%P</ns0:Timeout>
<ns0:MessageLimit>1</ns0:MessageLimit>
</ns0:PullMessages>
</soap-env:Body>
所以字符串 "PT1S" 似乎没有进入邮件正文,但 "P%P" 仍然存在!
如何说服 Zeep 插入正确的时间?
P. S. 还有,请不要告诉我使用 "python-onvif-zeep"。当然,我先这样做了,然后以这个问题结束("python-onvif-zeep" 的示例对于 pullpoint 服务不起作用)
必须属于 classisodate.Duration。这解决了问题:
import isodate
Timeout = isodate.Duration(seconds=10)
注意 events.wsdl 中使用的日期时间似乎是 XML 类型。在 Python 中,它由 datetime 的 timedelta 支持。
import datetime
timeout = datetime.timedelta(seconds=100)
ws_client_pp.PullMessages(MessageLimit=1, Timeout=timeout)
以上应用于 zeep,生成正确的请求。 100 s 是 PT1M40S。
无论如何我都无法使用我的相机,但现在的持续时间设置正确。
我很难尝试订阅标准 IP 摄像机中的 OnVif pullpoint 服务。
我使用的 SOAP 客户端是 Zeep https://python-zeep.readthedocs.io/en/master/index.html
Zeep 似乎构建了错误的 xml 数据,但我可能是错的(由于我对 SOAP 的了解有限)。让我们看例子:
from zeep.client import Client, CachingClient, Settings
from zeep.wsse.username import UsernameToken
import zeep.helpers
import logging.config
# # Put Zeep into verbose mode
logging.config.dictConfig({
'version': 1,
'formatters': {
'verbose': {
'format': '%(name)s: %(message)s'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'zeep.transports': {
'level': 'DEBUG',
'propagate': True,
'handlers': ['console'],
},
}
})
ip="192.168.0.134"; user="admin"; passwd="123456"; port=80 # My home cam 1. Now you know its username and password. :)
settings = Settings()
settings.strict = False
settings.xml_huge_tree = True
# # WSDL File
url = "https://www.onvif.org/ver10/events/wsdl/event.wsdl"
# # *** Events Service ***
xaddr = "http://"+ip+"/onvif/events_service"
print("creating a soap client with url = ", url)
zeep_client_events = CachingClient(wsdl=url, wsse=UsernameToken(user, passwd, use_digest=True), settings=settings)
print("soap client created")
print("binding to service")
ws_client_events = zeep_client_events.create_service("{http://www.onvif.org/ver10/events/wsdl}EventBinding", xaddr)
print("service OK")
# # *** PullPoint Service ***
xaddr = "http://"+ip+"/onvif/events_service"
print("creating a soap client with url = ", url)
zeep_client_pp = CachingClient(wsdl=url, wsse=UsernameToken(user, passwd, use_digest=True), settings=settings)
print("soap client created")
print("binding to service")
ws_client_pp = zeep_client_pp.create_service("{http://www.onvif.org/ver10/events/wsdl}PullPointSubscriptionBinding", xaddr)
print("service bound")
res = ws_client_events.CreatePullPointSubscription()
# # could see the namespaces like this:
# zeep_client_pp.namespaces
# # could create PullMessages' parameters like this:
# pm = zeep_client_pp.get_element("ns7:PullMessages")()
# So, this call never works
ws_client_pp.PullMessages(MessageLimit=1, Timeout="PT1S")
根据相机的不同,这总是导致 "Remote end closed connection without response" 否则,服务器会发送一条消息,指出该值无效。
将 Zeep 置于详细模式并检查 SOAP 消息正文时(也用 Wireshark 确认了这一点),它看起来像这样:
<soap-env:Body>
<ns0:PullMessages xmlns:ns0="http://www.onvif.org/ver10/events/wsdl">
<ns0:Timeout>P%P</ns0:Timeout>
<ns0:MessageLimit>1</ns0:MessageLimit>
</ns0:PullMessages>
</soap-env:Body>
所以字符串 "PT1S" 似乎没有进入邮件正文,但 "P%P" 仍然存在!
如何说服 Zeep 插入正确的时间?
P. S. 还有,请不要告诉我使用 "python-onvif-zeep"。当然,我先这样做了,然后以这个问题结束("python-onvif-zeep" 的示例对于 pullpoint 服务不起作用)
必须属于 classisodate.Duration。这解决了问题:
import isodate
Timeout = isodate.Duration(seconds=10)
注意 events.wsdl 中使用的日期时间似乎是 XML 类型。在 Python 中,它由 datetime 的 timedelta 支持。
import datetime
timeout = datetime.timedelta(seconds=100)
ws_client_pp.PullMessages(MessageLimit=1, Timeout=timeout)
以上应用于 zeep,生成正确的请求。 100 s 是 PT1M40S。
无论如何我都无法使用我的相机,但现在的持续时间设置正确。