Downloading media from Drone through SkyControlller RNDIS

Hello all,

I am in need of programmatically downloading videos and pictures triggered in flight. I have several options but they are all weird. I will detail below:

  • I found that if I run Sphinx of ANAFI I am able to connect to an FTP server in the IP address of the simulated Anafi. Unfortunately when I connect to the real ANAFI (through SkyController or not), I cannot reach any FTP server. Am i missing something?

  • I found that there is a REST API for the media, but the location is not reachable if I connect to the ANAFI IP address (192.168.53.1). On the other hand if I connect directly to the ANAFI wifi hotspot 192.168.42.1, i am offered the REST API. I guess this is due to the fact that I cannot reach the ANAFI network directly through the SkyController, but then this makes me have to choose between having the SkyController and Media Download, which is a terrible choice.

  • I found that the Android(Java) and iOS(swift) SDKs have support for download and listing of media. Unfortunately for Olympe(python) I can only find media listing, nothing about downloading and thumbnails.

With all of this I am very sad and this seems like a massive set-back on my project where i created a web based fleet manager of ANAFIs. It already takes off, lands, moves on map, streams live low latency videos to the browser and mobile…but i cannot download media :frowning:

Hope somebody can offer me a way out of this problem.

Hi,

You’ve correctly found that the Anafi provides a REST API for media downloading. This API is also available when you’re connected through a SkyController 3, but in this case you will need to use the SkyController 3 IP address (usually 192.168.53.1), and use port 180 instead of 80.

So basically, to list your medias, you can use either http://192.168.42.1/api/v1/media/medias when directly connected to the drone access point, or http://192.168.53.1:180/api/v1/media/medias when connected through a SkyController 3. The same applies for all the download URLs.

However, due to how the redirect is handled, you cannot use the web interface with the SkyController 3, just the REST API.

Regards,
Nicolas.

3 Likes

Hi Nicolas,

Thanks a lot! So cool. I have no use for the web interface so no loss for me, even so i am convinced some greasemonkey hacks could probably fix it, but is just some advice for whoever may need it.

Now the last thing. Where can I find documentation on this API? Do i need to have a look at the website code?

Best regards
Paulo Neves

So answering to myself…
The API is very simple just access http://192.168.53.1:180/api/v1/media/medias and there is json file with the data and url’s. An example:

[ { "media_id": "10000057", "type": "VIDEO", "datetime": "20191004T002534+0200", "size": 68545156, "video_mode": "Standard", "duration": 5163, "run_id": "0B0321BC3660A808E74A665813C81793", "thumbnail": "/data/thumbnails/100000570059.MP4", "resources": [ { "media_id": "10000057", "resource_id": "100000570059.MP4", "type": "VIDEO", "format": "MP4", "datetime": "20191004T002534+0200", "size": 68545156, "url": "/data/media/100000570059.MP4", "width": 3840, "height": 2160, "thumbnail": "/data/thumbnails/100000570059.MP4", "video_mode": "Standard", "replay_url": "replay/100000570059.MP4", "duration": 5163 } ] } ]
Notes:

  • The urls are all relative to the IP address not to the API.
  • The thumbnails have extension MP4 but are in fact JPEG

Also if you need to use SkyController to access the dashboard you do not need greasemonkey. Just
sudo socat tcp-listen:80,reuseaddr,fork tcp:192.168.53.1:180 and connect to localhost in your browser.

1 Like

We will provide the full Web API documentation really soon! :slight_smile:

Hi,
I am also using olympe with the SkyController connection to download media and have followed the steps above for downloading and listing media, which works, but when I try delete any media items I get a HTTP 400 BAD REQUEST response code.

