Skip to main content
DEJA

πŸš€ Deploy to Devices

The DEJA deploy wizard reads your device's configuration from DEJA Cloud, generates the right config files for the device type, and (optionally) flashes the firmware. The same wizard handles all four IO device types β€” deja-arduino, deja-esp32, deja-esp32-wifi, and deja-mqtt.

🧩 No code to write. DEJA IO includes the firmware. Plug in the board, attach your accessories, configure them in Throttle, and deploy. The firmware is built from your configuration and ships as readable source, so changing a pin is just a redeploy.

On a device's Firmware section in Throttle, the install tabs are Browser (install straight from a browser with Web Serial, such as Chrome or Edge β€” see Install from your browser below), CLI (deja deploy <id>, shown with your device's ID filled in) and Terminal (build and flash by hand β€” see Flashing By Hand below).

🎬 Running the Deploy Wizard

deja deploy

The interactive wizard walks you through:

  1. πŸ—ΊοΈ Layout selection β€” pick the layout from your DEJA account
  2. πŸ“Ÿ Device selection β€” pick a registered device (auto-filtered to flashable types)
  3. πŸ” WiFi and connection β€” only for deja-esp32-wifi and deja-mqtt: keep the credentials from the previous build, or enter the SSID and password plus the MQTT broker IP β€” or, for WebSocket devices, the DEJA server host and port (see WebSocket devices)
  4. πŸ“¦ Config generation β€” pulls in the device's configuration along with any effects, turnouts, sensors, and signals assigned to it in Throttle, and writes platform-specific config files
  5. ⬆️ Build & flash β€” compiles the firmware (or copies CircuitPython files) and uploads to the connected board

🧰 What deja deploy installs, and where

The first time you flash an Arduino or ESP32, the wizard asks once before downloading its tools. Pass --yes to accept those download questions (and the port question below) without being asked. Without a terminal and without --yes, it stops straight away instead of waiting for an answer.

--yes doesn't make deja deploy fully unattended: you still choose the deploy method and confirm or pick the serial port, and the device too unless you name it (deja deploy <deviceId>).

What Where Size
arduino-cli 1.5.1 + Arduino AVR boards (arduino:avr 1.8.6) ~/.deja/tools/ about 150 MB
ESP32 board support (esp32:esp32 3.3.8, asked separately) ~/.deja/tools/arduino/ about 1.5 GB on macOS and Linux, about 1.7 GB on Windows
Arduino libraries: PubSubClient 2.8.0, Adafruit BusIO 1.17.4, Adafruit PWM Servo Driver 3.0.3, ArduinoJson 7.4.3, WebSockets 2.7.2, TurnoutPulser 1.0.1 ~/.deja/tools/arduino/user/ small
πŸš‰ DCC-EX CommandStation-EX source (v5.6.6-Prod, EX-CSB1 only) ~/.deja/cache/dcc-ex/ about 1 MB
πŸš‰ ESP32 board support for DCC-EX (esp32:esp32 2.0.17, EX-CSB1 only, asked separately) ~/.deja/arduino-dccex/ about 1.5 GB download, needs about 5 GB free

DCC-EX gets its own ESP32 core, kept apart in ~/.deja/arduino-dccex/, because DCC-EX can't build on ESP32 core 3.x, which DEJA's own boards use. Having both side by side is normal. The DCC-EX source is checked against a SHA-256 written into DEJA before it is used, and a download that fails the check is thrown away.

These are DEJA's own copies, pinned to tested versions. DEJA checks the arduino-cli download against a SHA-256 written into DEJA itself before it is unpacked or run. The cores and libraries are then downloaded by arduino-cli, which checks each one against its package index (Espressif's ESP32 index is not signed). They never change an Arduino IDE you already have. Nothing needs sudo.

Using your own arduino-cli: set DEJA_ARDUINO_CLI=/path/to/arduino-cli (from a source checkout with no DEJA copy yet, an arduino-cli on your PATH is used the same way). It is your binary and your config, so DEJA does not checksum it, and DEJA's pinned cores and libraries install into your setup. The wizard prints a notice when that changes a version you had.

