I've been working on building a homemade camera slider system to make time lapse photos, and I needed a way to trigger my camera (a Sony a6100) to start taking photos at the same time that my slider starts moving. My slider is driven by an ESP32 microcontroller and has a web interface to setup and run automations. This left me with a few options to control my camera:
- Emulate an IR camera remote
- Emulate a Bluetooth LE camera remote
- Use Sony's HTTP based Camera API/SDK
I tried the IR approach first because it was super simple and well documented. Unfortunately after building a test circuit with a spare IR I took out of an old remote, I discovered that while most Sony a6000 series cameras support IR, some newer ones like my a6100 do not. Whoops.
Next I looked at the Camera's API. Sony has two versions of a SDK for developing apps that control its cameras. A deprecated one and a newer beta one. Both are pretty poorly documented. Neither are listed as supporting my specific camera model, but Sony's own applications that presumably use the same APIs work with the a6100, so it seemed worth a shot.
To test I enabled smartphone based remote control in my camera's settings, and connected my laptop to the camera's WiFi Access Point it creates. From there after figuring out the cameras IP and API port using the documented Simple Service Discovery Protocol (SSDP) approach.
Once I had the API base URL I could easily used Postman to snap a shot with one weird caveat. For whatever reason the camera will ignore requests to take a photo 2/3 of the time if you don't first ask it to focus. If you send it those two commands in short succession, it will snap a shot, and even provide you with a URL to download the picture it just too.
This looked like a pretty good approach until I tried to get my camera to connect to my home WiFi instead of operating in Access Point mode. As best I can tell, the a6100 will only remain connected to a WiFi network if it is placed in "Send to Computer" mode, where it pushes photos to a desktop Sony app, and cannot take pictures. Since my microcontroller in my camera slider can't be connected to two networks at once, I need another solution unless I want to rewrite the slider to be controlled over bluetooth and build some app to use that instead of a browser.
With the other two control methods off the table, that leaves Bluetooth. Sony sells a Bluetooth Low Energy remote (the RMT-P1BT) that works with it's Bluetooth enabled cameras, but provides no documentation of the interface. Using a BLE app on my phone I can look at the services and characteristics the camera exposes which is a good start. One service in particular is of particular interest,
8000-ff00-ff00-ffffffffffffffffffff, this service has a notification characteristic that when you subscribe to it gives you a unique ID back for ever button you press on the camera body. It has a writable characteristic as well. Unfortunately simply sending back the notification values to the write characteristic doesn't seem to do anything.
I saw that the Sony Android app does have a bluetooth intent declared even though it looks like it mostly uses the WiFi SDK to control the camera. I tried decompiling the APK and looking through the source for any info, and while it does have a class that handles some BLE communication, it seems to be there solely as a way to aid in discover and paring the WiFi to the camera using other BLE services. The
ff00 service isn't referenced in the code.
I also found an article online that corroborated the purpose of most of the BLE services, but crucially lacked the actual codes for camera control.
This left me with one more doable option, buy a remote and use a BLE Sniffer to capture the traffic. Luckily there is a knock off remote manufactured by JJC that has the same model number but retails for 1/3 the price of the Sony remote. I ordered one on Amazon and it easily paired to my camera and controls everything I could ask for. I already had a Bluetooth sniffer based on the Nordic nRF51 chip laying around that works with some python plugin to WireShark.
The general idea for bluetooth sniffing of "secure" communications is that your sniffer needs to be running when you first pair the two target BLE devices you want to capture the communications between. Unfortunately this process can be pretty hard to pull off, other bluetooth devices nearby can interfere with the capture, and BLE operates on 3 radio channels with channel hopping behavior, but the sniffer can only be sniffing one channel at any given time. This means that you only have a 33% chance of successfully capturing a given paring message. I tried and tried to get it to work including taking the target devices into my backyard away from the RF noise of my house but nothing worked.
Before giving up, on a whim I decided to buy a second bluetooth sniffer. I bought a USB dongle dev board based on the newer nRF52840. It didn't have the sniffing firmware preloaded like my other dongle, but Nordic provides the
.hex images. The dev kit I used had a file system based bootloader instead of DFU, so I had to use a python script to convert the
.hex to a
.u2f file before I could just drag and drop it to the board like a thumb drive. The bootloader no longer seems to allow me to flash the board again that way, but it worked the first time with the sniffer firmware, so that's a problem for another day if I ever decide I want to use the board for something else.
The new sniffer worked on the second attempt, and from there I was able to record every button press on remote. All commands send one code for pressing the button down, and another when you release the button with the exception of the video record button which only sends when you press it down, and operates like a toggle. A light on the remote stays on when the camera is recording, but I'm not absolutely sure that it actually is reading that status back out of the camera vs just tracking it's own state.
So, finally, presented to the internet for anyone who ever want's to control a modern BLE equipped Sony camera without going through all of that effort, here's what you need to do.
- Pair your device with the camera, the cameras don't appear to respond to commands from unpaired devices and immediately disconnect.
- Write to characteristic
8000-ff00-ff00-ffffffffffffffffffffone of the following commands:
|Zoom In Down||
|Zoom In Up||
|Zoom Out Down||
|Zoom Out Up||
|Focus In? Down||
|Focus In? Up||
|Focus Out? Down||
|Focus Out? Up||
To reliably get the camera to take a picture, you'll want to first send the focus command, so the following 4 commands are needed in this order: