CFMS — Court File Management System

ESP32 Firmware Deployment Guide

Step-by-step instructions for flashing the ESP32-S3 Trolley and ESP32-P4 Workstation units

Contents

  1. Prerequisites — Install ESP-IDF (Once)
  2. Part 1 — Flash Each Trolley Device (ESP32-S3)
  3. Part 2 — Flash Each Workstation Device (ESP32-P4)
  4. Flash Order Summary
  5. Post-Flash End-to-End Verification
0

Prerequisites — Install ESP-IDF (Do Once)

The workstation firmware requires ESP-IDF 5.3+. This version also covers the trolley (which requires 5.2+). Install once on your Mac before flashing any device.

1

Install system dependencies and clone ESP-IDF

# Install build tools via Homebrew
brew install cmake ninja dfu-util

# Clone ESP-IDF v5.3 with all submodules
mkdir ~/esp && cd ~/esp
git clone -b v5.3 --recursive https://github.com/espressif/esp-idf.git

# Run the installer for both chip targets
cd esp-idf
./install.sh esp32s3,esp32p4
2

Activate the environment and verify

Run this every new terminal session before any idf.py command:

. ~/esp/esp-idf/export.sh

Confirm the installation:

idf.py --version
# Expected output: ESP-IDF v5.3.x

1

Part 1 — Flash Each Trolley Device (ESP32-S3)

Target board: LILYGO T-Display-S3 (or equivalent ESP32-S3 with 1.9" ST7789v2 touchscreen). Repeat Steps 1–5 for each trolley unit. Steps 3–5 do not require a rebuild between units unless you change config.h.

1

Edit config.h — WiFi credentials and server URL

Open firmware/trolley/main/config.h and fill in the court WiFi network details:

/* ── WiFi credentials ──────────────────────────────────────── */
#define CFMS_WIFI_SSID    "YourCourtWiFiName"
#define CFMS_WIFI_PASS    "YourCourtWiFiPassword"

/* ── Server (Raspberry Pi static IP) ──────────────────────── */
#define CFMS_SERVER_URL   "http://192.168.1.100"   // confirm IP matches your RPi
#define CFMS_SERVER_PORT  80

/* ── Device ID — leave EMPTY, auto-generated from chip ID ─── */
#define CFMS_DEVICE_ID_DEFAULT  ""

Pin conflict to verify before building: The default config assigns the RFID UART to GPIO 17/18 and the capacitive touch IC (CST816S) I2C to the same GPIO 17/18. Check your physical board's schematic. If your RFID module is wired to different GPIO pins, update RFID_UART_TX_PIN and RFID_UART_RX_PIN to match before running the build.

2

Connect the board and find the serial port

Connect the ESP32-S3 via USB-C. Identify its port:

ls /dev/tty.usb*
# Examples: /dev/tty.usbserial-0001  or  /dev/tty.SLAB_USBtoUART
3

Set target, build, and flash

cd /path/to/file_tracking_system_ESP32_RFID/firmware/trolley

. ~/esp/esp-idf/export.sh

idf.py set-target esp32s3
idf.py build
idf.py -p /dev/tty.usbserial-0001 flash monitor

Replace /dev/tty.usbserial-0001 with your actual port from Step 2.
If the board does not enter flash mode automatically: hold BOOT, press RST, release BOOT.

4

Verify boot output in the monitor

Successful boot looks like this:

I (xxx) CFMS_WIFI: Connected to AP, IP: 192.168.1.XXX
I (xxx) CFMS_API:  Heartbeat → 200
I (xxx) CFMS_BLE:  Advertising as CFMS-TRL-A1B2C3
I (xxx) CFMS_RFID: UHF module ready, power=26 dBm

📝 Note the device ID (e.g. CFMS-TRL-A1B2C3) — you will need it in Step 5.

Press Ctrl+] to exit the monitor.

5

Register the device in the CFMS admin panel

Log into the web UI → Admin → Devices → Register Trolley

  • Enter the device ID noted from Step 4
  • Give it a descriptive name (e.g. Trolley 1)
  • Submit — the device is now in the registry and will receive OTA updates

Repeat Steps 2–5 for each additional trolley unit. There is no need to re-run idf.py build between units unless config.h changes. WiFi credentials are the same for all trolleys.


2

Part 2 — Flash Each Workstation Device (ESP32-P4)

Target board: GuiFiOn JC-ESP32P4-M3 (ESP32-P4, 32 MB PSRAM, 3" DSI display). Repeat Steps 1–6 for each workstation. The critical per-unit change is CFMS_WS_TYPE in config.h.

1

Edit config.h — set the workstation type

Open firmware/workstation/main/config.h. This is the only setting that differs between units:

/* ── Workstation type — change per unit ────────────────────── */
#define WS_TYPE_SECTION   0   // section workstation (can encode blank tags)
#define WS_TYPE_JUDGE     1   // judge secretary (no blank tag encoding)

#define CFMS_WS_TYPE    WS_TYPE_SECTION   // ← change to WS_TYPE_JUDGE for judge units

/* ── Server ─────────────────────────────────────────────────── */
#define CFMS_SERVER_URL    "http://192.168.1.100"
#define CFMS_SERVER_PORT   80

Device ID is automatically derived from the Ethernet MAC address on first boot and stored in NVS. Each unit gets a unique ID without any manual configuration.

2

Connect the board and find the serial port

ls /dev/tty.usb*
3

Set target, build, and flash

cd /path/to/file_tracking_system_ESP32_RFID/firmware/workstation

. ~/esp/esp-idf/export.sh

idf.py set-target esp32p4
idf.py build
idf.py -p /dev/tty.usbserial-0001 flash monitor
4

Verify boot output in the monitor

Successful boot looks like this:

I (xxx) CFMS_ETH:       Ethernet link up, IP: 192.168.1.XXX
I (xxx) CFMS_WS:        Device ID assigned: WS-AA:BB:CC:DD:EE:FF
I (xxx) CFMS_API:       Heartbeat → 200
I (xxx) CFMS_BLE:       Scanning for CFMS-TRL...
I (xxx) CFMS_WS_SERVER: WebSocket server listening on :8765

📝 Note the device ID (e.g. WS-AA:BB:CC:DD:EE:FF) — needed in Step 5.

Press Ctrl+] to exit the monitor.

5

Register the device and assign its location in the CFMS admin panel

Log into the web UI → Admin → Workstations → Create Workstation

  • Set type to match what was set in config.h (Section or Judge)
  • Set the section or judge association for this physical location
  • Note the workstation ID returned by the system
6

Write location ID to NVS (optional — skips manual selection at login)

If you want staff to skip the workstation selection dropdown on login, write the CFMS workstation ID into the device's NVS partition:

# While the monitor is open on the device in question:
idf.py -p /dev/tty.usbserial-0001 nvs-flash set cfms_ws location_id u32 <workstation_id>

Replace <workstation_id> with the numeric ID from Step 5.

Repeat Steps 1–6 for each workstation. Change CFMS_WS_TYPE in config.h to WS_TYPE_JUDGE for judge secretary units, then rebuild (idf.py build) before flashing each judge unit.


3

Flash Order & Summary

Flash trolleys first. Workstations actively scan for BLE trolley advertisements on boot. Having trolleys already advertising when workstations start makes the pairing verification step straightforward.

Device IDF Target IDF Minimum config.h change per unit Auto-ID source Rebuild between units?
ESP32-S3 Trolley esp32s3 5.2+ WiFi SSID/pass (same for all units) Chip ID No — one build for all trolleys
ESP32-P4 Workstation (Section) esp32p4 5.3+ CFMS_WS_TYPE = WS_TYPE_SECTION Ethernet MAC No — one build for all section units
ESP32-P4 Workstation (Judge) esp32p4 5.3+ CFMS_WS_TYPE = WS_TYPE_JUDGE Ethernet MAC Yes — rebuild after changing WS_TYPE

4

Post-Flash End-to-End Verification

After all devices are flashed and registered, run the integration simulation script against the live server. This confirms the full trolley lifecycle end-to-end — no hardware RFID reads required.

1

Run the simulation against the Raspberry Pi

cd /path/to/file_tracking_system_ESP32_RFID/cfms

python tests/simulate_trolley.py \
  --base-url http://192.168.1.100 \
  --username admin \
  --password admin1234
2

Expected output — all 14 steps pass

── Step 1 — Authenticate ────────────────────────────────────────────
  ✓ Authenticated  user=admin
── Step 2 — Register trolley device ─────────────────────────────────
  ✓ Trolley registered  TRL-SIM-XXXXXX
  ...
── Step 11 — Trigger 3-way comparison ───────────────────────────────
  ✓ Comparison triggered  id=1 status=mismatch
  ✓ Exactly 1 missing file detected  missing=[EPCXXXXXX]
── Step 14 — Trolley heartbeat ──────────────────────────────────────
  ✓ Heartbeat updates last_seen_at

── Simulation complete ───────────────────────────────────────────────

  Results: 20/20 checks passed
  ALL CHECKS PASSED — system integration confirmed

All checks passing confirms the server, database, API, BLE relay, offline sync, and OTA endpoints are all operational. The system is ready for physical RFID testing with real court files.