FalkTannhaeuser / python-onvif-zeep

ONVIF Client Implementation in Python 2+3 (using https://github.com/mvantellingen/python-zeep instead of suds as SOAP client)
MIT License
445 stars 145 forks source link

Python onvif PTZ ContinuousMove has an error Argument Value Invalid #98

Open lsirikh opened 2 years ago

lsirikh commented 2 years ago

I am currently making a program to control onvif using python.

The problem is that there is an error that does not work properly in certain cameras.

The original Python text and the Request and Response Soap xml text are attached together.

In particular, there is a problem with motor control on the PTZ side.

Package                 Version
----------------------- --------------------
anyio                   3.6.2
onvif-zeep              0.2.12
zeep                    4.1.0
"""Example to fetch pullpoint events."""
import asyncio
import datetime as dt
import logging

from pytz import UTC
from zeep import xsd

from onvif import ONVIFCamera

logging.getLogger("zeep").setLevel(logging.DEBUG)

class OnvifTestClass():
    def __init__(self) -> None:
        print("OnvifTestClass was created")

    async def run(self):
        self.mycam = ONVIFCamera(
            "192.168.1.65",
            80,
            "admin",
            "pass12345",
            wsdl_dir="C:/Users/Sensorway/source/python/python-onvif-zeep-async/onvif/wsdl",
        )

        #mycam.update_xaddrs()
        self.mycam.update_xaddrs()
        # try:
        #     self.analytics_service = self.mycam.create_analytics_service()
        # except:
        #     pass
        # try:
        #     self.devicemgmt_service = self.mycam.create_devicemgmt_service()
        # except:
        #     pass

        # try:
        #     self.deviceio_service = self.mycam.create_deviceio_service()
        # except:
        #     pass

        # try:
        #     self.event_service = self.mycam.create_events_service()
        #     for item in self.mycam.xaddrs:
        #         if "event" in item:
        #             factory = self.event_service.zeep_client.type_factory(item)
        #             print(factory)
        #             break
        # except:
        #     pass

        # try:
        #     self.imaging_service = self.mycam.create_imaging_service()
        # except:
        #     pass

        try:
            self.media_service = self.mycam.create_media_service()
            self.media_service_profiles = self.media_service.GetProfiles()
            #print(self.media_profiles)
            self.media_service_profile = self.media_service.GetProfiles()[0]
        except:
            pass

        # try:
        #     self.onvif_service = self.mycam.create_onvif_service()
        # except:
        #     pass

        try:
            self.ptz_service = self.mycam.create_ptz_service()
        except:
            pass

        try:
            self.pullPoint_service = self.mycam.create_pullpoint_service()
        except:
            pass

        # try:
        #     self.receiver_service = self.mycam.create_receiver_service()
        # except:
        #     pass

        # try:
        #     self.recording_service = self.mycam.create_recording_service()
        # except:
        #     pass

        # try:
        #     self.replay_service = self.mycam.create_replay_service()
        # except:
        #     pass

        # try:
        #     self.search_service = self.mycam.create_search_service()
        # except:
        #     pass

        #self.eventTest()
        self.getPtzConfig()
        self.ptzContinuous()
        #self.ptzStop()

    def eventTest(self):
        try:

            service = self.pullPoint_service.zeep_client._get_service('EventService')
            port = self.pullPoint_service.zeep_client._get_port(service, 'PullPointSubscription')
            port.binding_options['address'] = self.mycam.xaddrs['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription']
            plp = self.pullPoint_service.zeep_client.bind('EventService', 'PullPointSubscription')
            plp.PullMessages(Timeout=dt.timedelta(seconds=20), MessageLimit=100)
        except Exception as e:
            print("Exception raised during eventTest : ", e)
            pass

    def getPtzConfig(self):
        try:
            # Get PTZ configuration options for getting continuous move range
            request = self.ptz_service.create_type('GetConfigurationOptions')
            request.ConfigurationToken = self.media_service_profile.PTZConfiguration.token
            self.ptz_configuration_options = self.ptz_service.GetConfigurationOptions(request)
            print('PTZ configuration options:', self.ptz_configuration_options)

        except Exception as e:
            print("Exception raised during getPtzConfig : ", e)
            pass

    def ptzStop(self):
        try:
            request = self.ptz_service.create_type('ContinuousMove')
            status = self.ptz_service.GetStatus({'ProfileToken': self.media_service_profile.token})
            print('PTZ status:', status)
            request.ConfigurationToken = self.media_service_profile.PTZConfiguration.token
            request.PanTilt = True
            request.Zoom = True
            print('PTZ request:', request)

        except Exception as e:
            print("Exception raised during ptzStop : ", e)
            pass

    def ptzContinuous(self):
        try:
            request = self.ptz_service.create_type('ContinuousMove')
            request.ProfileToken = self.media_service_profile.token
            #request.ProfileToken = self.media_service_profile.PTZConfiguration.token
            #request.NodeToken = self.media_service_profile.PTZConfiguration.NodeToken
            request.Velocity = {'PanTilt': {'x': 0.5, 'y': 0.5}, 'Zoom': 0.0}
            request.Timeout = "PT10S"
            self.ptz_service.ContinuousMove(request)

        except Exception as e:
            print("Exception raised during ptzStop : ", e)
            pass

    def setVelocity(self, request):
        try:
            request.Velocity = self.ptz_service.GetStatus({'ProfileToken': self.media_service_profile.token}).Position
            request.Velocity.PanTilt.space = self.ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].URI
            request.Velocity.Zoom.space = self.ptz_configuration_options.Spaces.ContinuousZoomVelocitySpace[0].URI
            return request

        except Exception as e:
            print("Exception raised during setVelocity : ", e)
            return 

    def setMax(self):
        # Get range of pan and tilt
        # NOTE: X and Y are velocity vector
        try:
            self.XMAX = self.ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Max
            self.XMIN = self.ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].XRange.Min
            self.YMAX = self.ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Max
            self.YMIN = self.ptz_configuration_options.Spaces.ContinuousPanTiltVelocitySpace[0].YRange.Min
            self.ZMAX = self.ptz_configuration_options.Spaces.ContinuousZoomVelocitySpace[0].XRange.Max
            self.ZMIN = self.ptz_configuration_options.Spaces.ContinuousZoomVelocitySpace[0].XRange.Min
        except Exception as e:
            print("Exception raised during setMax : ", e)

