Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onvif.exceptions.ONVIFError: Unknown error: ('Connection aborted.', BadStatusLine('POST... *HTTP/1.1 500 Internal Server Error\r\n')) #118

Open
kim1037 opened this issue Oct 30, 2023 · 4 comments

Comments

@kim1037
Copy link

kim1037 commented Oct 30, 2023

Hi, I was trying to connect TP-Link tapo C220 ip camera with python, but I 'm stuck on a problem. Here is my code :

import time
from onvif import ONVIFCamera
import zeep
import requests
from requests.auth import HTTPDigestAuth
wsdl_path = r'C:/Users/user/Desktop/python-onvif/python-onvif-zeep/wsdl'
camera_ip = '192.168.X.XXX'
username = 'user'
password = '123456'

def zeep_pythonvalue(self, xmlvalue):
    return xmlvalue
 
def absolute_move():
    pan = 0
    pan_speed = 1
    tilt = 0
    tilt_speed = 1

    mycam = ONVIFCamera(camera_ip, 80, username, password, wsdl_path)

    # Create media service object
    media = mycam.create_media_service()
    # Create ptz service object
    ptz = mycam.create_ptz_service()
 
    # Get target profile
    zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
    media_profile = media.GetProfiles()[0]
 
    request = ptz.create_type('AbsoluteMove')
    request.ProfileToken = media_profile.token
    ptz.Stop({'ProfileToken': media_profile.token})
 
    if request.Position is None:
        request.Position = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
    if request.Speed is None:
        request.Speed = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
 
    request.Position.PanTilt.x = pan
    request.Speed.PanTilt.x = pan_speed
 
    request.Position.PanTilt.y = tilt
    request.Speed.PanTilt.y = tilt_speed
 
    ptz.AbsoluteMove(request)
    print('finish')

def snap():
    # Get target profile
    zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
    mycam = ONVIFCamera(camera_ip, 80, username, password, wsdl_path)
    media = mycam.create_media_service()  
    media_profile = media.GetProfiles()[0] 
    res = media.GetSnapshotUri({'ProfileToken': media_profile.token})
    response = requests.get(res.Uri, auth=HTTPDigestAuth("admin", "pass"))
    res = "{_time}.png".format(_time=time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime(time.time())))
    with open(res, 'wb') as f:
        f.write(response.content)
 
def gotoPreset():
    zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
    mycam = ONVIFCamera(camera_ip, 80, username, password, wsdl_path)
    media = mycam.create_media_service()
    ptz = mycam.create_ptz_service()
    params = ptz.create_type('GotoPreset')
    media_profile = media.GetProfiles()[0] 
    print(media_profile.token)
    params.ProfileToken = media_profile.token
    params.PresetToken = 1
    re = ptz.GotoPreset(params)
    print(re)
 
def getStatus():
    zeep.xsd.simple.AnySimpleType.pythonvalue = zeep_pythonvalue
    mycam = ONVIFCamera(camera_ip, 80, username, password, wsdl_path)
    media = mycam.create_media_service()
    ptz = mycam.create_ptz_service()
    params = ptz.create_type('GetStatus')
    media_profile = media.GetProfiles()[0]
    print(media_profile.token)
    params.ProfileToken = media_profile.token
    res = ptz.GetStatus(params)
    print(res)
 
if __name__ == '__main__':
    absolute_move()
    snap()
    gotoPreset()
    getStatus()

When I start this code, it is the error message:

Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connectionpool.py", line 790, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connectionpool.py", line 536, in _make_request
response = conn.getresponse()
^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connection.py", line 461, in getresponse
httplib_response = super().getresponse()
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 1378, in getresponse
response.begin()
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 318, in begin
version, status, reason = self._read_status()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 300, in _read_status
raise BadStatusLine(line)
http.client.BadStatusLine: POST /onvif/serviceHTTP/1.1Host 192.168.1.xxx:xxxUser-Agent Zeep/4.2.1 (www.python-zeep.org)Accept-Encoding gzip, deflateAccept *HTTP/1.1 500 Internal Server Error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\requests\adapters.py", line 486, in send
resp = conn.urlopen(
^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connectionpool.py", line 844, in urlopen
retries = retries.increment(
^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\util\retry.py", line 470, in increment
raise reraise(type(error), error, _stacktrace)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\util\util.py", line 38, in reraise
raise value.with_traceback(tb)
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connectionpool.py", line 790, in urlopen
response = self._make_request(
^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connectionpool.py", line 536, in _make_request
response = conn.getresponse()
^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\urllib3\connection.py", line 461, in getresponse
httplib_response = super().getresponse()
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 1378, in getresponse
response.begin()
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 318, in begin
version, status, reason = self._read_status()
^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\http\client.py", line 300, in _read_status
raise BadStatusLine(line)
urllib3.exceptions.ProtocolError: ('Connection aborted.', BadStatusLine('POST /onvif/service\x00HTTP/1.1\x00\x00Host\x00 192.168.1.xxx:xxx\x00\x00User-Agent\x00 Zeep/4.2.1 (www.python-zeep.org)\x00\x00Accept-Encoding\x00 gzip, deflate\x00\x00Accept\x00 *HTTP/1.1 500 Internal Server Error\r\n'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\onvif_zeep-0.2.12-py3.11.egg\onvif\client.py", line 25, in wrapped
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\onvif_zeep-0.2.12-py3.11.egg\onvif\client.py", line 150, in wrapped
return call(params, callback)
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\onvif_zeep-0.2.12-py3.11.egg\onvif\client.py", line 138, in call
ret = func(**params)
^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\zeep-4.2.1-py3.11.egg\zeep\proxy.py", line 46, in call
return self._proxy._binding.send(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\zeep-4.2.1-py3.11.egg\zeep\wsdl\bindings\soap.py", line 127, in send
response = client.transport.post_xml(options["address"], envelope, http_headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\zeep-4.2.1-py3.11.egg\zeep\transports.py", line 108, in post_xml
return self.post(address, message, headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\zeep-4.2.1-py3.11.egg\zeep\transports.py", line 74, in post
response = self.session.post(
^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\requests\sessions.py", line 637, in post
return self.request("POST", url, data=data, json=json, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\requests\sessions.py", line 589, in request
resp = self.send(prep, **send_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\requests\sessions.py", line 703, in send
r = adapter.send(request, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\requests\adapters.py", line 501, in send
raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', BadStatusLine('POST /onvif/service\x00HTTP/1.1\x00\x00Host\x00 192.168.1.xxx:xxx\x00\x00User-Agent\x00 Zeep/4.2.1 (www.python-zeep.org)\x00\x00Accept-Encoding\x00 gzip, deflate\x00\x00Accept\x00 *HTTP/1.1 500 Internal Server Error\r\n'))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:\Users\user\Desktop\vision\vision\onvif_control.py", line 102, in
absolute_move()
File "c:\Users\user\Desktop\vision\vision\onvif_control.py", line 44, in absolute_move
request.Position = ptz.GetStatus({'ProfileToken': media_profile.token}).Position
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\AppData\Local\Programs\Python\Python311\Lib\site-packages\onvif_zeep-0.2.12-py3.11.egg\onvif\client.py", line 27, in wrapped
raise ONVIFError(err)
onvif.exceptions.ONVIFError: Unknown error: ('Connection aborted.', BadStatusLine('POST /onvif/service\x00HTTP/1.1\x00\x00Host\x00 192.168.1.xxx:xxx\x00\x00User-Agent\x00 Zeep/4.2.1 (www.python-zeep.org)\x00\x00Accept-Encoding\x00 gzip, deflate\x00\x00Accept\x00 *HTTP/1.1 500 Internal Server Error\r\n'))`

What's wrong with my code? Thanks

@schauveau
Copy link

I have a similar problem with a Tapo 500. Basically, nothing works so I captured the traffic and I figured out that the Tapo does not like the GetCapabilities request.

request.xml:

    <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>
                        xxxxxxxxx
                        </wsse:Username>
                    <wsse:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                        xxxxxxxxxxx
                        </wsse:Password>
                    </wsse:UsernameToken>
                </wsse:Security>
            </soap-env:Header>
        <soap-env:Body>
            <ns0:GetCapabilities xmlns:ns0="http://www.onvif.org/ver10/device/wsdl"/>
        </soap-env:Body>
   </soap-env:Envelope>

When I use curl to do the POST request, it returns an error. I believe that there was not even a reply. The connection is simply closed.

# curl -k -X POST --header 'Content-Type: text/xml; charset=utf-8' -d @request.xml "http://192.168.1.26:2020/onvif/device_service"
curl: (1) Received HTTP/0.9 when not allowed
-:1: parser error : Document is empty

I eventually found what seems to be the problem: The Tapo does not like the self-closing tag <ns0:GetCapabilities ... />.

For example, the following GetCapabilities request works fine

<?xml version=1.0' encoding='utf-8'>
<soap-env:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <soap-env:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"></GetCapabilities>
    </soap-env:Body>
</soap-env:Envelope>

but that one does not

<?xml version=1.0' encoding='utf-8'>
<soap-env:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
    <soap-env:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <GetCapabilities xmlns="http://www.onvif.org/ver10/device/wsdl"/>
    </soap-env:Body>
</soap-env:Envelope>

This is quite a problem because there are probably a lot of onvif clients that do not work on the tapo for the same reason.

I will try to fill a ticket at Tp-Link about.

Is there a way to prevent onvif-zeep to produce closing tags?

@schauveau
Copy link

I figured out how to prevent self-closing tags. The XML is produced in package zeep by the function etree_to_string in wsdl/utils.py
The trick is to insert an empty text in all empty elements so

 def etree_to_string(node):
    for elem in node.iter():
        if elem.text == None:
            elem.text = ''
    return etree.tostring(
        node, pretty_print=False, xml_declaration=True, encoding="utf-8"
    )

So I can now successfully do the GetCapabilities and a few other requests.

I still get a disconnection later in my test script but this is probably because I am trying to use an feature that is not supported by my Tapo 500 (i.e. PTZ ContinuousMove)

@schauveau
Copy link

I noticed some self-closing tag in a network trace from another onvif tool that appears to be working fine so my initial diagnostic is probably incorrect. Something odd is happening here!!!

@gurka
Copy link

gurka commented Oct 17, 2024

Another workaround is to do GetCapabilities({"Category": "All"})

I think that it would return the same thing as providing no argument, but I'm not sure.

I also seem to remember reading somewhere, either in a ZoneMinder repo or HomeAssistant repo, something about this being fixed by upgrading zeep, but I can't find that ticket/comment/commit/PR now...

Edit: nevermind. I just tried it with zeep 4.3.1 and it still results in a 500 response.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants