Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "third_party/opendroneid-core-c"]
path = third_party/opendroneid-core-c
url = https://github.com/opendroneid/opendroneid-core-c.git
[submodule "third_party/mavlink_c_library_v2"]
path = third_party/mavlink_c_library_v2
url = https://github.com/mavlink/c_library_v2.git
120 changes: 97 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ and navigate to **ESP Remote ID**. The sections below explain what each option m
| **UAS ID** | Unique identifier for the aircraft, broadcast in the Basic ID message. Max 20 characters. |
| **Operator registration ID** | Your national pilot/operator registration number (e.g. an EASA number like `FIN87ASTRDGE12K8`), broadcast in the Operator ID message. Max 20 characters. |

Set both to your actual registration values before any flight. The placeholder defaults (`CHANGE_ME_*`) are not valid for operation.
Set both to your actual registration values before any flight. The placeholder defaults (`CHANGE_ME_*`) are not valid for operation and intentionally block all broadcasts until replaced or overridden by valid MAVLink OpenDroneID input.

### UAS ID type

Expand Down Expand Up @@ -106,15 +106,102 @@ BLE is enabled by default. Wi-Fi Beacon and Wi-Fi NAN are available but disabled
| Option | Default | Description |
|--------|---------|-------------|
| `Enable Bluetooth LE legacy advertisements` | Enabled | Broadcasts Android-compatible BLE service-data advertisements on UUID `0xFFFA`. |
| `BLE advertisement rotation interval` | `250 ms` | BLE payload rotation cadence. Default keeps Location refreshed around 1 Hz while also rotating Basic ID, System, and Operator ID. |
| `Enable Wi-Fi Beacon advertisements` | Disabled | Broadcasts OpenDroneID Message Pack payloads in Wi-Fi Beacon vendor IEs. |
| `Enable Wi-Fi NAN advertisements` | Disabled | Broadcasts OpenDroneID Message Pack payloads in Wi-Fi NAN sync/action frames. |
| `Wi-Fi Remote ID channel` | `6` | 2.4 GHz channel used by the ESP32-S3 Wi-Fi transport. |
| `Wi-Fi Remote ID transmit interval` | `1000 ms` | Remote ID Wi-Fi cadence. |
| `Wi-Fi TX power` | `20 dBm` | Converted internally to ESP-IDF quarter-dBm units. |
| `Wi-Fi Beacon SSID` | `OpenDroneID` | SSID embedded only in Beacon frames. Receivers should parse the vendor IE, not rely on this SSID. |
| `TX status LED GPIO` | Disabled (`-1`) | Optional simple GPIO LED that pulses after each successful BLE, Wi-Fi Beacon, or Wi-Fi NAN transmission. |
| `TX status LED is active high` | Enabled | Disable for active-low LEDs. |
| `TX status LED pulse duration` | `40 ms` | Duration of each transmission pulse. |
| `Wi-Fi Beacon TX interval` | `1000 ms` | Wi-Fi Beacon transmission cadence. |
| `Wi-Fi NAN TX interval` | `1000 ms` | Wi-Fi NAN sync/action transmission cadence. |
| `Enable onboard RGB status indicator` | Disabled | Drives a board-mounted addressable RGB LED as a local status indicator. |
| `Onboard RGB LED data GPIO` | `48` | Physical ESP32-S3 GPIO connected to the onboard WS2812/SK6812-style RGB LED data input. The UICPAL ESP32-S3-N16R8 board variant used by this firmware uses GPIO48; other variants may use GPIO33 or another pin. |
| `Onboard RGB LED brightness` | `16%` | Scales the local indicator LED brightness. |
| `Onboard RGB operational flash pattern` | `Drone beacon 1 Hz short flash` | Pattern used after transports have started and valid Remote ID identity is available. |
| `Enable external GPIO lighting outputs` | Disabled | Enables up to five simple GPIO outputs for external light trigger circuits. |
| `Startup delay before transmissions` | `10000 ms` | Development delay before starting BLE/Wi-Fi so there is time to attach the serial monitor. |

### Onboard RGB Indicator

The onboard RGB indicator is intended for local module status, not for driving external aviation lights. It uses the ESP32-S3 RMT peripheral to drive one addressable RGB LED, typically a WS2812/SK6812 device on the devboard. The UICPAL ESP32-S3-N16R8 board variant used by this firmware uses GPIO48 for the onboard RGB LED.

Status behavior:

| Firmware state | Onboard RGB behavior |
|----------------|----------------------|
| Waiting for Remote ID readiness or transport startup | Amber slow blink |
| Operational | Configured green flash pattern |
| Error state | Red fast blink |

Operational means the firmware has started its enabled transports and the state store has a valid Basic ID/UAS ID plus Operator ID. This prevents the indicator from showing the operational pattern while placeholder identity values are still blocking broadcasts.

The RGB data pin is not a suitable transistor trigger for external lights because addressable LEDs use a high-speed encoded data waveform. Use the external GPIO lighting outputs for that purpose.

### External GPIO Lighting

The external GPIO lighting module provides five independently configurable GPIO outputs. These outputs are logic-level triggers intended for transistor, MOSFET, relay-driver, or opto-isolator inputs. Do not power aircraft lights directly from ESP32 GPIO pins.

Each output has its own configuration:

| Setting | Description |
|---------|-------------|
| `Enable output N` | Enables this lighting output. |
| `Output N GPIO` | Physical ESP32-S3 GPIO used as the trigger signal. |
| `Output N active high` | Controls whether logical ON drives the pin high or low. |
| `Output N open drain` | Uses open-drain output mode for compatible external circuits. |
| `Output N operational pattern` | Pattern used when Remote ID transports are started and identity is ready. |
| `Output N pattern phase offset` | Staggers matching patterns across multiple outputs. |

Outputs remain off until valid Basic ID/UAS ID and Operator ID are available and enabled transports have started.

Available operational patterns:

- `Solid on`
- `Beacon 1 Hz short flash`
- `Beacon 1 Hz 50% duty`
- `Single strobe`
- `Double strobe`
- `Triple strobe`
- `Fast strobe`

Example setup:

```text
Output 0: GPIO 4, Double strobe, phase 0 ms
Output 1: GPIO 5, Double strobe, phase 500 ms
Output 2: GPIO 6, Beacon 1 Hz short flash
Output 3: disabled
Output 4: disabled
```

### MAVLink OpenDroneID Input

MAVLink input is available but disabled by default. When enabled, the firmware listens on a configured UART and accepts these MAVLink OpenDroneID messages:

- `OPEN_DRONE_ID_BASIC_ID`
- `OPEN_DRONE_ID_OPERATOR_ID`
- `OPEN_DRONE_ID_LOCATION`

Incoming Basic ID and Operator ID updates feed the same readiness gate as Kconfig values. This allows a flight controller or companion computer to provide identity at runtime while keeping the placeholder Kconfig values in flash. Broadcasts still do not start until a valid Basic ID/UAS ID and Operator ID are present.

| Option | Default | Description |
|--------|---------|-------------|
| `Enable MAVLink OpenDroneID UART input` | Disabled | Enables the UART MAVLink parser and state producer. |
| `MAVLink UART number` | `1` | ESP32-S3 UART peripheral used for input. This does not imply physical pins. |
| `MAVLink UART baud rate` | `57600` | UART baud rate. Common values are `57600`, `115200`, and `921600`. |
| `MAVLink UART RX GPIO` | `-1` | Physical ESP32-S3 pin routed to the selected UART RX signal. Connect this to the flight controller MAVLink TX pin. Must be configured when MAVLink input is enabled. |
| `MAVLink UART TX GPIO` | `-1` | Optional physical ESP32-S3 pin routed to the selected UART TX signal. Connect this to the flight controller MAVLink RX pin only for bidirectional wiring. Leave as `-1` for receive-only. |
| `Accepted MAVLink target system` | `0` | `0` accepts all systems; non-zero accepts that system or broadcast target `0`. |
| `Accepted MAVLink target component` | `0` | `0` accepts all components; non-zero accepts that component or broadcast target `0`. |

On ESP32-S3, the UART number selects the hardware UART block (`UART0`, `UART1`, or `UART2`). It does not uniquely select board pins. UART signals are routed through the ESP32 GPIO matrix, and many dev boards label only the programming/debug serial pins as `RX`/`TX`. Choose GPIOs that are exposed on your board and not already used by USB serial, flash/PSRAM, buttons, LEDs, or strapping functions.

Receive-only wiring is enough for the current MAVLink producer:

```text
Flight controller TX -> ESP32-S3 MAVLink UART RX GPIO
Flight controller GND -> ESP32-S3 GND
```

For Android app testing, use one transport at a time because many receiver apps do not display whether a detected aircraft came from BLE or Wi-Fi.

Expand All @@ -130,6 +217,8 @@ Before flashing for any actual operation:
- [ ] Set **EU operation category** to **Open** (or your authorised category)
- [ ] Optionally enable **Broadcast a known takeoff position** and enter your takeoff coordinates