if __name__ == "__main__":
    test_class = OnvifTestClass()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(test_class.run())
DEBUG:zeep.transports:HTTP Post to http://192.168.1.65:80/onvif/ptz:
<?xml version='1.0' encoding='utf-8'?>
<soap-env:Envelope xmlns:soap-env="http://www.w3.org/2003/05/soap-envelope">
<soap-env:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">BHlDKgrQxtAtAI0f/uky17bF0oI=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">KcX+EgBq2kYMw1Rz7Lg6PQ==</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2022-11-10T07:49:23+00:00</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap-env:Header>
<soap-env:Body>
<ns0:ContinuousMove xmlns:ns0="http://www.onvif.org/ver20/ptz/wsdl">
<ns0:ProfileToken>ProfileA01</ns0:ProfileToken>
<ns0:Velocity>
<ns1:PanTilt xmlns:ns1="http://www.onvif.org/ver10/schema" x="0.5" y="0.5"/>
<ns2:Zoom xmlns:ns2="http://www.onvif.org/ver10/schema" x="0.0"/>
</ns0:Velocity>
<ns0:Timeout>PT10S</ns0:Timeout>
</ns0:ContinuousMove>
</soap-env:Body>
</soap-env:Envelope>

DEBUG:zeep.transports:HTTP Response from http://192.168.1.65:80/onvif/ptz (status: 200):
<soap:Envelope 
xmlns:soap="http://www.w3.org/2003/05/soap-envelope" 
xmlns:ter="http://www.onvif.org/ver10/error" 
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" 
xmlns:wsntw="http://docs.oasis-open.org/wsn/2004/06/wsn-WS-BaseNotification-1.2-draft-01.wsdl" 
xmlns:xs="http://www.w3.org/2000/10/XMLSchema" 
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value><soap:Subcode>
<soap:Value>ter:InvalidArgVal</soap:Value>
<soap:Subcode>
<soap:Value>ter:NoEntity</soap:Value>
</soap:Subcode>
</soap:Subcode>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">Argument Value Invalid</soap:Text>
</soap:Reason>
<soap:Node>http://www.w3.org/2003/05/soap-envelope/node/ultimateReceiver</soap:Node>
<soap:Role>http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver</soap:Role>
</soap:Fault>
</soap:Body>
</soap:Envelope>
igorq777 commented 1 year ago

try removing ns0 from the query