From a109529de3b42c5daa1f1b17e10730d0fcfce505 Mon Sep 17 00:00:00 2001 From: konradit Date: Thu, 25 Oct 2018 12:08:04 +0200 Subject: [PATCH] Add docs --- README.md | 606 +--------------------------------------- docs/docs.md | 248 ++++++++++++++++ goprocam/GoProCamera.py | 77 ++++- setup.py | 2 +- 4 files changed, 328 insertions(+), 605 deletions(-) create mode 100644 docs/docs.md diff --git a/README.md b/README.md index eb0b4e1..5a9d5a2 100644 --- a/README.md +++ b/README.md @@ -35,610 +35,23 @@ python setup.py install **Tested on Python 3.6.0** -- **works on Linux and Windows and Mac** -### Documentation: - -#### HERO4 and newer (gpcontrol) - -These cameras use a new version of GoPro API which centers around /gp/gpControl/ url. - -| Code | Explanation | -|------|-------------| -| gpControlCommand(X,Y) | Sends a command to the camera, using GoPro constants | -| gpControlSet(X,Y) | Sends a setting to the camera, using GoPro constants | -| shutter(param) | Starts a video or takes a picture
param=constants.start or constants.stop | -| shoot_video(X) | Shoots a video, X is the number of seconds the video will be, default 0, (infinity) | -| take_photo(X) | Takes a photo, X is the time before the picture is taken. Default 0. Returns URL | -| video_settings(X,Y) | Changes the video settings
| -| mode(X,Y) | Changes the mode, X=Mode, Y=Submode (default is 0). Example: camera_mode(constants.Mode.PhotoMode, constants.Mode.SubMode.Photo.Single) | -| getStatusRaw() | Returns the status dump of the camera in json | -| getStatus(X,Y) | Returns the status.
| -| infoCamera(option) | Returns camera information
option = constants.Camera.Name/Number/Firmware/SerialNumber/SSID/MacAddress | -| overview() | Prints a general overview of the camera status. | -| parse_value(X,Y) | Parses integers to human strings (mode/sub_mode/rem_space/etc...) | -| delete() | Can be: delete(last) or delete(all) | -| deleteFile(folder,file) | Deletes a specific file | -| hilight() | HiLights a moment in the video recording | -| power_on() | Powers the camera on. NOTE: run this to put your H4 Session into app mode first! | -| power_off() | Powers the camera off | -| syncTime() | Syncs the camera time to the computer's time | -| locate(param) | Makes the camera beep. locate(constants.Locate.Start) for start and locate(constants.Locate.Stop) for stop. | -| getMedia() | returns the last media taken URL | -| downloadLastMedia() | Downloads latest media taken | -| downloadMedia(folder, file) | Downloads specified file, eg: 100GOPRO, GOPR0005.MP4 | -| listMedia(option, array) | Outputs a prettified JSON media list, for parsed output option must be True. Optional: ```array``` can be set to True and it will return an array with media items. | -| getMediaInfo(option) | Gets the media info
option=file/folder/size | -| downloadMedia(folder,file) | Downloads a speficic file, folder and file needed. Example: downloadMedia("104GOPRO","GOPR0001.JPG") -| downloadLowRes(path) | If video path is specified, it will download the LRV version of the MP4 video (path needs to be a full MP4 video path). If not specified it will get the latest video recorded and download that.
Only framerates below 60FPS supported. | -| getVideoInfo(option, file, folder) | Similar to getMediaInfo() but this will return the video duration or number of hilight tags.
Option can be: dur/tag_count/tags/profile. Optional: specify file and folder. | -| livestream(param) | Starts, restarts or stops the livefeed via UDP. | -| stream(path) | Streams the gopro feed to a specified ```path```, such as udp://127.0.0.1:10000, FFmpeg needed! | -| streamSettings(bitrate, resolution) | Sets the live stream's bitrate and resolution (HERO4/5) | -| pair() | Allows for camera initial pairing, pass usepin=False for HERO5,6 | -| getClip(file, resolution, fps, start_ms, stop_ms) | Gets a subclip from a video (even a TimeLapse video), similar to GoPro Capture's clip extraction (they do it via http-range) but this one saves it to the SD card.
file = the file to get a clip from in the form of [XXX]GOPRO/GOPRXXXX.MP4
resolution = the resolution to resize it, constants.Clip.R1080p/R720p/R640p
fps = the fps division to perform on the clip: constants.Clip.FPS_NORMAL (leave as is)/FPS_2 (divide by 2)/FPS_4/FPS_8...
start_ms & stop_ms = the start and stop time of the clip in milliseconds. - -#### HERO3/HERO3+/HERO2 (auth): - -These cameras use the traditional /camera/ or /bacpac/ GoPro API, which is now deprecated and replaced with gpControl for newer cameras starting with HERO 4. - -| Code | Explanation | -|------|-------------| -| sendCamera(X,Y) | Sends a command to the camera using /camera/. Use constants.Hero3Commands. | -| sendBacpac(X,Y) | Sends a command to the camera using /bacpac/. Use constants.Hero3Commands. | -| shutter(param) | Starts a video or takes a picture
param=constants.start or constants.stop | -| shoot_video(X) | Shoots a video, X is the number of seconds the video will be, default 0, (infinity) | -| take_photo(X) | Takes a photo, X is the time before the picture is taken. Default 0. | -| video_settings(X,Y) | Changes the video settings
| -| mode(X,Y) | Changes the mode, X=Mode: constants.Hero3Commands.Mode.VideoMode/PhotoMode/BurstMode/TimeLapseMode | -| getStatusRaw() | Returns the status dump of the camera in json | -| getStatus(status) | Gets camera status, status can be constants.Hero3Status.Mode/SpotMeter/TimeLapseInterval/FOV/Beep/LED/AutoOff/VideoRes/FPS/Loop/WhiteBalance/IsRecording/Pictures | -| infoCamera(option) | Returns camera information
option = model_name, firmware_version, ssid -| delete() | Can be: delete(last) or delete(all) | -| deleteFile(folder,file) | Deletes a specific file | -| power_on_auth() | Powers the camera on. | -| power_off() | Powers the camera off | -| syncTime() | Syncs the camera time to the computer's time | -| getMedia() | returns the last media taken URL | -| downloadLastMedia() | Downloads latest media taken | -| listMedia() | Outputs a prettified JSON media list | -| getMediaInfo(option) | Gets the media info
option=file/folder/size | -| downloadMedia(folder,file) | Downloads a speficic file, folder and file needed. Example: downloadMedia("104GOPRO","GOPR0001.JPG") -| downloadLowRes(path) | If video path is specified, it will download the LRV version of the MP4 video (path needs to be a full MP4 video path). If not specified it will get the latest video recorded and download that.
Only framerates below 60FPS supported. | -| getVideoInfo(option) | Similar to getMediaInfo() but this will return the video duration or number of hilight tags.
Option can be: dur/tag_count/tags/profile. Optional: specify file and folder. | -| livestream(param) | Starts, restarts or stops the livefeed /live/amba.m3u8 | -| stream(path) | Streams the gopro feed to a specified ```path```, such as udp://127.0.0.1:10000, FFmpeg needed! | - -### Usage: - -You can do a ton of stuff with this library, here is a snippet of how some of the commands can be used: - -```python -from goprocam import GoProCamera -from goprocam import constants - -gpCam = GoProCamera.GoPro() -``` - -NOTE: You can initialise with ```GoProCamera.GoPro()``` and it will detect which camera is connected and what API to use, this can be unreliable as I have only tested it with HERO4 and HERO3. If you want to connect to a specific camera use ```GoProCamera.GoPro(constants.gpcontrol)``` for HERO4/5/HERO+ and ```GoProCamera.GoPro(constants.auth)``` for HERO3/HERO3+. - -If you want to specify a MAC address for the camera (only for HERO4/5/HERO+): - -**IMPORTANT**: This is necessary for HERO5 Session/Black and HERO4 Session. - -```GoProCamera.GoPro(mac_address="...")``` - ---- - -NOTE: Some commands are HERO4/5 only and viceversa: gpControlCommand/gpControlSet/gpControlExecute are for HERO4/5 only, sendBacpac/sendCamera are HERO3/3+ only. Make sure you use the right constant for getStatus according to your camera. - -#### Commands: - -* Start or stop - -You can start a video or stop it, also take pictures or timelapses. This works with all cameras. - -To start a video or take a picture: -```python -gpCam.shutter(constants.start) -``` - -To stop a video or timelapse: -```python -gpCam.shutter(constants.stop) -``` - -* Change Modes: - -You can change camera modes. Second line only works with HERO4 Black/Silver/Session and HERO5 Black/Session (due to them having Modes and submodes.) - -```python -gpCam.mode(constants.Mode.VideoMode) -gpCam.mode(constants.Mode.VideoMode, constants.Video.SubMode.Looping) -``` - -* Hilight taging: - -HERO4 and newer only: You can set a hilight tag on a video. - -```python -gpCam.hilight() -``` - -* Locate camera: - -This will make the camera start beeping. - -```python -gpCam.locate(constants.start) -... -gpCam.locate(constants.stop) -``` - -* Turn camera on or off: - -Depending on your specified camera, you can turn it on or off with a separate command. - -For HERO4 and newer (gpcontrol): - -```python -gpCam.power_on() -``` - -For HERO3/3+ (auth): - -```python -gpCam.power_on_auth() -``` - -To power off, regardless of camera used: - -```python -gpCam.power_off() -``` - -* Quickly take a photo: - -You can quickly snap a photo with just one command, you can specify a timer if you wish. This works with all cameras. - -```python -gpCam.take_photo(10) #will wait 10 seconds before taking the picture -``` - -It will return the photo URL - -* Quickly shoot a video: - -You can start a video with just one command, you can specify the duration of the video, if you don't the video will not be stopped. This works with all cameras. - -```python -gpCam.shoot_video() #starts a video -gpCam.shoot_video(40) #shoots a 40 second video -``` - -* Quickly change the video resolution: - -This command will set the video resolution and frame rate specified, it will need to be typed between commas. Make sure your camera supports the video resolution and frame rate specified. - -```python -gpCam.video_settings("1080p","30") -gpCam.video_settings("1440p") -``` - -* Set the correct time: - -GoPro cameras need to have the clock set up, otherwise the media metadata will not be correct. - -```python -gpCam.syncTime() -``` - -#### Change settings: - -Depending on the camera you have, you will need to change the settings using certain commands. - -* HERO4 and newer: - -The command ```gpControlSet()``` will allow you to change all the camera's settings. The structure is like follows: - -```python -gpCam.gpControlSet(constants.Setup.COMMAND_NAME, constants.Setup.CommandName.Parameter) -``` - -So, to turn off the beeps on the camera: - -```python -gpCam.gpControlSet(constants.Setup.BEEP, constants.Setup.Beep.OFF) -``` - -The ```constants``` commands are divided into different sections: - - * Video - * Photo - * Multishot - * Setup - -Each section has its different commands and parameters, so the beep command mentioned above is in setup. - -For video, photo, and multishot you can change the resolution, protune values and depeding on the mode you can change mode-specific commands such as TimeLapse interval for Multishot to 10 seconds: - -```python -gpCam.gpControlSet(constants.Multishot.TIMELAPSE_INTERVAL, constants.Multishot.TimeLapseInterval.I10) -``` - -Or the Video+Photo submode interval from video mode to 30 minutes: - -```python -gpCam.gpControlSet(constants.Video.VIDEO_PHOTO_INTERVAL, constants.Video.VideoPhotoInterval.Interval30Min) -``` - -For the complete list of available settings, look in the constants.py file. - -* HERO3 / HERO3+ - -For HERO3/HERO3+ cameras its a bit different, because they use an older version of the API the commands are not the same as HERO4. - -```python -gpCam.sendCamera(constants.Hero3Commands.COMMAND_NAME, constants.Hero3Commands.CommandName.Parameter) -``` - -Most of the settings are on ```constants.Hero3Commands.``` but the ones found in the GoPro Setup section are in ```constants.Hero3Commands.Setup.``` and the settings in Capture Settings are found in ```constants.Hero3Commands.``` - -* **Hero3Commands**: - - * BURST_RATE - * PHOTO_RESOLUTION - * CONTINOUOUS_RATE - * TIMELAPSE_RATE - * FOV - * FRAME_RATE - * VIDEO_RESOLUTION - -* **Setup:** - - * BEEP - * ONE_BTN_MODE - * ON_SCREEN_DISP - * DEFAULT_MODE - * LED - * NTSC - -* **Capture Settings**: - - * VIDEO_PHOTO_INTERVAL - * LOOPING_VIDEO - * WHITE_BALANCE - * ORIENTATION - * PROTUNE - * **HERO3+ Black Cameras only:** - * COLOR_PROFILE - * SHARPNESS - * EXPOSURE_COMP - * SPOT_METER - * ISO - -```python -gpCam.sendCamera(constants.Hero3Commands.BURST_RATE, constants.Hero3Commands.BurstRate.BU10_1) -gpCam.sendCamera(constants.Hero3Commands.Setup.LED, constants.Hero3Commands.Setup.StatusLight.OFF) -gpCam.sendCamera(constants.Hero3Commands.CaptureSettings.PROTUNE, constants.Hero3Commands.CaptureSettings.ProTune.ON) -``` - -#### Status - -You can get all status available. - -```gpCam.overview()``` will display a simple overview of the camera, such as this one: - -For HERO4 and newer: - -``` -current mode: Video -current submode: Video -current video resolution: 1080p -current video framerate: 30 -pictures taken: 78 -videos taken: 17 -videos left: 01:42:46 -pictures left: 3916 -battery left: Nearly Empty -space left in sd card: 24.27GB -camera SSID: KonradHERO4Black -Is Recording: Not recording - standby -Clients connected: 1 -camera model: HERO4 Black -camera ssid name: KonradHERO4Black -firmware version: HD4.02.05.00.00 -``` - -For HERO3/3+: - -``` -current mode: Video -current video resolution: 1080p -current photo resolution: 12mp -current timelapse interval: 1s -current video Fov: Wide -status lights: OFF -recording: OFF -``` - -##### HERO4 and newer: - -The status messages are divided into 2 sections, Status and Settings. - -In Status, the camera returns the camera in general, for example number of photos taken, battery left, current mode... - -In Settings, it returns the status from the id specified, this id is a command from the constants file that works in gpControlSet() - -You can use getStatus() to query the status messages. - -```python -gpCam.getStatus(constants.Status.Status,constants.Status.STATUS.Mode) #Gets current mode status -0 - -gpCam.getStatus(constants.Status.Status, constants.Status.STATUS.BatteryLevel) #Gets battery level -3 - -gpCam.getStatus(constants.Status.Settings, constants.Setup.ORIENTATION) #Gets orientation mode -2 - -``` - -This returns the raw value, to convert it into something we can easily recognise you use parse_value() - -```python -gpCam.parse_value("video_left",gpCam.getStatus(constants.Status.Status, constants.Status.STATUS.RemVideoTime)) -'01:42:50' - -gpCam.parse_value("video_res",gpCam.getStatus(constants.Status.Settings, constants.Video.RESOLUTION)) -'1080p' - -gpCam.parse_value("battery", gpCam.getStatus(constants.Status.Status, constants.Status.STATUS.BatteryLevel)) -'Full' -``` - -To get information about the camera, such as the name or firmware version with infoCamera(): - -```python -print(gpCam.infoCamera(constants.Camera.Name)) #Gets camera name -HERO4 Black -print(gpCam.infoCamera(constants.Camera.Firmware)) #Gets camera fw version -HD4.02.05.00.00 -``` - -##### HERO3 / HERO3+: - -Very similar to ```sendCamera()```, you can input any value you want to get and it will return it. - -The status messages are in ```constants.Hero3Status.```. This will return the raw value. - -```python -gpCam.getStatus(constants.Hero3Status.WhiteBalance) -'00' -gpCam.getStatus(constants.Hero3Status.IsRecording) -'01' -gpCam.getStatus(constants.Hero3Status.PicRes) -'5' -``` - -To translate those values to something we can understand: - -```python -gpCam.parse_value(constants.Hero3Status.PicRes, gpCam.getStatus(constants.Hero3Status.PicRes)) -'12mp' -gpCam.parse_value(constants.Hero3Status.TimeLapseInterval, gpCam.getStatus(constants.Hero3Status.TimeLapseInterval)) -'1s' -gpCam.parse_value(constants.Hero3Status.Mode, gpCam.getStatus(constants.Hero3Status.Mode)) -'Video' -``` - -#### Media - -This is camera agnostic: - -* Get the url of latest video or picture taken - -```python -print(gpCam.getMedia()) #Latest media taken URL -http://10.5.5.9:8080/videos/DCIM/104GOPRO/GOPR2386.JPG -``` - -* Get the latest media's filename/size: - -``` -print(gpCam.getMediaInfo("file")) #Latest media taken filename -GOPR2386.JPG -print(gpCam.getMediaInfo("size")) #Latest media taken size -14.82MB -``` - -* Download the latest media: - -```python -gpCam.downloadLastMedia() #Downloads last video/photo taken -``` - -* Download a certain URL (or snap something and download it.): - -```python -gpCam.downloadLastMedia(gpCam.take_photo(5)) #Waits 5 seconds, takes a photo, downloads it to current directory. -gpCam.downloadLastMedia(gpCam.shoot_video(120)) #Shoots a 120 second video and then downloads it. -``` - -* Download a video in low resolution: - -You can download a video that is recorded in 1080p or below in low resolution. This enables fast transfer of videos but the low res videos are only intended to be used as a reference for the actual high quality video. - -```python -gpCam.downloadLowRes() #video is already recorded, now this downloads the low resolution version -gpCam.downloadLowRes(gpCam.shoot_video(120)) #Record a 120 second video and download it in low resolution -``` - -* Download all media on the camera: - -```python -gpCam.downloadAll() #downloads all media -gpCam.downloadAll("photos") #downloads only all photos -gpCam.downloadAll("videos") #downloads all videos -``` - -* Download a specific media: - -```python -gpCam.downloadMedia("100GOPRO","GOPR0045.MP4") -``` - -* Get video metadata: +### Quick start: -```python -gpCam.getVideoInfo("dur", "GOPR2524.MP4") #gets video duration -24 - -gpCam.getVideoInfo("tags", "GOPR2524.MP4") #get an array of hilight tags in ms -[5872, 7907] - -gpCam.getVideoInfo("tag_count", "GOPR2524.MP4") -2 -``` - -* Delete: - -All: - -```python -gpCam.delete("all") -``` - -Last: - -```python -gpCam.delete("last") -``` - -A specific file: - -```python -gpCam.deleteFile("104GOPRO","GOPR0038.JPG") -``` - -* List camera media contents: - -```python -gpCam.listMedia() -``` - -it will return a JSON list of the media files available on the camera: - -``` -{ - "id": "3993129928403681535", - "media": [ - { - "d": "104GOPRO", - "fs": [ - { - "mod": "1490468532", - "n": "GOPR2760.JPG", - "s": "4919786" - }, - { - "mod": "1490468536", - "n": "GOPR2761.JPG", - "s": "4942872" - }, - { - "mod": "1490468540", - "n": "GOPR2762.JPG", - "s": "4943428" - }, - -``` - -If you want it formatted: - -```python -gpCam.listMedia(format=True) -``` - -``` -folder: 104GOPRO -GOPR2760.JPG -GOPR2761.JPG -GOPR2762.JPG -GOPR2763.JPG -GOPR2764.MP4 -GOPR2765.MP4 -GOPR2766.MP4 -GOPR2767.MP4 -GOPR2768.MP4 -``` - -will return it in a new line each. - -Lastly, if you want it in an array: - -```python -gpCam.listMedia(format=True, media_array=True) -``` - -``` -[['100GOPRO', 'GOPR3132.MP4', '741578340'], ['100GOPRO', 'GOPR3133.MP4', '61818786'], ['100GOPRO', 'GOPR3134.MP4', '52298492'], ['100GOPRO', 'GOPR3135.MP4', '22484879']] -``` - -``` ->>> m=gopro.listMedia(True, True) ->>> m[0] #First media item -['100GOPRO', 'GOPR3132.MP4', '741578340'] ->>> m[1] Second media item -['100GOPRO', 'GOPR3133.MP4', '61818786'] ->>> m[2] Third media item -['100GOPRO', 'GOPR3134.MP4', '52298492'] ->>> m[2][1] #Get name of third media item -'GOPR3134.MP4' ->>> m[2][0] #Get folder of third media item -'100GOPRO' ->>> m[2][2] #Get size (bytes) of first media item -'52298492' - -``` - -### Pairing: - -If you don't want to use the GoPro APP to pair your camera for the first time you can pair it with this API. +Connect your camera to your computer via WiFi (WiFi on the camera must be on!) ``` -... -gopro = GoProCamera.GoPro() -gopro.pair(usepin=False) # GoPro HERO 5, HERO 6 - +from goprocam import GoProCamera, constants +goproCamera = GoProCamera.GoPro() +goproCamera.shoot_video(10) ``` -### Streaming: +### Examples: -In regards to streaming, this library provides with the following functions: +See [examples](/examples) for examples on how to use this API. -This will enable livestreaming on all cameras. - -```python -gpCam.livestream("start") -gpCam.livestream("stop") -``` - -To stream GoPro feed to another place such as localhost (this is needed for HERO4/5): - -```python -gpCam.stream("udp://localhost:5000") -``` - -You can also set the quality of the stream, HERO5 supports 720p! - -```python -gpCam.streamSettings(constants.Stream.Bitrate.B4Mbps, constants.Stream.WindowSize.R480) #For HERO4 - -gpCam.streamSettings(constants.Stream.Bitrate.B4Mbps, constants.Stream.WindowSize.R720) #For HERO5 -``` - -For HERO3 do the same steps above. +### Documentation: -See the [examples/opencv_gopro](examples/opencv_gopro) folder for a python script to open the HERO4/5 feed in openCV and detect faces. On [examples/streaming](examples/streaming) there are scripts to stream the GoPro live feed to Facebook, YouTube or Twitch. +Documentation is available: [docs](/docs) ### Video screencap: @@ -646,3 +59,4 @@ See the [examples/opencv_gopro](examples/opencv_gopro) folder for a python scrip * HERO4 Session: https://vimeo.com/209129019 * HERO3 Black: https://vimeo.com/209181246 * HERO5 Black: https://vimeo.com/235135652 +* HERO7 Black: https://www.youtube.com/watch?v=i-X4fPVfoW0 \ No newline at end of file diff --git a/docs/docs.md b/docs/docs.md new file mode 100644 index 0000000..5f80840 --- /dev/null +++ b/docs/docs.md @@ -0,0 +1,248 @@ + +## Docs: + +`GoPro(camera='detect', ip_address='10.5.5.9', +mac_address='AA:BB:CC:DD:EE:FF') ` + + + ` + | Methods defined here: + +**IsRecording**(self) + + ` Returns either 0 or 1 if the camera is recording or not.` + +**KeepAlive**(self) + + ` Sends keep alive packet` + +**__init__**(self, camera='detect', ip_address='10.5.5.9', +mac_address='AA:BB:CC:DD:EE:FF') + + ` Initialize self. See help(type(self)) for accurate signature.` + +**__str__**(self) + + ` Return str(self).` + +**cancelClip**(self, video_id) + + ` cancels clip conversion` + +**changeWiFiSettings**(self, ssid, password) + + ` Changes ssid and passwod of Hero4 camera` + +**clipStatus**(self, status) + + ` returns clip status` + +**delete**(self, option) + + ` Deletes media. "last", "all" or an integer are accepted values for option` + +**deleteFile**(self, folder, file) + + ` Deletes a file. Pass folder and file as parameters.` + +**downloadAll**(self, option='') + + ` Download all media on camera` + +**downloadLastMedia**(self, path='', custom_filename='') + + ` Downloads last media taken, set custom_filename to download to that filename` + +**downloadLowRes**(self, path='', custom_filename='') + + ` Downloads the low-resolution video` + +**downloadMedia**(self, folder, file, custom_filename='') + + ` Downloads specific folder and filename` + +**downloadMultiShot**(self, path='') + + ` Downloads a multi-shot sequence.` + +**getClip**(self, file, resolution, frame_rate, start_ms, stop_ms) + + ` Starts a clip conversion: +file: folder + filename +resolution: see constants.Clip +frame_rate: see constants.Clip +start_ms: start of the video in ms +stop_ms: stop of the video in ms` + +**getClipURL**(self, status) + + ` gets clip URL from status` + +**getInfoFromURL**(self, url) + + ` Gets information from Media URL.` + +**getMedia**(self) + + ` Returns last media URL` + +**getMediaFusion**(self) + +**getMediaInfo**(self, option) + + ` Returns an array of the last media, both front and back URLs` + +**getPassword**(self) + + ` Gets password from Hero3, Hero3+ cameras` + +**getPhotoEXIF**(self, option='', folder='', file='') + + ` Gets Photo EXIF data, set folder and file parameters.` + +**getPhotoInfo**(self, option='', folder='', file='') + + ` Gets photo nformation, set folder and file parameters. +option parameters: w/h/wdr/raw...` + +**getStatus**(self, param, value='') + + ` This returns a status message based on param (status/setting) and value (numeric)` + +**getStatusRaw**(self) + + ` Delivers raw status message` + +**getVideoInfo**(self, option='', folder='', file='') + + ` Gets video information, set folder and file parameters. +option parameters: dur/tag_count/tags/profile/w/h` + +**gpControlCommand**(self, param) + + ` sends Parameter gpControl/command` + +**gpControlExecute**(self, param) + + ` sends Parameter to gpControl/execute` + +**gpControlSet**(self, param, value) + + ` sends Parameter and value to gpControl/setting` + +**hilight**(self) + + ` Tags a hilight in the video` + +**infoCamera**(self, option='') + + ` Gets camera info, such as mac address and firmware version. See constants.Camera for possible options.` + +**listMedia**(self, format=False, media_array=False) + + ` Lists media on SD card +format = (True/False) - Sets formatting +media_array = (True/False) - returns an array` + +**livestream**(self, option) + + ` start livestreaming +option = "start"/"stop"` + +**locate**(self, param) + + ` Starts or stops locating (beeps camera)` + +**mode**(self, mode, submode='0') + + ` Changes mode of the camera. See constants.Mode and constants.Mode.SubMode for sub-modes.` + +**overview**(self) + +**pair**(self, usepin=True) + + ` This is a pairing procedure needed for HERO4 and HERO5 cameras. When those type GoPro camera are purchased the GoPro Mobile app needs an authentication code when pairing the camera to a mobile device for the first time. +The code is useless afterwards. This function will pair your GoPro to the +machine without the need of using the mobile app -- at all.` + +**parse_value**(self, param, value) + +**power_off**(self) + + ` Sends power off command` + +**power_on**(self, _mac_address='') + + ` Sends power on command. Mac address might need to be defined` + +**power_on_auth**(self) + + ` Sends power on command to Hero 3/3+ cameras` + +**prepare_gpcontrol**(self) + +**reset**(self, r) + + ` Resets video/photo/multishot protune values` + +**sendBacpac**(self, param, value) + + ` sends Parameter and value to 10.5.5.9/camera/` + +**sendCamera**(self, param, value='') + + ` sends Parameter and value to 10.5.5.9/camera/` + +**setZoom**(self, zoomLevel) + + ` Sets camera zoom (Hero6/Hero7), zoomLevel is an integer` + +**shoot_video**(self, duration=0) + + ` Shoots a video, if duration is 0 it will not stop the video, set duration to an integer to set the video duration.` + +**shutter**(self, param) + + ` Starts/stop video or timelapse recording, pass constants.start or constants.stop as value in param` + +**stream**(self, addr, quality='') + + ` Starts a FFmpeg instance for streaming to an address +addr: Address to stream to +quality: high/medium/low` + +**streamSettings**(self, bitrate, resolution) + + ` Sets stream settings` + +**syncTime**(self) + + ` Sets time and date to computer's time and date` + +**take_photo**(self, timer=1) + + ` Takes a photo. Set timer to an integer to set a wait time` + +**video_settings**(self, res, fps='none') + + ` Change video resolution and FPS +See constants.Video.Resolution` + +**whichCam**(self) + + ` This returns what type of camera is currently connected. +- gpcontrol: HERO4 Black and Silver, HERO5 Black and Session, HERO Session (formally known as HERO4 Session), HERO+ LCD, HERO+. +- auth: HERO2 with WiFi BacPac, HERO3 Black/Silver/White, HERO3+ Black and Silver.` + +* * * + +Data descriptors defined here: + +**__dict__** + + ` dictionary for instance variables (if defined)` + +**__weakref__** + + ` list of weak references to the object (if defined)` + diff --git a/goprocam/GoProCamera.py b/goprocam/GoProCamera.py index bb3dab7..0c06791 100644 --- a/goprocam/GoProCamera.py +++ b/goprocam/GoProCamera.py @@ -45,6 +45,7 @@ def __init__(self, camera="detect", ip_address="10.5.5.9", mac_address="AA:BB:CC exit() self.ip_addr = ip_address self._camera="" + self._mac_address=mac_address try: from getmac import get_mac_address self._mac_address = get_mac_address(ip="10.5.5.9") @@ -67,11 +68,13 @@ def __init__(self, camera="detect", ip_address="10.5.5.9", mac_address="AA:BB:CC def __str__(self): return str(self.infoCamera()) def KeepAlive(self): + """Sends keep alive packet""" while True: sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto("_GPHD_:0:0:2:0.000000\n".encode(), (self.ip_addr, 8554)) time.sleep(2500/1000) def getPassword(self): + """Gets password from Hero3, Hero3+ cameras""" try: PASSWORD = urllib.request.urlopen('http://' + self.ip_addr + '/bacpac/sd', timeout=5).read() password = str(PASSWORD, 'utf-8') @@ -84,7 +87,7 @@ def getPassword(self): return "" print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def gpControlSet(self, param,value): - #sends Parameter and value to gpControl/setting + """sends Parameter and value to gpControl/setting""" try: return urllib.request.urlopen('http://' + self.ip_addr + '/gp/gpControl/setting/' + param + '/' + value, timeout=5).read().decode('utf-8') except (HTTPError, URLError) as error: @@ -95,6 +98,7 @@ def gpControlSet(self, param,value): print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def gpControlCommand(self, param): + """sends Parameter gpControl/command""" try: return urllib.request.urlopen('http://' + self.ip_addr + '/gp/gpControl/command/' + param, timeout=5).read().decode('utf-8') except (HTTPError, URLError) as error: @@ -104,6 +108,7 @@ def gpControlCommand(self, param): return "" print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def gpControlExecute(self, param): + """sends Parameter to gpControl/execute""" try: return urllib.request.urlopen('http://' + self.ip_addr + '/gp/gpControl/execute?' + param, timeout=5).read().decode('utf-8') except (HTTPError, URLError) as error: @@ -113,6 +118,7 @@ def gpControlExecute(self, param): return "" print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def sendCamera(self, param,value=""): + """sends Parameter and value to 10.5.5.9/camera/""" value_notempty = "" if not value == "": value_notempty=str('&p=%' + value) @@ -124,7 +130,7 @@ def sendCamera(self, param,value=""): except timeout: print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def sendBacpac(self, param,value): - #sends parameter and value to /bacpac/ + """sends Parameter and value to 10.5.5.9/camera/""" value_notempty = "" if value: value_notempty=str('&p=%' + value) @@ -135,9 +141,9 @@ def sendBacpac(self, param,value): except timeout: print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def whichCam(self): - # This returns what type of camera is currently connected. - # gpcontrol: HERO4 Black and Silver, HERO5 Black and Session, HERO Session (formally known as HERO4 Session), HERO+ LCD, HERO+. - # auth: HERO2 with WiFi BacPac, HERO3 Black/Silver/White, HERO3+ Black and Silver. + """ This returns what type of camera is currently connected. + - gpcontrol: HERO4 Black and Silver, HERO5 Black and Session, HERO Session (formally known as HERO4 Session), HERO+ LCD, HERO+. + - auth: HERO2 with WiFi BacPac, HERO3 Black/Silver/White, HERO3+ Black and Silver. """ if self._camera != "": return self._camera else: @@ -196,6 +202,7 @@ def whichCam(self): def getStatus(self, param, value=""): + """This returns a status message based on param (status/setting) and value (numeric)""" if self.whichCam() == "gpcontrol": try: req=urllib.request.urlopen("http://" + self.ip_addr + "/gp/gpControl/status", timeout=5) @@ -215,6 +222,7 @@ def getStatus(self, param, value=""): return str(response_hex[param[0]:param[1]]) def getStatusRaw(self): + """Delivers raw status message""" if self.whichCam() == "gpcontrol": try: return urllib.request.urlopen("http://" + self.ip_addr + "/gp/gpControl/status", timeout=5).read().decode('utf-8') @@ -236,11 +244,13 @@ def getStatusRaw(self): else: print("Error, camera not defined.") def changeWiFiSettings(self, ssid, password): + """Changes ssid and passwod of Hero4 camera""" if self.whichCam() == "gpcontrol": self.gpControlCommand("wireless/ap/ssid?ssid=" + ssid + "&pw=" + password) print("Disconnecting") exit() def infoCamera(self, option=""): + """Gets camera info, such as mac address and firmware version. See constants.Camera for possible options.""" if self.whichCam() == "gpcontrol": try: info=urllib.request.urlopen('http://' + self.ip_addr + '/gp/gpControl', timeout=5) @@ -291,6 +301,7 @@ def infoCamera(self, option=""): print("Error, camera not defined.") def shutter(self,param): + """Starts/stop video or timelapse recording, pass constants.start or constants.stop as value in param""" if self.whichCam() == "gpcontrol": print(self.gpControlCommand("shutter?p=" + param)) else: @@ -300,6 +311,7 @@ def shutter(self,param): def mode(self, mode, submode="0"): + """Changes mode of the camera. See constants.Mode and constants.Mode.SubMode for sub-modes.""" if self.whichCam() == "gpcontrol": print(self.gpControlCommand("sub_mode?mode=" + mode + "&sub_mode=" + submode)) else: @@ -307,6 +319,7 @@ def mode(self, mode, submode="0"): mode = "0" + mode self.sendCamera("CM",mode) def delete(self, option): + """Deletes media. "last", "all" or an integer are accepted values for option""" if self.whichCam() == "gpcontrol": if isinstance(option, int): #This allows you to delete x number of files backwards. Will delete a timelapse/burst entirely as its interpreted as a single file. for _ in range(option): @@ -323,6 +336,7 @@ def delete(self, option): if option == "all": print(self.sendCamera("DA")) def deleteFile(self, folder,file): + """Deletes a file. Pass folder and file as parameters.""" if folder.startswith("http://" + self.ip_addr): self.getInfoFromURL(folder) if self.whichCam() == "gpcontrol": @@ -335,24 +349,28 @@ def deleteFile(self, folder,file): else: print(self.sendCamera("DA",folder+"/"+file)) def locate(self, param): + """Starts or stops locating (beeps camera)""" if self.whichCam() == "gpcontrol": print(self.gpControlCommand("system/locate?p=" + param)) else: print(self.sendCamera("LL","0"+param)) def hilight(self): + """Tags a hilight in the video""" if self.whichCam() == "gpcontrol": print(self.gpControlCommand("storage/tag_moment")) else: print("Not supported.") def power_off(self): + """Sends power off command""" if self.whichCam() == "gpcontrol": print(self.gpControlCommand("system/sleep")) else: print(self.sendBacpac("PW","00")) def power_on(self,_mac_address=""): + """Sends power on command. Mac address might need to be defined""" print("Waking up...") mac_address=_mac_address if mac_address is None: @@ -374,8 +392,8 @@ def power_on(self,_mac_address=""): #Fallback for HERO5 sock.sendto(message, (self.ip_addr, 7)) def pair(self, usepin=True): - #This is a pairing procedure needed for HERO4 and HERO5 cameras. When those type GoPro camera are purchased the GoPro Mobile app needs an authentication code when pairing the camera to a mobile device for the first time. - #The code is useless afterwards. This function will pair your GoPro to the machine without the need of using the mobile app -- at all. + """This is a pairing procedure needed for HERO4 and HERO5 cameras. When those type GoPro camera are purchased the GoPro Mobile app needs an authentication code when pairing the camera to a mobile device for the first time. + The code is useless afterwards. This function will pair your GoPro to the machine without the need of using the mobile app -- at all. """ if usepin == False: paired_resp = "" while "{}" not in paired_resp: @@ -396,8 +414,11 @@ def pair(self, usepin=True): self.gpControlCommand("wireless/ap/ssid?ssid=" + wifi_ssid + "&pw=" + wifi_pass) print("Connect now!") def power_on_auth(self): + """Sends power on command to Hero 3/3+ cameras""" print(self.sendBacpac("PW","01")) def video_settings(self, res, fps="none"): + """Change video resolution and FPS + See constants.Video.Resolution""" if self.whichCam() == "gpcontrol": x="constants.Video.Resolution.R" + res videoRes = eval(x) @@ -430,6 +451,7 @@ def video_settings(self, res, fps="none"): videoFps = eval(x) print(self.sendCamera(constants.Hero3Commands.FRAME_RATE,videoFps)) def take_photo(self,timer=1): + """Takes a photo. Set timer to an integer to set a wait time""" if "HERO5 Black" in self.infoCamera(constants.Camera.Name) or "HERO6" in self.infoCamera(constants.Camera.Name): self.mode(constants.Mode.PhotoMode, constants.Mode.SubMode.Photo.Single_H5) else: @@ -450,6 +472,7 @@ def take_photo(self,timer=1): ready=str(self.getStatus(constants.Hero3Status.IsRecording)) return self.getMedia() def shoot_video(self, duration=0): + """Shoots a video, if duration is 0 it will not stop the video, set duration to an integer to set the video duration.""" self.mode(constants.Mode.VideoMode) time.sleep(1) self.shutter(constants.start) @@ -468,6 +491,7 @@ def shoot_video(self, duration=0): return self.getMedia() def syncTime(self): + """Sets time and date to computer's time and date""" now = datetime.datetime.now() year=str(now.year)[-2:] datestr_year=format(int(year), 'x') @@ -482,11 +506,14 @@ def syncTime(self): else: print(self.sendCamera("TM",datestr)) def reset(self, r): + """Resets video/photo/multishot protune values""" self.gpControlCommand(r + "/protune/reset") def setZoom(self, zoomLevel): + """Sets camera zoom (Hero6/Hero7), zoomLevel is an integer""" if zoomLevel >= 0 and zoomLevel <= 100: - self.gpControlCommand("digital_zoom?range_pcnt=" + zoomLevel) + self.gpControlCommand("digital_zoom?range_pcnt=" + str(zoomLevel)) def getMedia(self): + """Returns last media URL""" if "FS" in self.infoCamera(constants.Camera.Firmware): self.getMediaFusion() else: @@ -538,6 +565,7 @@ def getMediaFusion(self): return "" print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def getMediaInfo(self, option): + """Returns an array of the last media, both front and back URLs""" folder = "" file = "" size = "" @@ -565,6 +593,9 @@ def getMediaInfo(self, option): return "" print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def listMedia(self, format=False, media_array=False): + """Lists media on SD card + format = (True/False) - Sets formatting + media_array = (True/False) - returns an array""" try: if format == False: raw_data = urllib.request.urlopen('http://' + self.ip_addr + ':8080/gp/gpMediaList').read().decode('utf-8') @@ -605,6 +636,7 @@ def listMedia(self, format=False, media_array=False): ## Misc media utils ## def IsRecording(self): + """Returns either 0 or 1 if the camera is recording or not.""" if self.whichCam() == "gpcontrol": return self.getStatus(constants.Status.Status, constants.Status.STATUS.IsRecording) elif self.whichCam() == "auth": @@ -613,6 +645,7 @@ def IsRecording(self): else: return 1 def getInfoFromURL(self, url): + """Gets information from Media URL.""" media=[] media.append(url.replace('http://' + self.ip_addr + ':8080/videos/DCIM/','').replace('/','-').rsplit('-', 1)[0]) media.append(url.replace('http://' + self.ip_addr + ':8080/videos/DCIM/','').replace('/','-').rsplit('-', 1)[1]) @@ -622,6 +655,7 @@ def getInfoFromURL(self, url): ## Downloading media functions ## def downloadMultiShot(self, path=""): + """Downloads a multi-shot sequence.""" if path == "": path = self.getMedia() folder = self.getInfoFromURL(path)[0] @@ -658,6 +692,7 @@ def downloadMultiShot(self, path=""): f = filename[:4] + str(int(lower_bound) + i) + ".JPG" self.downloadMedia(folder, f) def downloadLastMedia(self, path="", custom_filename=""): + """Downloads last media taken, set custom_filename to download to that filename""" if self.IsRecording() == 0: if path == "": print("filename: " + self.getMediaInfo("file") + "\nsize: " + self.getMediaInfo("size")) @@ -679,6 +714,7 @@ def downloadLastMedia(self, path="", custom_filename=""): else: print("Not supported while recording or processing media.") def downloadMedia(self, folder, file, custom_filename=""): + """Downloads specific folder and filename""" if self.IsRecording() == 0: print("filename: " + file) filename = "" @@ -693,6 +729,7 @@ def downloadMedia(self, folder, file, custom_filename=""): else: print("Not supported while recording or processing media.") def downloadAll(self, option=""): + """Download all media on camera""" media_stash=[] if option == "": try: @@ -748,6 +785,7 @@ def downloadAll(self, option=""): except timeout: print("HTTP Timeout\nMake sure the connection to the WiFi camera is still active.") def downloadLowRes(self, path="", custom_filename = ""): + """Downloads the low-resolution video""" if self.IsRecording() == 0: if path == "": url=self.getMedia() @@ -800,6 +838,8 @@ def downloadLowRes(self, path="", custom_filename = ""): ## Query Media Info ## def getVideoInfo(self, option= "", folder = "", file= ""): + """Gets video information, set folder and file parameters. + option parameters: dur/tag_count/tags/profile/w/h""" if option == "": if folder == "" and file == "": if self.getMediaInfo("file").endswith("MP4"): @@ -817,6 +857,8 @@ def getVideoInfo(self, option= "", folder = "", file= ""): jsondata=json.loads(data) return jsondata[option] #dur/tag_count/tags/profile/w/h def getPhotoInfo(self, option= "", folder= "", file = ""): + """Gets photo nformation, set folder and file parameters. + option parameters: w/h/wdr/raw...""" if option == "": if folder == "" and file == "": if self.getMediaInfo("file").endswith("JPG"): @@ -835,6 +877,8 @@ def getPhotoInfo(self, option= "", folder= "", file = ""): jsondata=json.loads(data) return jsondata[option] #"w":"4000","h":"3000" / "wdr":"0","raw":"0" def getPhotoEXIF(self, option="", folder="", file=""): + """Gets Photo EXIF data, set folder and file parameters. + """ if option == "": if folder == "" and file == "": if self.getMediaInfo("file").endswith("JPG"): @@ -857,6 +901,12 @@ def getPhotoEXIF(self, option="", folder="", file=""): ## Clip functions ## def getClip(self, file, resolution, frame_rate, start_ms, stop_ms): + """Starts a clip conversion: + file: folder + filename + resolution: see constants.Clip + frame_rate: see constants.Clip + start_ms: start of the video in ms + stop_ms: stop of the video in ms""" out="" if "HERO4" in self.infoCamera("model_name"): out = self.gpControlCommand("transcode/request?source=DCIM/" + file + "&res=" + resolution + "&fps_divisor=" + frame_rate + "&in_ms=" + start_ms + "&out_ms=" + stop_ms) @@ -865,21 +915,27 @@ def getClip(self, file, resolution, frame_rate, start_ms, stop_ms): video_id = json.loads(out.replace("\\","/")) return video_id["status"]["id"] def clipStatus(self, status): + """returns clip status""" resp = json.loads(self.gpControlCommand("transcode/status?id=" + status).replace("\\","/")) resp_parsed = resp["status"]["status"] return constants.Clip.TranscodeStage[resp_parsed] def getClipURL(self, status): + """gets clip URL from status""" resp = json.loads(self.gpControlCommand("transcode/status?id=" + status).replace("\\","/")) resp_parsed = resp["status"]["status"] if resp_parsed == 2: return "http://" + self.ip_addr + ":80/videos/" + resp["status"]["output"] def cancelClip(self, video_id): + """cancels clip conversion""" self.gpControlCommand("transcode/cancel?id=" + video_id) ## ## Livestreaming functions ## def livestream(self,option): + """start livestreaming + option = "start"/"stop" + """ if option == "start": if self.whichCam() == "gpcontrol": print(self.gpControlExecute('p1=gpStream&a1=proto_v2&c1=restart')) @@ -891,6 +947,10 @@ def livestream(self,option): else: print(self.sendCamera("PV","00")) def stream(self, addr, quality=""): + """Starts a FFmpeg instance for streaming to an address + addr: Address to stream to + quality: high/medium/low + """ self.livestream("start") if self.whichCam() == "gpcontrol": if "HERO4" in self.infoCamera("model_name"): @@ -912,6 +972,7 @@ def stream(self, addr, quality=""): elif self.whichCam() == "auth": subprocess.Popen("ffmpeg -i http://" + self.ip_addr + ":8080/live/amba.m3u8 -f mpegts " + addr, shell=True) def streamSettings(self, bitrate, resolution): + """Sets stream settings""" self.gpControlSet("62", bitrate) self.gpControlSet("64", resolution) def parse_value(self, param,value): diff --git a/setup.py b/setup.py index 741b7f4..ef9dfaf 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ with open("README.md", "r") as fh: long_description = fh.read() setup(name='goprocam', - version='2.0.10', + version='3.0.0', description='GoPro WiFi API Wrapper for Python - Compatible with HERO3, HERO3+, HERO4, HERO5, HERO+, HERO6', url='http://github.com/konradit/gopro-py-api', long_description=long_description,