Generated firmware bundles are kept in ~/.deja/builds/ (readable only by your user account). They hold your WiFi password and each WebSocket device's token. deja update never touches them, so redeploying a WebSocket device keeps it paired.

On an installed copy, if the DEJA server is using the board's USB port, the wizard offers to disconnect it for the upload (the default is yes) and always reconnects it afterwards. Downloads and the compile happen first, while the server still has the board. With --yes, or when there is no terminal, it takes the default (yes) without asking. For an EX-CommandStation, trains stop until it reconnects. From a source checkout (deja deploy run from the repo, or pnpm run deploy in io/), the wizard has no link to the server, so stop the server or disconnect the device in Throttle β†’ Devices before you flash.

After a successful flash, the wizard records lastDeployedAt and firmwareVersion on the device.

πŸ“¦ Installed copies

deja deploy runs on a normal installed copy: no source checkout, pnpm, or admin keys. It first checks that the firmware shipped with your server matches the installed version, and tells you to run deja update if it doesn't.

Boards deja deploy installs: Arduino Mega, ESP32 (USB), ESP32 (WiFi), Pico W and EX-CSB1 (EX-CommandStation or booster).

  • πŸš‰ EX-CommandStation: an EX-CSB1 builds and flashes with deja deploy (DEJA downloads DCC-EX v5.6.6-Prod, adds your track outputs, and compiles it). The device's Expansion setting picks the motor shield. A booster is deployed the same way. A Mega EX-CommandStation uses DCC-EX's EX-Installer. DEJA sends your track outputs to the EX-CommandStation each time the DEJA Server connects to it; to apply a change right away, disconnect and reconnect it.
  • πŸ’‘ LED strips (DEJA LED, WLED): these run WLED, not DEJA firmware. Install WLED with the WLED web installer, then add or connect the board in Throttle as a WLED device.

Exit codes: 0 built or flashed, 1 error, 2 cancelled. For diagnostics, run node ~/.deja/server/deploy.js --self-check.

The firmware source ships with the server, along with notices for the MIT-licensed Adafruit CircuitPython libraries it bundles. arduino-cli and the EX-CommandStation firmware (CommandStation-EX) are GPL-3.0 and are downloaded on your machine, never redistributed by DEJA.

πŸ“¦ What Gets Deployed

🟒 deja-arduino (Arduino Mega over USB)

Generates config.h with:

  • DEVICE_ID from the device registered in Throttle
  • Feature flags based on what's configured (effects β†’ ENABLE_OUTPUTS, turnouts β†’ ENABLE_TURNOUTS, etc.)
  • OUTPINS, SIGNALPINS, SENSORPINS arrays from your device's pin mapping
  • TurnoutPulser definitions from your configured turnouts

Then compiles + uploads via arduino-cli against the Mega FQBN.

🟠 deja-esp32 (ESP32 over USB)

Same config.h shape as deja-arduino (the sketch is shared) β€” only the build target changes. Compiles + uploads via arduino-cli against the ESP32 FQBN at 460800 baud upload speed.

πŸ›œ deja-esp32-wifi (ESP32 over WiFi β€” MQTT or WebSocket)

Generates config.h with everything deja-arduino ships plus the WiFi and transport settings baked in at build time:

  • WIFI_SSID, WIFI_PASSWORD β€” entered during the wizard
  • DEJA_TRANSPORT_WS β€” 1 when the device's transport is WebSocket, else 0
  • MQTT_BROKER β€” entered during the wizard (MQTT devices); MQTT_PORT is 1883. MQTT_USERNAME / MQTT_PASSWORD are written empty β€” edit config.h by hand if your broker needs them
  • WS_HOST, WS_PORT, WS_TOKEN β€” WebSocket devices: the server host and port from the wizard, and the generated token
  • LAYOUT_ID, DEVICE_ID, TOPIC_ID β€” sourced from your layout's DEJA Cloud config

