KonradIT / gopro-py-api

Unofficial GoPro API Library for Python - connect to GoPro via WiFi.
MIT License
1.39k stars 211 forks source link

Problem with GoProHero3+ #109

Closed harwood-yoha closed 3 years ago

harwood-yoha commented 5 years ago

Hi been trying to solve this for a couple of days - HERO3+Silver - wonder if you have any ideas

gpCam.overview() File "/usr/local/lib/python3.5/dist-packages/goprocam-3.0.3-py3.5.egg/goprocam/GoProCamera.py", line 1437, in overview self.getStatus(constants.Hero3Status.Mode))) File "/usr/local/lib/python3.5/dist-packages/goprocam-3.0.3-py3.5.egg/goprocam/GoProCamera.py", line 239, in getStatus data = self.getStatusRaw() File "/usr/local/lib/python3.5/dist-packages/goprocam-3.0.3-py3.5.egg/goprocam/GoProCamera.py", line 263, in getStatusRaw return self._request("camera/sx?t=" + self.getPassword()) File "/usr/local/lib/python3.5/dist-packages/goprocam-3.0.3-py3.5.egg/goprocam/GoProCamera.py", line 112, in _request return urllib.request.urlopen(uri, timeout=_timeout, context=_context).read().decode("utf-8") UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 11: invalid start byte

yet-another-average-joe commented 5 years ago

Use Python 3.6+, not 3.5 !

harwood-yoha commented 5 years ago

I'm using 3.6 - been trying to work out what is going on for a couple of days sorry for bothering you.

KonradIT commented 5 years ago

Hi,

This is hard to debug for me because I don't have a HERO3 generation camera anymore, I dug up my old HERO4 Black, used constants.auth in the GoPro() constructor and tried to debug the issue, but I can't get any response from it using camera/sx. Incidentally, the password does work because gopro.shutter(constants.start) works.

I would need more details in order to fix this, including the output of http://10.5.5.9/bacpac/sd (CAUTION: this outputs the password of your camera, change it in the app before sending). I did some minor refactoring of the API thinking it wouldn't affect sub-HERO4 cameras. Anyone else have issues with their HERO3 cameras regarding getting the password?

yet-another-average-joe commented 5 years ago

