KonradIT / goprowifihack

Unofficial GoPro WiFi API Documentation - HTTP GET requests for commands, status, livestreaming and media query.
Apache License 2.0
2.12k stars 335 forks source link

Set date and time with Bluetooth #216

Open rhoenschrat opened 3 years ago

rhoenschrat commented 3 years ago

Does anyone know how to use the Bluetooth command to set date and time of the GoPro?

On this page: https://gethypoxic.com/blogs/technical/gopro-hero5-interfaces I can see that there is a command to do so like SET_DATE_TIME(new byte[]{(byte) 5, (byte) 13, (byte) 1})

But how to provide the date and time? Based on the way the date is set with the wifi api described in https://github.com/ztzhang/GoProWifiCommand/issues/3 I assumed that I need to add year (2 digits), month, day, hour, minute and second as parameters. And based on the description of the command structure in https://github.com/KonradIT/goprowifihack/blob/master/Bluetooth/Platforms/ArchLinux.md I assumed that every parameter need to be prefixed by it's length which used to by 1 byte. So I end up with the following for the parameters like: (byte) 1, (byte) 20, (byte) 1, (byte) 12, (byte) 1, (byte) 31, (byte) 1, (byte) 15, (byte) 1, (byte) 43, (byte) 1, (byte) 51

What struggles me is, that according to the described command structure it is always like request, length of parameter 1, parameter 1 [, length of parameter 2, parameter 2 ...] And the length can be 1 or 2 bytes. So the 13 in the mentioned command doesn't match that picture. And also the request 5 is already the one to set the camera to sleep mode. My assumption was that this might be a type and the request is actually 13 which also matches the order in the list of the commands. So I give it it try. I used 13 as request and added also a 13 for the overall length of the command which would by like: 2f 0d0d0114010c011f010f012b0133

But it doesn't work.

Any idea what is the right way to do it?

rhoenschrat commented 3 years ago

I solved the puzzle. As the official GoPro App is now controlling the Hero8 and up via Bluetooth by default, I was able to use the packet sniffer tool to check how they are doing it. I was quite close with my assumption, but the date is sent as one parameter with the year using all four digits like 2f 090d0707e501040a0413

where 09 = 9 -> length of request 0d = 13 -> request: set date time 07 = 7 -> length of parameter 07e5 = 2021 -> year 01 = 1 -> month 04 = 4 -> day 0a =10 -> hour 04 = 4 -> minute 13 = 19 -> second

KonradIT commented 3 years ago

Very cool!

ludaokai commented 3 years ago

So cool!

fcaraballo commented 3 years ago

Hi @rhoenschrat, I was wondering what's the package sniffer you have used for this?

rhoenschrat commented 3 years ago

Hi @rhoenschrat, I was wondering what's the package sniffer you have used for this?

@fcaraballo I'm trying to write my own GoPro Remote Controll app for iOS. And I found this article on the Bluetooth SIG page: https://www.bluetooth.com/blog/a-new-way-to-debug-iosbluetooth-applications/

So I just use the PacketLogger that is part of the additional tools from Xcode.

Even if GoPro has finally decided to offer a Bluetooth based remote, it does not really fit my needs. I do motovlogs and used to use 3 cameras at the same time that I want to control and I want to be aware if they are recording or not. And the new GoPro remote in the end only supports Hero8 and Hero9, while my app is even able to play with the Hero4 ;-)

IMG_1200

Archimede55 commented 3 years ago

Hi @rhoenschrat, are you able to read the status via bluetooth also on the Hero7? At this moment I use BT just to start and stop the camera recording (with an embedded linux system) but I would like also to read if it is recording or not... :(

rhoenschrat commented 3 years ago

Hi @Archimede55 after some nightshifts of heavy Packet Logger usage I managed to get everything working that I was looking for. Just some fine tuning needed I think.

https://user-images.githubusercontent.com/47184635/103796891-111e5500-5048-11eb-96c0-24d200a46c47.mp4

All the information shown for a camera are coming from notifications. While recording there are notifications that can hold any combination of battery level, recording time, free space etc.

Archimede55 commented 3 years ago

Really impressive!!! Luckily I don't have to make so huge work, but I only to start/stop recording and check that the Gopro is really recording. Could you help me on this second point? (obviously all by Bluetooth).

Thanks!

KonradIT commented 3 years ago

That's described in Bluetooth/* in this repository.

KonradIT commented 3 years ago

I did see the notifications come in from the GoPro via BLE. Do they follow the usual status key value pairs? Or new ones?

Archimede55 commented 3 years ago

That's described in Bluetooth/* in this repository.

Thanks Konrad, but in the repository I just found how to start/stop the recording (that works perfectly) but not how to read the status. The status link on the Hero9 is not working (https://github.com/KonradIT/goprowifihack/blob/master/HERO9/CameraStatus.md)

KonradIT commented 3 years ago

Ah, i missed the question, yeah status getting is not described yet.

rhoenschrat commented 3 years ago

@KonradIT I anyway planned to share my findings. What is the best way to do so? Can I add this somewhere here in the repository?

KonradIT commented 3 years ago

Yes! Please do, on the Bluetooth folder. Make a PR and I'll clean it up if needed.

Archimede55 commented 3 years ago

Hi @rhoenschrat, waiting for your priceless repository update, could you just anticipate the UUID of the Characteristic involved in the "is registering" notification (just to try to spend some nights trying to obtain the results ;D) I suppose that it will be necessary to enable that notification with the descriptor.

rhoenschrat commented 3 years ago

@Archimede55 until Konrad has merged the pull request you can already check the document in the branch https://github.com/rhoenschrat/goprowifihack/blob/patch-1/Bluetooth/bluetooth-api.md

Archimede55 commented 3 years ago

@rhoenschrat Thanks for your work!

Archimede55 commented 3 years ago

@rhoenschrat thanks again, I read the document and it is really well written and impressive (thinking about at the sniffing work). I have only a doubt about the status response.

In the example you have:

ATT Send Write Request - Handle:0x003C - Value: 0100
ATT Send Write Request - Handle:0x0039 - Value: 0113
ATT Receive Handle Value Notification - Handle:0x003B - Value: 215D 1300 0101 0102 0104 0301 0004 01FF…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8001 0009 0100 0A01 000B 0100 0D04 0000…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8100 0000 0011 0101 1301 0014 0100 1504…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8216 0100 1701 0018 0100 1A01 001B 0100…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8300 1E0A 4865 726F 3842 6C61 636B 1F01…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8421 0100 2204 0000 3E90 2304 0000 4468…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8500 0025 0400 0000 0426 0400 0000 0027…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8604 2812 2531 3525 3031 2530 3325 3038…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8730 3429 0100 2A01 002D 0100 3104 0000…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8800 0000 0006 D7B7 0037 0101 3801 0039…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 894B 3A01 003B 0400 0000 003C 0400 0001…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8A3E 0400 0000 003F 0100 4001 4841 0100…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8B01 6444 0100 4501 0046 015F 4701 0C48…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8C18 4A01 004B 0100 4C01 014D 0101 4E01…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8D51 0101 5201 0153 0101 5501 0056 0100…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8E01 0C5A 0100 5B01 005C 0100 5D04 0000…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8F00 0100 005F 0400 0200 0060 0400 0003…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8000 0000 6204 0600 0000 6304 0000 16CD…
ATT Receive Handle Value Notification - Handle:0x003B - Value: 8100 0065 0100 6601 00

so a "Get camera status" and the content should be a parameter list.

215D lenght

13 ID (get camera status)

00 status/error

then should start the content in the ID/lenght/content format

01 01 01 ID=01 lenght=1 Value=1 but this should be the battery..with 0 or 2 value

02 01 04 ID=02 lenght=1 value=4

but I'm not able to find the ID 08 (the only one I'm interested in..) so I suppose I'm reading the answer in the wrong way...?

rhoenschrat commented 3 years ago

@Archimede55 The PacketLogger shortens the line (indicated by "…") in the summary. If you check the full content, the recording status is there Jan 07 08:04:03.398 ATT Receive 0x005B GoPro 4506 Handle Value Notification - Handle:0x003B - Value: 215D 1300 0101 0102 0103 0301 0004 01FF…
00000000: 1B3B 0021 5D13 0001 0101 0201 0303 0100 .;.!]........... 00000010: 0401 FF06 0100 08 ....... Jan 07 08:04:03.399 ATT Receive 0x005B GoPro 4506 Handle Value Notification - Handle:0x003B - Value: 8001 0009 0100 0A01 000B 0100 0D04 0000…
00000000: 1B3B 0080 0100 0901 000A 0100 0B01 000D .;.............. 00000010: 0400 0000 000E 04 .......

Also for the recording ... Start: Jan 03 09:54:28.350 ATT Receive 0x005D 00:00:00:00:00:00 Handle Value Notification - Handle:0x003B - Value: 0893 0008 0101 0A01 01

Stop: Jan 03 09:58:13.018 ATT Receive 0x005D 00:00:00:00:00:00 Handle Value Notification - Handle:0x003B - Value: 201A 9300 0801 000A 0100 0D04 0000 0000…
Jan 03 09:58:13.047 ATT Receive 0x005D 00:00:00:00:00:00 Handle Value Notification - Handle:0x003B - Value: 803D CF3D 0102 4001 E7

