python-zeep icon indicating copy to clipboard operation
python-zeep copied to clipboard

Failing to parse response from ONVIF Pullmessages method

Open barban-dev opened this issue 3 years ago • 1 comments

Zeep version : 4.0.0 Python: 3.9.1 OS: Linux kali 5.9.0 x86_64 GNU/Linux WSDL used: http://www.onvif.org/ver10/events/wsdl/event.wsdl

I am trying to use Zeep with ONVIF camera to get alarms via PullPointSubscription and PullMessages method (e.g. tns1:VideoSource/MotionAlarm alarm). XML parsing of the PullMessageResponse received from the server produces invalid output as reported below (Topic is set to None, _value_1 is set to Message at 0xXXXXXXX); nevertheless I was able to get the correct output using suds. I don't know if it could be relevant, but the "Topic Dialect" reference in the returned XML data is not valid (404 error): http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet

Received XML:

<s:Envelope
    xmlns:sc="http://www.w3.org/2003/05/soap-encoding"
    xmlns:s="http://www.w3.org/2003/05/soap-envelope"
    xmlns:tt="http://www.onvif.org/ver10/schema"
    xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
    xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
    xmlns:wsa5="http://www.w3.org/2005/08/addressing"
    xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
    xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
    xmlns:tns1="http://www.onvif.org/ver10/topics">
    <s:Header>
        <wsa5:Action>
            http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse
            </wsa5:Action>
        <wsa5:To>
            http://192.168.1.242/onvif/Subscription?Idx=206
            </wsa5:To>
        </s:Header>
    <s:Body>
        <tev:PullMessagesResponse>
            <tev:CurrentTime>
                2021-01-09T17:44:23Z
                </tev:CurrentTime>
            <tev:TerminationTime>
                2021-01-09T17:45:15Z
                </tev:TerminationTime>
            <wsnt:NotificationMessage>
                <wsnt:Topic
                    Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
                    tns1:RuleEngine/CellMotionDetector/Motion
                    </wsnt:Topic>
                <wsnt:Message>
                    <tt:Message
                        UtcTime="2021-01-09T17:44:21Z"
                        PropertyOperation="Changed">
                        <tt:Source>
                            <tt:SimpleItem
                                Name="VideoSourceConfigurationToken"
                                Value="00000"/>
                            <tt:SimpleItem
                                Name="VideoAnalyticsConfigurationToken"
                                Value="00000"/>
                            <tt:SimpleItem
                                Name="Rule"
                                Value="00000"/>
                            </tt:Source>
                        <tt:Data>
                            <tt:SimpleItem
                                Name="IsMotion"
                                Value="true"/>
                            </tt:Data>
                        </tt:Message>
                    </wsnt:Message>
                </wsnt:NotificationMessage>
            <wsnt:NotificationMessage>
                <wsnt:Topic
                    Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
                    tns1:VideoSource/MotionAlarm
                    </wsnt:Topic>
                <wsnt:Message>
                    <tt:Message
                        UtcTime="2021-01-09T17:44:21Z"
                        PropertyOperation="Changed">
                        <tt:Source>
                            <tt:SimpleItem
                                Name="Source"
                                Value="00000"/>
                            </tt:Source>
                        <tt:Data>
                            <tt:SimpleItem
                                Name="State"
                                Value="true"/>
                            </tt:Data>
                        </tt:Message>
                    </wsnt:Message>
                </wsnt:NotificationMessage>
            </tev:PullMessagesResponse>
        </s:Body>
    </s:Envelope>

Parsed output:

{
    'CurrentTime': datetime.datetime(2021, 1, 9, 17, 44, 23, tzinfo=<isodate.tzinfo.Utc object at 0x7f0219d73b50>),
    'TerminationTime': datetime.datetime(2021, 1, 9, 17, 45, 15, tzinfo=<isodate.tzinfo.Utc object at 0x7f0219d73b50>),
    'NotificationMessage': [
        {
            'SubscriptionReference': None,
            'Topic': {
                '_value_1': None,
                'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
                '_attr_1': {
            }
            },
            'ProducerReference': None,
            'Message': {
                '_value_1': <Element {http://www.onvif.org/ver10/schema}Message at 0x7f0219b4d980>
            }
        },
        {
            'SubscriptionReference': None,
            'Topic': {
                '_value_1': None,
                'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
                '_attr_1': {
            }
            },
            'ProducerReference': None,
            'Message': {
                '_value_1': <Element {http://www.onvif.org/ver10/schema}Message at 0x7f0219b4dbc0>
            }
        }
    ]
}

Runnable debug script to reproduce the issue:

import pretend    # pip install pretend
from zeep import Client
from zeep.transports import Transport

wdsl = 'http://www.onvif.org/ver10/events/wsdl/event.wsdl'
client = Client(wdsl)

response = pretend.stub(
status_code=200,
headers={},
#The response from the server (onvif camera)
content="""<s:Envelope xmlns:sc="http://www.w3.org/2003/05/soap-encoding" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:tns1="http://www.onvif.org/ver10/topics"><s:Header><wsa5:Action> http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse </wsa5:Action><wsa5:To> http://192.168.1.242/onvif/Subscription?Idx=206 </wsa5:To></s:Header><s:Body><tev:PullMessagesResponse><tev:CurrentTime> 2021-01-09T17:44:23Z </tev:CurrentTime><tev:TerminationTime> 2021-01-09T17:45:15Z </tev:TerminationTime><wsnt:NotificationMessage><wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"> tns1:RuleEngine/CellMotionDetector/Motion </wsnt:Topic><wsnt:Message><tt:Message UtcTime="2021-01-09T17:44:21Z" PropertyOperation="Changed"><tt:Source><tt:SimpleItem Name="VideoSourceConfigurationToken" Value="00000"/><tt:SimpleItem Name="VideoAnalyticsConfigurationToken" Value="00000"/><tt:SimpleItem Name="Rule" Value="00000"/></tt:Source><tt:Data><tt:SimpleItem Name="IsMotion" Value="true"/></tt:Data></tt:Message></wsnt:Message></wsnt:NotificationMessage><wsnt:NotificationMessage><wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">tns1:VideoSource/MotionAlarm</wsnt:Topic><wsnt:Message><tt:Message UtcTime="2021-01-09T17:44:21Z" PropertyOperation="Changed"><tt:Source><tt:SimpleItem Name="Source" Value="00000"/></tt:Source><tt:Data><tt:SimpleItem Name="State" Value="true"/></tt:Data></tt:Message></wsnt:Message></wsnt:NotificationMessage></tev:PullMessagesResponse></s:Body></s:Envelope>""")

operation_name = 'PullMessages'

service = client.create_service(
    '{http://www.onvif.org/ver10/events/wsdl}PullPointSubscriptionBinding',
    'http://my-endpoint.com/acceptance/')

operation = service._binding._operations[operation_name]
result = service._binding.process_reply(client, operation, response)

#xml parsing is error free but fields from NotificationMessage are invalid
print(result)

barban-dev avatar Jan 10 '21 17:01 barban-dev

@barban-dev Maybe a bit late, but i struggled with the same issue. But i finally found what the problem is. The 'Message' field is defined as type 'any'. That basically means it can be anything. Because it is not defined and there is no schema for it, zeep cannot decode it. But what the documentation does not tell you (or at least i could not find it) is that it returns a 'lxml.etree._element'. Zeep uses the 'lxml' package for parsing the xml. It basically contains the complete XML node. I wrote a bit of demo code to shows how to decode the result:

from lxml import etree

-- your debug script ---

for msg in result.NotificationMessage:
    if isinstance(msg.Message._value_1, etree._Element):
        etree.dump(msg.Message._value_1)
        source = msg.Message._value_1.find('./{*}Source')
        for child in source.getchildren():
            print(child.tag, child.attrib)
        data = msg.Message._value_1.find('./{*}Data')
        for child in data.getchildren():
            print(child.tag, child.attrib)

Victor-Mo avatar Nov 30 '21 15:11 Victor-Mo