AlphaLoc is an ESP32 application that allows embedding GPS location data directly into Sony Alpha camera photos via Bluetooth Low Energy (BLE). It acts as a bridge between a standard GPS module and your Sony camera, providing real-time geolocation tagging.
- Automatic Geotagging: Sends GPS coordinates (Latitude, Longitude, Altitude, Time) to the camera.
- BLE Connection: Emulates a smartphone location provider for Sony cameras.
- Dual Configuration: Configurable via a Web Interface (WiFi) or BLE characteristics.
- Status Indicators: NeoPixel (RGB LED) feedback for Camera connection, GPS fix, Battery, and WiFi status.
- Low Power: Supports disabling external peripherals (like Stemma QT) to save power.
The project is set up for PlatformIO and currently supports:
| Board | Environment | Pinout |
|---|---|---|
| DFRobot Beetle ESP32-C6 | esp32c6 |
GPS TX: 5, GPS RX: 4, NeoPixel: 6 |
| Adafruit Feather ESP32-S3 | esp32s3 |
GPS TX: 38, GPS RX: 39, NeoPixel: 6 |
You can easily adapt it to other ESP32 boards by modifying platformio.ini.
The following is a parts list of what I ended up with.
- Adafruit ESP32-S3 Feather, Overview
- Adafruit Ultimate GPS featherwing
- SparkFun RGB LED Breakout - WS2812B
- Adafruit WiFi Antenna with w.FL / MHF3 / IPEX3 Connector
- This is optional if you don't have an ESP32 with a PCB antenna.
- Mini sliding switch (8.5mm x 3.7mm, 3 pin, slider 4mm tall)
- The antenna of a GY-GPS6MV2
- 2x Panasonic NCR18650GA Battery (3450mAh)
- Wires, electrical tape and whatnot
- Holder: Holder for the batteries, ESP32, optional wifi antenna, ...
- Cover: Cover with a press fit for the holder and room for the LED board.
- Cover Large: Same as cover but taller and with room for a larger, external GPS antenna.
-
Connect your GPS module (e.g., GY-GPS6MV2 or an Adafruit Ultimate GPS Featherwing) to the defined TX/RX pins.
-
Flash the firmware using PlatformIO.
pio run -e esp32c6 -t upload
-
Power on the device.
- On your Sony Alpha camera, go to Network -> Bluetooth Settings.
- Enable Bluetooth Function.
- Select Pairing.
- The camera should discover "AlphaLoc". Select it to pair.
- Once paired, go to Location Info. Link Set. and enable it.
- The camera should now show the GPS icon (solid when receiving data).
The NeoPixel LED provides a visual "heartbeat" every 5 seconds. It flashes multiple colors in sequence to report the status of different subsystems:
Sequence: [Camera Status] -> [GPS Status] -> [Battery Status] -> [WiFi Status] -> [Sleep]
- First Flash: Camera Connection
- π’ Green: Connected to camera and bonded.
- π΅ Blue: Connected to camera but not bonded yet.
- π΄ Red: Not connected.
- Second Flash: GPS Fix
- π’ Green: Valid 3D GPS Fix acquired.
- π£ Violet: Fake GPS fix (injected when
ALPHALOC_FAKE_GPS=1). - π΄ Red: No fix (searching for satellites).
- Third Flash: Battery Level (Optional)
- π’ Green: > 50%
- π‘ Yellow: > 30%
- π΄ Red: <= 30%
- Fourth Flash: WiFi/Config (Optional)
- Only appears during the startup "Config Window" (first 5 minutes).
- π΅ Blue: Web server is active.
- β« (Off): Config window closed, WiFi disabled to save power.
Example:
- π΄-π΄-π’-π΅: No camera, no GPS, battery good, config mode active (just turned on).
- π΅-π’-π‘-β«: Camera connected (not bonded yet), GPS fixed, battery medium, normal operation (config closed).
- π’-π’-π΄-β«: Camera connected (bonded), GPS fixed, battery low, normal operation (config closed).
- π΅-π£-π’-β«: Camera connected (not bonded yet), fake GPS fixed, battery good, normal operation (config closed).
β οΈ SECURITY WARNING: The BLE configuration service is DISABLED by default for security reasons. When enabled, it allows UNAUTHENTICATED access to device settings including WiFi passwords. Only enable it (ALPHALOC_BLE_CONFIG=1) in trusted environments or for initial setup, then rebuild with it disabled.
On startup, AlphaLoc enters a Configuration Window (default 5 minutes). During this time, you can change settings via WiFi (if ALPHALOC_WIFI_WEB=1) or BLE (if ALPHALOC_BLE_CONFIG=1).
| Parameter | Description | Default |
|---|---|---|
| Camera Name Prefix | Filter which cameras to connect to. Useful if you have multiple Sonys. | SonyA7 |
| Camera MAC Prefix | Connect only to a specific MAC address prefix. Empty matches any. | (Empty) |
| TZ Offset | Timezone offset in minutes (e.g., 60 for UTC+1). |
60 |
| DST Offset | Daylight Savings Time offset in minutes. | 60 |
| WiFi SSID/Pass | Credentials for connecting to your home WiFi. | WiFi / changeme |
| AP SSID/Pass | Credentials for the hotspot created by AlphaLoc. | AlphaLoc / alphaloc1234 |
| Max GPS Age | How long (seconds) to reuse old coordinates if GPS signal is lost. | 300 |
AlphaLoc tries to connect to the configured WiFi as a client:
- Default SSID:
WiFi - Default Password:
changeme - IP: assigned via DHCP
If it can't connect to the WiFi, it starts an access point itself:
- SSID:
AlphaLoc - Password:
alphaloc1234 - IP:
192.168.4.1(direct link to webserver: http://192.168.4.1/)
To enable this, set the build flag (ALPHALOC_WIFI_WEB=1 in platformio.ini).
You can use a generic BLE app (like nRF Connect) to write to the configuration service.
Service UUID: B1F0B4D5-797B-5A9E-5B4F-4A1F01007EA1
| Characteristic Name | UUID (Base B1F0...) |
R/W | Type (Over BLE) | Description |
|---|---|---|---|---|
| Camera Name Prefix | ...02007EA1 |
R/W | String | Camera name identifier |
| Camera MAC Prefix | ...03007EA1 |
R/W | String | MAC address filter |
| Timezone Offset | ...04007EA1 |
R/W | String (Int) | Minutes from UTC |
| DST Offset | ...05007EA1 |
R/W | String (Int) | Daylight Savings offset (minutes) |
| Wifi SSID | ...07007EA1 |
R/W | String | Station SSID |
| Wifi Password | ...08007EA1 |
R/W | String | Station Password |
| AP SSID | ...09007EA1 |
R/W | String | Access Point SSID |
| AP Password | ...0A007EA1 |
R/W | String | Access Point Password |
| Max GPS Age | ...0B007EA1 |
R/W | String (Int) | Max age of GPS lock in seconds |
| GPS Lock | ...0C007EA1 |
R | String (0/1) | 1 when GPS lock is valid |
| GPS Satellites | ...0D007EA1 |
R | String (Int) | Satellites in view (from GGA) |
| GPS Constellations | ...0E007EA1 |
R | String (Int) | Bitmask: 1=GPS, 2=GLONASS |
| Camera Connected | ...0F007EA1 |
R | String (0/1) | BLE camera link active |
| Camera Bonded | ...10007EA1 |
R | String (0/1) | Link bonded (after pairing) |
If you want to keep WiFi credentials and camera filters out of git, place them in platformio.secrets.ini and keep the file ignored. The build merges these flags into every environment via platformio.ini.
Example platformio.secrets.ini with all supported defaults:
[secrets]
build_flags =
-DALPHALOC_DEFAULT_WIFI_SSID="\"MyWifi\""
-DALPHALOC_DEFAULT_WIFI_PASS="\"MyPass\""
-DALPHALOC_DEFAULT_AP_SSID="\"AlphaLoc\""
-DALPHALOC_DEFAULT_AP_PASS="\"AlphaLocPass\""
-DALPHALOC_DEFAULT_CAMERA_NAME_PREFIX="\"SonyA7\""
-DALPHALOC_DEFAULT_CAMERA_MAC_PREFIX="\"AA:BB:CC\""These values are used as defaults on first boot (or after a factory reset) and can still be changed later via the WiFi or BLE config UIs.
AlphaLoc acts as a BLE client to Sony cameras
- Manufacturer data: company ID
0x012D, product ID0x0003 - Optional name prefix filter:
camera_name_prefix(if set) - Optional MAC prefix filter:
camera_mac_prefix(if set)
AlphaLoc looks for two Sony services (UUIDs are built from 16-bit IDs using the Sony base UUID):
Sony base UUID (constructed):
00000000-0000-8000-ffff-ffff-ffff-ffff
with 16-bit words inserted at positions:
first = 0xDD00 / 0xFF00
second = 0xDD00 / 0xFF00
It accepts either 128-bit UUIDs or 16-bit UUIDs:
- Location Service:
0xDD00 - Remote Service:
0xFF00
Within those services, AlphaLoc searches for:
Location Service (DD00)
0xDD21: Flags read to determine if TZ/DST are required0xDD30: Lock location (0x00 - Off, 0x01 - On)0xDD31: Enable location updates (0x00 - Off, 0x01 - On)0xDD11: Location write characteristic; used for sending GPS payloads
Data is a 95 byte buffer
| Offset | Description | Remark |
|---|---|---|
| [0:1] | Payload Length (exclude these two bytes) | 0x5D = 93 bytes |
| [2:4] | Fixed Data | 0x0802FC |
| [5] | Flag of transmitting timezone offset and DST offset required | 0x03 for transmit and 0x00 for do not transmit |
| [6:10] | Fixed Data | 0x0000101010 |
| [11:14] | Latitude (multiplied by 10000000) | 0x0BF79E5E = 200777310 / 10000000 = 20.077731 |
| [15:18] | Longitude (multiplied by 10000000) | 0x41C385A7 = 1103332775 / 10000000 = 110.3332775 |
| [19:20] | UTC Year | 0x07E4 = 2020 |
| [21] | UTC Month | 0x0B = 11 |
| [22] | UTC Day | 0x05 = 5 |
| [23] | UTC Hour | 0x04 = 4 |
| [24] | UTC Minute | 0x02 = 2 |
| [25] | UTC Second | 0x2A = 42 |
| [26:90] | Zeros | 0x00 |
| *[91:92] | Difference between UTC and current timezone in minutes | 0x01E0 = 480min = 8h (UTC+8) |
| *[93:94] | Difference for DST in current timezone in minutes |
Remote Service (FF00)
0xFF02(notification characteristic; CCCD0x2902)
ADV (Sony) --> connect
|
+--> discover DD00 (Location Service)
| +--> find DD11, DD21, DD30, DD31
| +--> read DD21 flag byte
| +--> enable location writes on DD11
|
+--> discover FF00 (Remote Service)
+--> find FF02
+--> find/guess CCCD (0x2902)
+--> enable notifications
Once services and characteristics are resolved:
- Builds a Sony-compatible location payload
- Writes to
DD11 - Enables FF02 notifications after first location write (if required)
- Camera Name Prefix: Limits connection to cameras starting with this name (Default: "SonyA7").
- Timezone/DST: Offset in minutes for timestamp correction.
- Max GPS Age: How long to keep sending the last known location if GPS signal is lost.
This project uses the Espressif IoT Development Framework (ESP-IDF) within PlatformIO.
Check platformio.ini for build flags and pin definitions.
; Example Override
build_flags =
-DGPS_UART_TX_PIN=5
-DGPS_UART_RX_PIN=4The platformio.ini file defines several build environments for different purposes:
env:esp32c6: The standard production build for the ESP32-C6. Logging is disabled for performance.env:esp32c6-debug: A debugging environment.- Enables verbose logging (
ALPHALOC_VERBOSE=1). - Enables Fake GPS (
ALPHALOC_FAKE_GPS=1): Simulates a stationary location (Munich) for testing without a GPS module or satellite lock.
- Enables verbose logging (
env:esp32c6-debug-gps: Debugging environment using real GPS data but with verbose logging enabled.env:esp32s3: The standard production build for the ESP32-S3. Logging is disabled for performance.env:esp32s3-debug: A debugging environment.- Enables verbose logging (
ALPHALOC_VERBOSE=1). - Enables Fake GPS (
ALPHALOC_FAKE_GPS=1): Simulates a stationary location (Munich) for testing without a GPS module or satellite lock.
- Enables verbose logging (
env:esp32s3-debug-gps: Debugging environment using real GPS data but with verbose logging enabled.
You can customize the firmware behavior using these compilation flags in platformio.ini:
| Flag | Description | Default |
|---|---|---|
ALPHALOC_WIFI_WEB |
Enable internal settings web server. Set to 0 to remove WiFi stack and save power/flash. |
1 |
ALPHALOC_BLE_CONFIG |
Enable BLE configuration service. Note: This allows reading and writing the config via BLE unauthenticated! | 0 (DISABLED) |
ALPHALOC_VERBOSE |
Enable extensive debug logging to serial UART. | 0 |
ALPHALOC_FAKE_GPS |
Ignore UART GPS and output a static test location. | 0 |
ALPHALOC_NEOPIXEL_PIN |
GPIO pin number for the WS2812B NeoPixel. | (Board dependent) |
ALPHALOC_BATTERY_MONITOR |
Enable MAX17048 / LC709203F battery monitor over I2C. | 0 |
ALPHALOC_BATTERY_SDA_PIN |
I2C SDA pin for battery monitor. | (Board dependent) |
ALPHALOC_BATTERY_SCL_PIN |
I2C SCL pin for battery monitor. | (Board dependent) |
ALPHALOC_BATTERY_I2C_POWER_PIN |
Optional power-enable pin for I2C battery monitor. | (Unset) |
GPS_UART_TX_PIN |
TX Pin for GPS Serial (Connects to GPS RX). | (Board dependent) |
GPS_UART_RX_PIN |
RX Pin for GPS Serial (Connects to GPS TX). | (Board dependent) |
DALPHALOC_FACTORY_RESET |
If set to 1, wipes NVS settings on boot. Dangerous. |
Undefined |
Security Best Practices:
- Keep
ALPHALOC_BLE_CONFIG=0in production builds - Only enable BLE config for initial setup in controlled environments
- Use WiFi config (
ALPHALOC_WIFI_WEB=1) with strong AP password instead - Change default WiFi credentials immediately after first boot
There is a bunch of work done by others before me which greatly helped figuring out how the BLE protocol works with the Sony Alpha cameras. I'm sure I'm forgetting a bunch but to at least name a few:
- https://github.com/dzwiedziu-nkg/esp32-a7iv-rc
- https://github.com/ekutner/camera-gps-link
- https://github.com/whc2001/ILCE7M3ExternalGps
- And many more (search GitHub for one of the unique identifiers such as the service UUIDs).