Archimede55 commented 3 years ago

@rhoenschrat ops... I missed this thing :D By the way, since you tested on different camera, The status is always the same? I mean, the recording value is always in the same poistion= (byte number xx..). Just to avoid to parse every time the status...

rhoenschrat commented 3 years ago

@Archimede55 once you activated the status updates with the 0x053 request ID, you will receive a 0X93 notification whenever there is change in the status. These notifications are kind of a surprise package. You know - life was like a box of chocolates. You never know what you're gonna get. 😉 During idle time you will get for example a notification when the battery level drops from 100 to 99. But only when it does. If it does not change, you won't get a notification. During recording, you will get a notification every second, as the current recording time is changing every second. Some of the notification only include the current recording time (0x0D), others do also include the free space (0x36). So also the recording status (0x08) is only included when it changes. When you start the recording, the notification will have the recording status 1 in it. When you stop the recording, it will have the recording status 0 in it. This can be the only parameter in the notification, or it also includes the number of video (0x25) and the free space (0x36). It looks like they are always sorted by status code ID, but I'm not sure. And in the end it doesn't matter. Bottom line: When starting your app, you fetch the current status with with a 0x13 request and get the full status of the camera. Then you activate the status update with 0x53 and deal with every 0X93 notification that you receive to update your status.

Archimede55 commented 3 years ago

@rhoenschrat I was thinking to periodically send just a status request since I'm interested only in the recording flag, but your approach is more correct and clean ;)

rhoenschrat commented 3 years ago

@Archimede55 When I started with this two weeks ago, I also expected that I need to poll the status. I was quite happy to see, that I works using notifications instead. And I also think that this is more the idea of BLE ... as it says Bluetooth Low Energy. Polling for status and sending messages when nothing happens only drains the battery.

KonradIT commented 3 years ago

Hi @rhoenschrat I will merge your pull request tomorrow once I test everything and will also include some gatttool specific code for users to test. Thank you for contributing!

Archimede55 commented 3 years ago

@KonradIT when you merge, I suppose you should correct this:

0D 04 00 00 00 CE 36 08 00 00 06 C4 21 FD

0D | ID 13 = Current recording duration 04 | Length = 4 bytes 000000CE | 206 seconds 36 | ID 54 = Remaning free space 08 | Length = 4 bytes 000006C421FD | 113517053 kilobytes = 108GB

The length of the second part is 8 instead of 4 and I think a 00 byte is missing since 00 00 06 C4 21 FD are only 6 bytes

Archimede55 commented 3 years ago

Hi @rhoenschrat , I implemented it and finally I have the status :D Thanks again! Just a couple of things. I have to check if it is due to QT but when I send the ID=53 I receive just an answer, not a periodic update (during the recording). Since you log a lot of things, do you know which is the confirmation command for the pairing? I mean, when I successfully complete the pairing by QT the Gopro is still in the "Pairing mode" and I have to cancel it, while if I do that with the iPhone the "pairing mode" disappear.

rhoenschrat commented 3 years ago

@Archimede55 just to make sure ... the 0x53 is a information request. So you sent it to handle 39 (UUID b5f90076-aa8d-11e3-9046-0002a5d5c51b) and not to the command handle 2f (UUID b5f90072-aa8d-11e3-9046-0002a5d5c51b) - right?

Regarding the pairing - I don't know. Honestly I did not investigate in this. I will tell, that a prerequisite for my app is, that the GoPros have been paired to the iPhone with the official app before. What I did experience is however, that the HERO8 does properly end the pairing mode. Only HERO7 and below remain in this mode and need to be canceled manually. I guess GoPro has changed something for the HERO8 and HERO9 in preparation of their own Bluetooth remote. For the other cameras I think I remember to saw something on one of the pages or discussions of this repository, that the WiFi API has a command to confirm to the camera that pairing was successful. But I'm not sure.

Archimede55 commented 3 years ago

@rhoenschrat, yes I enable the notification on the UUID b5f90077-aa8d-11e3-9046-0002a5d5c51b (in QT I don't manage the handle but directly the UUID) and then I write 0x53 on the UUID b5f90076-aa8d-11e3-9046-0002a5d5c51b. I corretti receive the notification and reading the value I recognize the ID 0x53 in the response, but I receive it just one time. I don't know if due to QT, but to have the response I hat to enable the notify also on the b5f90077-aa8d-11e3-9046-0002a5d5c51b while you wore that the information notification are automatically enabled.

Thanks for the info about the pairing competition on the hero8!