Note: BLE and Wi-Fi transports wait for the store readiness gate before transmitting. The gate requires a usable Basic ID/UAS ID and Operator ID, either from Kconfig or from runtime producers such as MAVLink.

## Prerequisites

- ESP32-S3 board
Expand Down Expand Up @@ -164,21 +253,6 @@ The default ESP serial device inside the container is `/dev/ttyESP32`. Override
make flash ESPPORT=/dev/ttyACM0
```

## Architecture

The ESP-IDF component is split so transports can share the same Remote ID state and OpenDroneID encoding:

- `src/remoteid/main.c`: application entrypoint and top-level startup.
- `src/remoteid/remoteid/config.h`: compile-time configuration constants from Kconfig.
- `src/remoteid/remoteid/types.h`: internal Remote ID state and message bundle types.
- `src/remoteid/remoteid/model.c`: builds the current aircraft/operator/location state from configuration.
- `src/remoteid/remoteid/encode.c`: converts internal state into official OpenDroneID messages.
- `src/remoteid/remoteid/led.c`: optional TX status LED pulse handling.
- `src/remoteid/remoteid/ble.c`: NimBLE lifecycle, TX power, and BLE legacy advertisement rotation.
- `src/remoteid/remoteid/wifi.c`: ESP-IDF Wi-Fi setup and OpenDroneID Wi-Fi Beacon/NAN transmission.

Both transports use the same `model` and `encode` modules instead of rebuilding message payloads independently.

## Transmit Power

OpenDroneID BLE reception range is not guaranteed by a fixed distance in the EU documents; practical range depends on transmitter power, receiver hardware, antenna design, enclosure, orientation, and RF environment. This firmware therefore makes BLE advertising TX power explicit and configurable.
Expand All @@ -191,9 +265,9 @@ CONFIG_REMOTEID_BLE_TX_POWER_P9=y

Change it with `make menuconfig` under `ESP Remote ID -> BLE advertising TX power`, or by editing `sdkconfig.defaults` before regenerating `sdkconfig`. Keep the configured level within the limits of your board, antenna, enclosure, and local RF rules.

## macOS Serial Bridge
## (macOS) Serial Bridge

Docker Desktop on macOS does not expose `/dev/cu.*` serial devices directly to Linux containers. Use `socat` to bridge the ESP32-S3 USB serial device from the host into the devcontainer.
Docker on macOS does not expose `/dev/cu.*` serial devices directly to Linux containers. Use `socat` to bridge the ESP32-S3 USB serial device from the host into the devcontainer.

On the macOS host:

Expand Down Expand Up @@ -244,7 +318,7 @@ Use `make menuconfig` under **ESP Remote ID** within the `Component config` menu

For Wi-Fi-only testing, flash the firmware and use an Android receiver that supports the specific Wi-Fi transport being tested. If the app does not show a source transport, enable only one Wi-Fi transport at a time so any detection has a known source.

The screenshot below shows the OpenDroneID Android app receiving live advertisements from the module. The placeholder identifiers (`CHANGE_ME_UAS_ID`, `CHANGE_ME_OP_ID`) are visible, replace these with your registration details before any flight.
The screenshot below shows the OpenDroneID Android app receiving live advertisements from the module. Current firmware blocks placeholder identifiers (`CHANGE_ME_UAS_ID`, `CHANGE_ME_OP_ID`), so replace these with your registration details or provide valid MAVLink OpenDroneID identity before testing reception.

<p align="center">
<img src=".github/images/android-opendroneid.png" width="300" alt="OpenDroneID Android app showing one detected drone with Basic ID, Location (no position), System, and Operator ID messages">
Expand Down
12 changes: 11 additions & 1 deletion src/remoteid/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@ idf_component_register(
"main.c"
"remoteid/ble.c"
"remoteid/encode.c"
"remoteid/led.c"
"remoteid/indicator.c"
"remoteid/lighting.c"
"remoteid/mavlink.c"
"remoteid/model.c"
"remoteid/pattern.c"
"remoteid/store.c"
"remoteid/wifi.c"
INCLUDE_DIRS
"."
"remoteid"
REQUIRES
bt
esp_driver_gpio
esp_driver_rmt
esp_driver_uart
esp_event
esp_netif
esp_timer
esp_wifi
nvs_flash
opendroneid_core
)

target_include_directories(${COMPONENT_LIB} PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/../../third_party/mavlink_c_library_v2"
)
Loading
Loading