ESP32 Firmware

Build, flash, provision, and maintain the WakeLink firmware that bridges encrypted relay traffic to local Wake-on-LAN packets.

Note
The firmware handles its own identity generation on first boot (MAC-based agent_id) and relies on locally provisioned E2E secrets to securely interact with the relay.

Hardware Requirements

ItemDetails
MCUESP32 (tested on ESP32-WROOM-32)
Flash4 MB recommended
Wi-Fi2.4 GHz 802.11 b/g/n
Status LEDGPIO2 by default

Agent Provisioning

Provisioning is the process of loading the unique configuration into the ESP32's NVS (Non-Volatile Storage).

Provisioning DataSourceStorage
Agent IDHardware (MAC)ESP32 NVS
Relay Access Token (wla_)Relay DashboardESP32 NVS (Hashed)
EWSP E2E SecretClient (Wizard)ESP32 NVS (Plaintext)
Wi-Fi CredentialsUserESP32 NVS
Warning
The EWSP E2E Secret (agent_token) must be generated by your client and never sent to the relay server. The Relay Access Token (wla_...) is provided by the relay for WebSocket authentication.

Build

WakeLink firmware is built with emdformer (emdf) — our Cargo-style build & package manager for embedded firmware. It vendors the ESP32 toolchain and libraries per project into a local cache, so there are no global Arduino IDE or PlatformIO installs to manage. One tool covers resolve, build, flash and serial monitor.

# From the firmware project directory (contains emdformer.toml)
emdf install                  # resolve + fetch toolchain, core and libraries
emdf build --profile release  # compile the firmware
emdf flash                    # auto-detects the serial port
emdf flash --port /dev/ttyUSB0
emdf monitor --baud 115200    # open the serial console

Provisioning

On first boot, the agent starts an AP named WakeLink-Setup. The AP password is an 8-character random string stored in NVS and printed to the serial console on first boot.

Browser portal

Open http://192.168.4.1 and fill in:

FieldDescription
wifi_ssidYour Wi-Fi network name
wifi_passWi-Fi password
server_hostWakeLink relay hostname
server_portUsually 443
tls_enabledEnable WSS/TLS
agent_idRegistered agent identifier
agent_tokenEWSP shared secret
api_tokenRelay API token used for the WebSocket auth step

JSON API

The Android wizard authenticates to the AP JSON API with the AP password and then sends the same fields programmatically.

{
  "wifi_ssid": "MyNetwork",
  "wifi_pass": "secret",
  "server_host": "wakelink-project.org",
  "server_port": 443,
  "tls_enabled": true,
  "agent_id": "esp32-living-room",
  "agent_token": "your-ewsp-secret",
  "api_token": "wla_your_device_relay_token"
}

Local Interfaces

InterfaceDetails
TCP command portPort 7625 for direct LAN EWSP commands
Status HTTP endpointGET /api/info for discovery and health checks
Provisioning portalhttp://192.168.4.1 while AP mode is active
Local WebSocket serverPort 81 for LAN EWSP sessions when enabled

Supported Commands

CommandDescription
pingRound-trip latency test
infoReturn firmware version, uptime, and identifiers
statusReturn Wi-Fi RSSI, heap, and connection state
wakeSend a Wake-on-LAN magic packet
rebootRestart the ESP32
otaDownload and flash a new firmware image
update_tokenReplace the stored per-agent relay token used for WebSocket auth

OTA Signing

Production OTA images are verified with an Ed25519 public key baked into the firmware.

pip install pynacl
python3 scripts/sign_ota.py --gen-key ota_private.key
python3 scripts/sign_ota.py --key ota_private.key \
  --bin .emdformer/build/release/firmware.bin

Use -DWAKELINK_OTA_PUBKEY_HEX=... to embed the matching public key. Developer builds can bypass signature checks with -DWAKELINK_OTA_ALLOW_UNSIGNED=1, but that should never be enabled in production.

Source Layout

File / DirectoryPurpose
WakeLink.inoFirmware entry point
config.*Persistent configuration and NVS helpers
provisioning.*AP portal and JSON provisioning API
cloud.*Relay WebSocket client and reconnect logic
commands.*EWSP command handlers
ota_manager.*OTA download and verification
ws_server.*Local WebSocket server
web_server.*Status and provisioning HTTP endpoints

Continue reading