Then compiles + uploads against the ESP32 FQBN (with -DWEBSOCKETS_TCP_TIMEOUT=1000, so an unreachable server stalls each connect attempt for about a second rather than five). After flashing, the device connects to WiFi, then subscribes to DEJA/{LAYOUT_ID}/{DEVICE_ID} (MQTT) or opens ws://{WS_HOST}:{WS_PORT}/device (WebSocket), and starts processing commands.

πŸ“ deja-mqtt (Raspberry Pi Pico W)

Generates:

  • settings.toml with WiFi credentials, TRANSPORT, the MQTT broker or WebSocket host/port/token, layout ID, and device ID
  • config.json with the pin mapping, Kato turnouts and sensors from your device configuration

Then copies code.py, the other firmware files, lib/, settings.toml, and config.json to the mounted CIRCUITPY drive β€” no compilation required.

WebSocket devices

When the device's Transport is WebSocket (ESP32 WiFi or Pico W), deja deploy asks for the DEJA server host (default: this machine's LAN IPv4) and port (default VITE_WS_PORT, else 8082) instead of an MQTT broker. It then:

  1. Generates a per-device token (32 random bytes, 64 hex characters) and bakes it into config.h / settings.toml.
  2. Saves only the token's SHA-256 hash to the device in DEJA Cloud β€” the server checks every connection against it.

Redeploying reuses the token from the previous bundle (if it's a valid 64-hex token), so an already-flashed board keeps working. Options:

Flag Env Effect
--ws-host <host> WS_HOST Server host to bake in. Always wins over the previous bundle and skips the prompt
--ws-port <port> WS_PORT Server port (integer 1–65535). Always wins; an invalid value stops the deploy
--rotate-token β€” Issue a new token. Boards flashed with the old one are refused until you reflash them

pnpm build:firmware (from io/) handles WebSocket devices the same way and accepts the same flags.

🌐 Install from your browser (ESP32 WiFi and Arduino Mega)

For a deja-esp32-wifi board or a deja-arduino Arduino Mega 2560 you can skip the command line. In Throttle, open Devices, pick the device, then Firmware β†’ Browser. Plug the board into your computer with a USB cable. Four steps take you from a blank board to an online device:

  1. πŸ”Œ Plug it in β€” click Connect board and choose the board's USB serial port.
  2. πŸ‘€ Review β€” check the pins, your WiFi Network and Password ("Sent over USB. Never stored.") and the DEJA server Address and Port, then click Install firmware.
  3. ⬇️ Install β€” Throttle writes the firmware and sends the device's configuration. Don't unplug the board until it says Online, and keep the tab open.
  4. 🟒 Online β€” the board restarts, joins your WiFi and checks in with the server. Click Done.

This needs a browser with Web Serial, such as Chrome or Edge, on a computer, loaded over HTTPS (the hosted Throttle, or localhost). Safari and phones can't talk to USB serial, so use deja deploy above, which also works for every other device type. A browser install leaves the device status LED unlit unless you choose a pin under Status LEDs.

On an Arduino Mega 2560 there is nothing to type: Review shows the pins, and Install writes the firmware with this device's configuration already inside it, then reads it back to check. If the DEJA server has the Mega's port open, Throttle asks it to let go during the install and hands the port back afterwards. A Mega holds up to 64 outputs, 32 signal pins, 32 sensors, 24 Kato turnouts and 16 servos; for more, use deja deploy. If you build the sketch yourself in the Arduino IDE, an existing config.h keeps working and builds as a baked build; regenerate it from the device page only to pick up new settings.


πŸ› οΈ Flashing By Hand

If you'd rather flash an Arduino-family board yourself instead of letting the wizard do it, deja deploy also drops a self-contained bundle you can open in PlatformIO, Arduino CLI, or the Arduino IDE. The exact commands for your board are shown on the device's page in Throttle (Devices β†’ the device) and in the bundle's own DEPLOYMENT.md β€” copy them from there rather than guessing, since they're generated per device type.

deja-mqtt (Pico W) doesn't have a manual build step β€” it's just CircuitPython files copied to the CIRCUITPY drive, which the wizard does for you.

Your device must be registered in Throttle (Devices) before deploying. See Devices.

πŸ“š Next Steps