On my side, with a H3+Black and the last version of the library, overview() works fine and getPassword() has no issues. (Don't know if this helps...)

harwood-yoha commented 5 years ago

Hi Konrad - I managed to find an old version of GoProCamera.py - using python 3.4 - which I have attached - this one worked apart from the line 1017

print("current photo resolution: " +

self.parse_value(constants.Hero3Status.PicRes,self.getStatus(constants.Hero3Status.PicRes)))

Hope this helps you with the debug

H

On 19/07/19 22:42, yet-another-average-joe wrote:

On my side, with a H3+Black and the last version of the library, overview() works fine and getPassword() has no issues. (Don't know if this helps...)

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/KonradIT/gopro-py-api/issues/109?email_source=notifications&email_token=AA33XZUFXOQIVCN6HXTZ4WDQAIYLXA5CNFSM4IFJII7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2M2YEA#issuecomment-513387536, or mute the thread https://github.com/notifications/unsubscribe-auth/AA33XZSGZNSQRMTOTCP2FGTQAIYLXANCNFSM4IFJII7A.

LucasMOHIMONT commented 5 years ago

Hi, I have the same problem with a GoPro Hero 3 Silver. With this code: from goprocam import GoProCamera from goprocam import constants

gpCam = GoProCamera.GoPro(constants.auth) gpCam.take_photo() gpCam.downloadLastMedia(path='img')

When I use an older version of the API I get this:

ValueError Traceback (most recent call last) ~\Anaconda3\lib\http\client.py in _read_status(self) 281 try: --> 282 status = int(status) 283 if status < 100 or status > 999:

ValueError: invalid literal for int() with base 10: 'ÿûAllow:'

During handling of the above exception, another exception occurred:

BadStatusLine Traceback (most recent call last)

in 3 4 gpCam = GoProCamera.GoPro(constants.auth) ----> 5 gpCam.take_photo() 6 gpCam.downloadLastMedia(path='img') ~\Anaconda3\lib\site-packages\goprocam\GoProCamera.py in take_photo(self, timer) 513 return "" 514 print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") --> 515 def getMediaInfoFront(self, option): 516 folder = "" 517 file = "" ~\Anaconda3\lib\site-packages\goprocam\GoProCamera.py in getMedia(self) 571 year=str(now.year)[-2:] 572 datestr_year=format(int(year), 'x') --> 573 datestr_month=format(now.month, 'x') 574 datestr_day=format(now.day, 'x') 575 datestr_hour=format(now.hour, 'x') ~\Anaconda3\lib\site-packages\goprocam\GoProCamera.py in _request(self, path, param, value, _timeout, _isHTTPS, _context) 111 if not value == "": 112 value_notempty=str('&p=%' + value) --> 113 #sends parameter and value to /camera/ 114 try: 115 urllib.request.urlopen('http://' + self.ip_addr + '/camera/' + param + '?t=' + self.getPassword() + value_notempty, timeout=5).read() ~\Anaconda3\lib\urllib\request.py in urlopen(url, data, timeout, cafile, capath, cadefault, context) 220 else: 221 opener = _opener --> 222 return opener.open(url, data, timeout) 223 224 def install_opener(opener): ~\Anaconda3\lib\urllib\request.py in open(self, fullurl, data, timeout) 523 req = meth(req) 524 --> 525 response = self._open(req, data) 526 527 # post-process response ~\Anaconda3\lib\urllib\request.py in _open(self, req, data) 541 protocol = req.type 542 result = self._call_chain(self.handle_open, protocol, protocol + --> 543 '_open', req) 544 if result: 545 return result ~\Anaconda3\lib\urllib\request.py in _call_chain(self, chain, kind, meth_name, *args) 501 for handler in handlers: 502 func = getattr(handler, meth_name) --> 503 result = func(*args) 504 if result is not None: 505 return result ~\Anaconda3\lib\urllib\request.py in http_open(self, req) 1343 1344 def http_open(self, req): -> 1345 return self.do_open(http.client.HTTPConnection, req) 1346 1347 http_request = AbstractHTTPHandler.do_request_ ~\Anaconda3\lib\urllib\request.py in do_open(self, http_class, req, **http_conn_args) 1318 except OSError as err: # timeout error 1319 raise URLError(err) -> 1320 r = h.getresponse() 1321 except: 1322 h.close() ~\Anaconda3\lib\http\client.py in getresponse(self) 1319 try: 1320 try: -> 1321 response.begin() 1322 except ConnectionError: 1323 self.close() ~\Anaconda3\lib\http\client.py in begin(self) 294 # read until we get a non-100 response 295 while True: --> 296 version, status, reason = self._read_status() 297 if status != CONTINUE: 298 break ~\Anaconda3\lib\http\client.py in _read_status(self) 284 raise BadStatusLine(line) 285 except ValueError: --> 286 raise BadStatusLine(line) 287 return version, status, reason 288 BadStatusLine: HTTP/1.1 ÿûAllow: GET
mbugert commented 4 years ago

I can confirm that Hero 3 support is very broken in version 3.0.9.

A major issue is that _request decodes all responses into utf-8 strings: https://github.com/KonradIT/gopro-py-api/blob/756b84896f289f3de852c51f373c4e1b9e7cf427/goprocam/GoProCamera.py#L100-L112

Several methods calling _request expect byte-strings, such as getPassword, whichCam, getStatus (maybe more). Removing .decode("utf-8") in the above code snippet makes it work for the Hero 3, but I don't know what the consequences for other models are.

Also, getMedia is broken because it requests gp/gpMediaList which doesn't exist on Hero 3's.

findell666 commented 4 years ago

Hello, on a web browser 10.5.5.9:8080/gp/gpMediaList works with hero3 !

yet-another-average-joe commented 4 years ago

It seems I wasn't using the latest version... Finally, same problem here with a GoPro3H+, after I reinstalled OctoPi (comes with Python 3.7) and installed the newest gopro-py-api release.

Removing the decode() calls as suggested by @mbugert seems to solve the problem.

@KonradIT : the problem seems to be really easy to solve : in init(), line 42, a flag could be set for H2 and H3, and then checked in _request(), so decode("utf8") will be called or not depending on the camera model. I'm not familiar with Python (honestly I never did the effort to learn it just because I hate the identations !). Not sure where I could define such a flag (what object). A global variable could do it, it is quick, but really dirty. If you tell me where, I could do a PR.

KonradIT commented 4 years ago

Hi everyone, thanks for pointing out the fix @mbugert , will push a fix ASAP. I don't have a Hero3 or 3+ for testing anymore. Oldest camera I have is a Hero4.

yet-another-average-joe commented 4 years ago

I can do all the testing you could need. Dedicated RasPi 3B, and GoPro H3+.

KonradIT commented 4 years ago

Just released https://pypi.org/project/goprocam/4.0.3/ with hopefully Hero3 fix.

Overall, the API wrapper is in poor state, when I wrote the bulk of the code in 2017 my Python skills were severely lacking (back then I only knew Java and JS), which means no usage of Exceptions, error checking, callbacks, decorators... Right now I know more advanced Python usage and will start to add these badly needed features.

yet-another-average-joe commented 4 years ago

I tested your last release (4.0.3)

unfortunately, there's still an error, related to utf8 (seems to be related to password :

` Traceback (most recent call last): File "/usr/lib/python3.7/http/client.py", line 292, in _read_status status = int(status) ValueError: invalid literal for int() with base 10: 'ÿûAllow:'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 183, in whichCam response_raw = self._request("gp/gpControl") File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 112, in _request return urllib.request.urlopen(uri, timeout=_timeout, context=_context).read().decode("utf-8") File "/usr/lib/python3.7/urllib/request.py", line 222, in urlopen return opener.open(url, data, timeout) File "/usr/lib/python3.7/urllib/request.py", line 525, in open response = self._open(req, data) File "/usr/lib/python3.7/urllib/request.py", line 543, in _open '_open', req) File "/usr/lib/python3.7/urllib/request.py", line 503, in _call_chain result = func(*args) File "/usr/lib/python3.7/urllib/request.py", line 1345, in http_open return self.do_open(http.client.HTTPConnection, req) File "/usr/lib/python3.7/urllib/request.py", line 1320, in do_open r = h.getresponse() File "/usr/lib/python3.7/http/client.py", line 1336, in getresponse response.begin() File "/usr/lib/python3.7/http/client.py", line 306, in begin version, status, reason = self._read_status() File "/usr/lib/python3.7/http/client.py", line 296, in _read_status raise BadStatusLine(line) http.client.BadStatusLine: HTTP/1.1 ÿûAllow: GET

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "", line 1, in File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 38, in init self._camera = self.whichCam() File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 228, in whichCam self.power_on_auth() File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 443, in power_on_auth return self.sendBacpac("PW", "01") File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 167, in sendBacpac self.getPassword() + value_notempty) File "/usr/local/lib/python3.7/dist-packages/goprocam-4.0.2-py3.7.egg/goprocam/GoProCamera.py", line 66, in getPassword password = str(self._request("bacpac/sd"), "utf-8") TypeError: decoding str is not supported

`

yet-another-average-joe commented 4 years ago

Had an idea... H3 and H2 are hugely outdated. Why not freezing the last known good realease as "H2/3 edition branch", and flagging it as "unsupported" ? But what version ??? I have problems with Git desktop, and don't know how to use it in console mode, so I don't know how to explore older releases...

Looking at the issues, nobody or nearly nobody posts about the old GoPros !

Code for older GoPros seems to be very different from newer ones, and it probably could make code maintenance easier (I remember maintaining sources for apps for Windows Desktop + Windows Mobile 3-4-5-6 with conditionnal compilation ; it was a such a pain I gave up ! )

KonradIT commented 4 years ago

Ah, Will revert the change then. I'll probably just buy a Hero3 second hand, I see a few locally for 60€. https://paypal.me/konradit if anyone wants to contribute.

yet-another-average-joe commented 4 years ago

Done. H3 are overpriced. I see the cheapest one at 105€ on eBay (including P&P). This is crazy ! Pretty sure this can be solved without having to get one. First thing to do : find out when the H3 code was broken. I have a working version on one Pi, but no idea what version it is. Sources are in 3 files. It was installed on 2019-03-02 acccording to timestamps.

The funniest thing is I don't even really use your API ; I experiment, so GoPro support can be intergrated in someone else's 3D printer timelapse plugin... and I can't do timelapses ! (no time, no room for proper lightings and background because of the wife acceptance factor)

KonradIT commented 4 years ago

So, to clarify, you need to specify which camera you are connecting to when using a Hero2 or Hero3 or Hero3+. This is done via:

gpCam = GoProCamera.GoPro(constants.Camera.Interface.Auth)

Because then _request will not do the UTF parsing bit if the camera is not GPControl.

yet-another-average-joe commented 4 years ago

I don't understand a word !

And the more I read Python code, the more I hate it. ;)

[EDIT] not your code, I hate Python itself !

But I got your library to work very easily with my H3+BE, adding a few lines of code. Following @mbugert information, I added a global boolean, isH2orH3, (True if H2 or H3), and depending on this flag, decode("utf-8") is called or not. Maybe it's dirty but it works like a charm !

GoProCamera.py.gz

mannyluccio commented 4 years ago

Hi, i've fixed the above error but replacing the GoProCamera.py with the one you provided. I'm using a simple script to take photo every 10 seconds, but the script crash when the 2nd photo is taken with this error:

` File "C:\Python\Python36\lib\http\client.py", line 283, in _read_status status = int(status) ValueError: invalid literal for int() with base 10: 'ÿûAllow:'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "scricca.py", line 5, in goproCamera.shoot_video(10) File "C:\Python\Python36\lib\site-packages\goprocam\GoProCamera.py", line 547, in shoot_video return self.getMedia() File "C:\Python\Python36\lib\site-packages\goprocam\GoProCamera.py", line 587, in getMedia raw_data = self._request("gp/gpMediaList") File "C:\Python\Python36\lib\site-packages\goprocam\GoProCamera.py", line 123, in _request return urllib.request.urlopen(uri, timeout=_timeout, context=_context).read() File "C:\Python\Python36\lib\urllib\request.py", line 223, in urlopen return opener.open(url, data, timeout) File "C:\Python\Python36\lib\urllib\request.py", line 526, in open response = self._open(req, data) File "C:\Python\Python36\lib\urllib\request.py", line 544, in _open '_open', req) File "C:\Python\Python36\lib\urllib\request.py", line 504, in _call_chain result = func(*args) File "C:\Python\Python36\lib\urllib\request.py", line 1346, in http_open return self.do_open(http.client.HTTPConnection, req) File "C:\Python\Python36\lib\urllib\request.py", line 1321, in do_open r = h.getresponse() File "C:\Python\Python36\lib\http\client.py", line 1331, in getresponse response.begin() File "C:\Python\Python36\lib\http\client.py", line 297, in begin version, status, reason = self._read_status() File "C:\Python\Python36\lib\http\client.py", line 287, in _read_status raise BadStatusLine(line) http.client.BadStatusLine: HTTP/1.1 ÿûAllow: GET`

Any advise on how to solve it?

Incineratinq commented 3 years ago

hi, i noticed you closed the issue but i'm still getting the same error on version pypi goprocam 4.0.3 with my Hero3+ Silver, is there a confirmed workaround? or will you push a fix? i am willing to test for you if you need testing still (feel free to add me on discord - maya#4588)

i ran the "Quick start" code here:


Python 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 22:39:24) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from goprocam import GoProCamera, constants
>>> goproCamera = GoProCamera.GoPro()
HTTP/1.1 ÿûAllow: GET

Traceback (most recent call last):
  File "C:\Program Files (x86)\Python38-32\lib\http\client.py", line 289, in _read_status
    status = int(status)
ValueError: invalid literal for int() with base 10: 'ÿûAllow:'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 183, in whichCam
    response_raw = self._request("gp/gpControl")
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 112, in _request
    return urllib.request.urlopen(uri, timeout=_timeout, context=_context).read().decode("utf-8")
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 525, in open
    response = self._open(req, data)
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 542, in _open
    result = self._call_chain(self.handle_open, protocol, protocol +
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 502, in _call_chain
    result = func(*args)
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 1348, in http_open
    return self.do_open(http.client.HTTPConnection, req)
  File "C:\Program Files (x86)\Python38-32\lib\urllib\request.py", line 1323, in do_open
    r = h.getresponse()
  File "C:\Program Files (x86)\Python38-32\lib\http\client.py", line 1322, in getresponse
    response.begin()
  File "C:\Program Files (x86)\Python38-32\lib\http\client.py", line 303, in begin
    version, status, reason = self._read_status()
  File "C:\Program Files (x86)\Python38-32\lib\http\client.py", line 293, in _read_status
    raise BadStatusLine(line)
http.client.BadStatusLine: HTTP/1.1 ÿûAllow: GET

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 38, in __init__
    self._camera = self.whichCam()
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 228, in whichCam
    self.power_on_auth()
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 443, in power_on_auth
    return self.sendBacpac("PW", "01")
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 167, in sendBacpac
    self.getPassword() + value_notempty)
  File "C:\Users\Incineratinq\AppData\Roaming\Python\Python38\site-packages\goprocam\GoProCamera.py", line 66, in getPassword
    password = str(self._request("bacpac/sd"), "utf-8")
TypeError: decoding str is not supported