I am using this code, with the resource URL from the listed media:
import requests
response = requests.delete(“http://192.168.53.1:180{}”.format(resource_url))

The response I get back always has status code 400. Any advice on what I might be doing wrong with my request?

Thanks,
Chloe

Hi @Chloe ,

What’s in resource_url ? Can you post the full HTTP delete URL you are trying?

Sure an example of the complete url I am using is:
http://192.168.53.1:180/data/media/1000001718.JPG

It is the same URL I am using for the GET call to download the image which works fine.

Note: I do have some networking rules set up so it does use different IP addresses sometimes depending on which SkyController I am communicating with (similar to this post Multiple Parrot Anafi controlled via Olympe on Linux, configure IP ) just in case that might somehow be interfering

1 Like

Hello everyone,

For your information, Olympe 1.2.0 has just been released with a new media API.

Nicolas

1 Like

I’m trying to run examples/media.py through a SkyController3 by changing DRONE_IP to “192.168.53.1” for the RNDIS IP address. It times out when waiting for media indexing to finish (see log below). I really just care about downloading a photo via the SkyController3, which does work if I use a web browser to GET http://192.168.53.1:180/data/media/XXXXXXXXXXX.JPG , but I can’t get the Olympe version of this to work. I don’t understand why media indexing is failing. I deleted almost everything from the SD card, which didn’t help.

2020-12-02 15:59:32,380 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.recording_capabilities(id=3, recording_modes=‘standard|hyperlapse’, resolutions=‘res_2_7k’, framerates=‘fps_24|fps_25|fps_30’, hdr=supported.supported, list_flags=’’)
2020-12-02 15:59:32,381 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.recording_capabilities(id=4, recording_modes=‘slow_motion|high_framerate’, resolutions=‘res_1080p’, framerates=‘fps_48|fps_50|fps_60’, hdr=supported.not_supported, list_flags=’’)
2020-12-02 15:59:32,381 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.recording_capabilities(id=5, recording_modes=‘slow_motion|high_framerate’, resolutions=‘res_720p’, framerates=‘fps_96|fps_100|fps_120’, hdr=supported.not_supported, list_flags=‘Last’)
2020-12-02 15:59:32,381 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=0, photo_modes=‘single|time_lapse|gps_lapse’, photo_formats=‘full_frame’, photo_file_formats=‘dng_jpeg’, hdr=supported.not_supported, list_flags=‘First’)
2020-12-02 15:59:32,382 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=1, photo_modes=‘single|time_lapse|gps_lapse’, photo_formats=‘rectilinear’, photo_file_formats=‘dng_jpeg’, hdr=supported.not_supported, list_flags=’’)
2020-12-02 15:59:32,385 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=2, photo_modes=‘single|burst|time_lapse|gps_lapse’, photo_formats=‘full_frame’, photo_file_formats=‘jpeg’, hdr=supported.supported, list_flags=’’)
2020-12-02 15:59:32,386 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=3, photo_modes=‘single|burst|time_lapse|gps_lapse’, photo_formats=‘rectilinear’, photo_file_formats=‘jpeg’, hdr=supported.supported, list_flags=’’)
2020-12-02 15:59:32,388 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=4, photo_modes=‘bracketing’, photo_formats=‘full_frame’, photo_file_formats=‘jpeg|dng_jpeg’, hdr=supported.not_supported, list_flags=’’)
2020-12-02 15:59:32,388 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_capabilities(id=5, photo_modes=‘bracketing’, photo_formats=‘rectilinear’, photo_file_formats=‘jpeg|dng_jpeg’, hdr=supported.not_supported, list_flags=‘Last’)
2020-12-02 15:59:32,389 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - camera.photo_mode(cam_id=0, mode=photo_mode.burst, format=photo_format.rectilinear, file_format=photo_file_format.jpeg, burst=burst_value.burst_14_over_1s, bracketing=bracketing_preset.preset_1ev, capture_interval=0.0, list_flags=’’)
2020-12-02 15:59:32,397 [INFO] main - main - waiting for media resources indexing…
2020-12-02 15:59:35,886 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-27)
2020-12-02 15:59:36,886 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:38,887 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:40,889 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:41,888 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:42,889 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:43,889 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:44,890 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 15:59:45,890 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:47,891 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:49,893 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:51,894 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:52,894 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:54,894 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 15:59:55,894 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 15:59:57,896 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:00,898 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 16:00:01,897 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:02,898 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:03,421 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - common.CommonState.BatteryStateChanged(percent=58)
2020-12-02 16:00:03,897 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:04,898 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:07,900 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 16:00:08,901 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:09,901 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 16:00:10,901 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:11,902 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-27)
2020-12-02 16:00:12,902 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:15,904 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:16,906 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-28)
2020-12-02 16:00:18,906 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:20,907 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 16:00:24,909 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:25,911 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-31)
2020-12-02 16:00:27,910 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-30)
2020-12-02 16:00:31,912 [INFO] olympe.example_media_standalone.drone - _recv_cmd_cb - wifi.rssi_changed(rssi=-29)
2020-12-02 16:00:32,399 [ERROR] main - main - Media indexing timed out
2020-12-02 16:00:32,403 [INFO] olympe.example_media_standalone.media - _shutdown - olympe.media shutdown
2020-12-02 16:00:32,406 [INFO] olympe.example_media_standalone.media - destroy_timer - Pomp loop timer has been destroyed
2020-12-02 16:00:32,409 [INFO] olympe.example_media_standalone.media - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,422 [INFO] olympe.example_media_standalone.drone - disconnect - we are not disconnected yet
2020-12-02 16:00:32,428 [INFO] olympe.example_media_standalone.drone - _disconnected_cb - Disconnected from device: Skycontroller 3
2020-12-02 16:00:32,429 [INFO] olympe.example_media_standalone.drone - _disconnection_impl - disconnected from device: b’192.168.53.1’
2020-12-02 16:00:32,430 [INFO] olympe.example_media_standalone.drone - disconnect - Disconnection with the device OK. IP: b’192.168.53.1’
2020-12-02 16:00:32,431 [INFO] olympe.example_media_standalone.pdraw - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,433 [INFO] olympe.example_media_standalone.pdraw - dispose - pdraw callbacks thread loop stopped
2020-12-02 16:00:32,435 [INFO] olympe.example_media_standalone.pdraw - _destroy - destroying yuv buffer pool…
2020-12-02 16:00:32,436 [INFO] olympe.example_media_standalone.pdraw - _destroy - yuv buffer pool destroyed
2020-12-02 16:00:32,437 [INFO] olympe.example_media_standalone.pdraw - _destroy - pdraw thread loop stopped
2020-12-02 16:00:32,446 [INFO] olympe.example_media_standalone.backend - _destroy - Manager has been destroyed
2020-12-02 16:00:32,447 [INFO] olympe.example_media_standalone.backend - destroy_timer - Pomp loop timer has been destroyed
2020-12-02 16:00:32,448 [INFO] olympe.example_media_standalone.backend - destroy_timer - Pomp loop timer has been destroyed
2020-12-02 16:00:32,448 [INFO] olympe.example_media_standalone.backend - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,452 [INFO] olympe.example_media_standalone.scheduler - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,456 [INFO] olympe.example_media_autoconnect.backend - _create_pomp_loop - Creating pomp loop
2020-12-02 16:00:32,457 [INFO] olympe.example_media_autoconnect.backend - _do_create - device callbacks have been added to arsdk_ctrl
2020-12-02 16:00:32,459 [INFO] olympe.example_media_autoconnect.backend - create_timer - Creating pomp timer
2020-12-02 16:00:32,459 [INFO] olympe.example_media_autoconnect.scheduler - _create_pomp_loop - Creating pomp loop
2020-12-02 16:00:32,548 [INFO] olympe.example_media_standalone.pdraw - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,910 [INFO] olympe.example_media_autoconnect.backend - create_timer - Creating pomp timer
2020-12-02 16:00:32,912 [INFO] olympe.example_media_autoconnect.backend - _device_added_cb - New device has been detected: ‘Skycontroller 3’
2020-12-02 16:00:32,913 [INFO] olympe.example_media_autoconnect.drone - _connecting_cb - Connecting to device: Skycontroller 3
2020-12-02 16:00:32,914 [INFO] olympe.example_media_autoconnect.drone - _connection_impl - Connection in progress…
2020-12-02 16:00:32,916 [INFO] olympe.example_media_autoconnect.drone - _canceled_cb - Connection to device: Skycontroller 3 has been canceled for reason: REJECTED
2020-12-02 16:00:32,918 [ERROR] olympe.example_media_autoconnect.drone - connect - Unable to connect to the device: b’192.168.53.1’
2020-12-02 16:00:32,921 [INFO] olympe.example_media_autoconnect.backend - _destroy - Manager has been destroyed
2020-12-02 16:00:32,925 [INFO] olympe.example_media_autoconnect.backend - destroy_timer - Pomp loop timer has been destroyed
2020-12-02 16:00:32,926 [INFO] olympe.example_media_autoconnect.backend - destroy_timer - Pomp loop timer has been destroyed
2020-12-02 16:00:32,926 [INFO] olympe.example_media_autoconnect.backend - _destroy_pomp_loop - Pomp loop has been destroyed
2020-12-02 16:00:32,929 [INFO] olympe.example_media_autoconnect.scheduler - destroy_pomp_loop - Pomp loop has been destroyed
Traceback (most recent call last):
File “media.py”, line 197, in
main(drone)
File “media.py”, line 161, in main
media.download_dir = tempfile.mkdtemp(prefix="olympe_media_example
")
AttributeError: ‘NoneType’ object has no attribute ‘download_dir’
2020-12-02 16:00:32,955 [INFO] olympe.example_media_standalone.scheduler - _destroy_pomp_loop - Pomp loop has been destroyed

What’s the simplest way to download a photo using Olympe? If I skip waiting on indexing_state(state=“indexed”), then drone(download_media(media_id, integrity_check=True)) fails with

2020-12-02 15:09:52,021 [ERROR] olympe.callbacks - call - Unhandled exception
Traceback (most recent call last):
File “/home/olympe/code/parrot-groundsdk/packages/olympe/src/olympe/_private/init.py”, line 104, in call
return self.func(*args, **kwargs)
File “/home/olympe/code/parrot-groundsdk/packages/olympe/src/olympe/arsdkng/expectations.py”, line 177, in _schedule
expectation._schedule(self)
File “/home/olympe/code/parrot-groundsdk/packages/olympe/src/olympe/media.py”, line 1120, in _schedule
self._media = media_context._get_media(self._media_id)
File “/home/olympe/code/parrot-groundsdk/packages/olympe/src/olympe/media.py”, line 1678, in _get_media
if media_id in self._media_state:
TypeError: argument of type ‘NoneType’ is not iterable