Skip to content

ESP3D Commands Module

The esp3d_commands module is the central command dispatch engine of the ESP3D firmware. It implements the ESP3DCommands class, which detects, parses, authenticates, routes, and responds to all [ESPxxx] control commands received from any transport channel.

Every communication path — Serial UART, Bluetooth SPP/BLE, USB Serial, TCP Socket, WebSocket — funnels incoming text through this module. When an [ESPxxx] command token is detected inside a message, the module takes ownership: it extracts parameters, enforces the caller’s authentication level, executes the corresponding handler method, then dispatches the response back to the originating client in either plain text or JSON format.

The module is also responsible for forwarding non-command messages to the CNC firmware via the active transport and for managing multi-part response streaming (head / core / tail message types).


┌─────────────────────────────────┐
│ Communication Transports │
│ Serial │ BT │ USB │ Socket │ WS │
└──────────────┬──────────────────┘
│ ESP3DMessage
▼
┌──────────────────────────────────┐
│ ESP3DCommands │
│ process() → is_esp_command() │
│ → execute_internal_command() │
└───┬──────────────────────────────┘
│
┌───────────┼──────────────────────────────┐
▼ ▼ ▼
ESP3DAuthentication ESP3DSettings ESP3DValues
(auth gate) (NVS read/write) (runtime events)
│
▼
┌──────────────────────────────────────────────────┐
│ Command Handlers │
│ System │ Network │ Files │ Display │ Auth │ … │
└──────────────────────────────────────────────────┘
│
▼ dispatch() / dispatchAnswer()
┌───────────────────┐
│ Target Transport │
└───────────────────┘

ItemPath
Class declarationmain/core/includes/esp3d_commands.h
Command implementationsmain/core/commands/esp*.cpp
Module tree groupCore_Platform_&_Infrastructure → esp3d_commands

The universal message container that flows through every transport and through this module.

struct ESP3DMessage {
uint8_t *data; // Raw payload bytes
size_t size; // Payload size
ESP3DClientType origin; // Sending client type
ESP3DClientType target; // Receiving client type
ESP3DAuthenticationLevel authentication_level; // guest / user / admin
ESP3DRequest request_id; // Response routing key
ESP3DMessageType type; // head | core | tail
ESP3DMessagePriority priority; // normal (back) | high (front)
};

ESP3DMessageType drives multi-part streaming: a single logical response is split into a head (opening segment), zero or more core segments (body entries), and a tail (closing segment with summary). This avoids large heap allocations for directory listings or settings dumps.

class ESP3DCommands {
public:
// Command detection and dispatch
bool is_esp_command(uint8_t *sbuf, size_t len);
void process(ESP3DMessage *msg);
void execute_internal_command(int cmd, int cmd_params_pos, ESP3DMessage *msg);
// Structured response helpers
bool dispatchAnswer(ESP3DMessage *msg, uint cmdid, bool json,
bool hasError, const char *answerMsg);
bool dispatchIdValue(bool json, const char *Id, const char *value,
ESP3DClientType target, ESP3DRequest requestId,
bool isFirst = false);
bool dispatchKeyValue(bool json, const char *key, const char *value,
ESP3DClientType target, ESP3DRequest requestId,
bool nested = false, bool isFirst = false);
bool dispatchSetting(bool json, const char *filter,
ESP3DSettingIndex index, const char *help,
const char **optionValues, const char **optionLabels,
uint32_t maxsize, uint32_t minsize, uint32_t minsize2,
uint8_t precision, const char *unit, bool needRestart,
ESP3DClientType target, ESP3DRequest requestId,
bool isFirst = false);
bool dispatchAuthenticationError(ESP3DMessage *msg, uint cmdid, bool json);
// Command channels without a session record (UART0 console, USB CDC
// device): pwd= handling and guest refusal per line (AUTHENTICATION builds)
bool checkCommandChannelLine(ESP3DAuthenticationLevel &level,
const uint8_t *msg, size_t size);
// FACTORY builds: point the next boot to the factory partition
bool rebootToFactory();
// Low-level dispatch overloads
bool dispatch(ESP3DMessage *msg);
bool dispatch(ESP3DMessage *msg, const char *sbuf);
bool dispatch(ESP3DMessage *msg, uint8_t *sbuf, size_t len);
bool dispatch(const char *sbuf, ESP3DClientType target,
ESP3DRequest requestId,
ESP3DMessageType type = ESP3DMessageType::head,
ESP3DClientType origin = ESP3DClientType::command,
ESP3DAuthenticationLevel authentication_level =
ESP3DAuthenticationLevel::guest);
// Parameter extraction
const char *get_param(ESP3DMessage *msg, uint start,
const char *label, bool *found = nullptr);
const char *get_clean_param(ESP3DMessage *msg, uint start);
bool hasTag(ESP3DMessage *msg, uint start, const char *label);
bool has_param(ESP3DMessage *msg, uint start);
// Output client management
ESP3DClientType getOutputClient(bool fromSettings = false);
void setOutputClient(ESP3DClientType output_client);
bool canSendData();
void flush();
};

Transport RX task
│
│ ESP3DMessage (raw bytes from wire)
▼
ESP3DCommands::process(msg)
│
├── is_esp_command() ─── No ──► forward to CNC transport (GCode path)
│
└── Yes: extract cmd number + params_pos
│
▼
execute_internal_command(cmd, params_pos, msg)
│
├── [ESP3D_AUTHENTICATION_FEATURE]
│ check msg->authentication_level
│ insufficient? ──► dispatchAuthenticationError()
│
└── route to ESPxxx(cmd_params_pos, msg)
│
├── get_param() / hasTag() / get_clean_param()
├── business logic (FS, settings, network…)
│
├── dispatch(msg, head_payload) [type=head]
├── dispatch(newMsg, entry_payload) [type=core] ×N
└── dispatch(newMsg, tail_payload) [type=tail]
│
▼
Target client TX queue

Every handler respects an optional json tag in the command parameters. Without it the output is human-readable text; with json it is structured JSON compatible with the WebUI.

Plain text example (ESP720 directory listing):

Directory on Flash : /
[config]
boot.txt 2024-01-15 10:23:01 512 B
Files: 1, Dirs: 1
Total: 1.00 MB, Used: 24.00 KB, Available: 1.00 MB

JSON example (ESP720 directory listing):

{
"cmd": "720",
"status": "ok",
"data": {
"path": "/",
"files": [
{"name": "config", "size": "-1"},
{"name": "boot.txt", "size": "512 B", "time": "2024-01-15 10:23:01"}
],
"total": "1.00 MB",
"used": "24.00 KB",
"occupation": "2"
}
}

All commands check msg->authentication_level before executing. The model has three levels:

LevelSymbolAccess
No authenticationguestRead-only public commands only
Normal useruserMost read + limited write commands
AdministratoradminAll commands including settings write

When access is denied, dispatchAuthenticationError() sends a structured error without revealing system state. The standard guard pattern used in every handler:

#if ESP3D_AUTHENTICATION_FEATURE
if (msg->authentication_level == ESP3DAuthenticationLevel::guest) {
dispatchAuthenticationError(msg, COMMAND_ID, json);
return;
}
#endif

How the level is assigned per transport: connection_management.md, authentication_lifecycle.md. On the command channels (telnet, /wsdata, USB CDC device, UART0 console) the level is checked on every line: a guest line is refused unless it is an ESP command, a wrong password demotes to guest. Telnet and /wsdata sessions expire after the STREAM= inactivity timeout of [ESP510] (0 = none, the default); the USB CDC device and UART0 console have no session record and keep their own level through checkCommandChannelLine(). DISABLE_SERIAL_AUTHENTICATION (ON by default) gives admin to every serial-class line and turns authentication off on the USB CDC device channel too (physical access trusted). [ESP500]LOGOUT closes the session. See esp3d_x_stream_authentication.md.


Commands are grouped by functional area. Each group is compiled in or out via CMake feature flags defined in CMakeLists.txt and converted to C preprocessor defines by cmake/features.cmake. Mutual exclusions are enforced in cmake/sanity_check.cmake.

Descriptions and guards below come from each handler’s header comment (main/core/commands/espNNN.cpp) and from the #if blocks around its case in ESP3DCommands::execute_internal_command(). Feature names drop the ESP3D_ prefix and _FEATURE suffix.

CommandGuardDescription
[ESP0]—Help: list the commands, or [ESP0]<command> for one
[ESP290]DISPLAYDelay / pause (ms)
[ESP400]—Get all ESP3D settings (JSON, admin)
[ESP401]—Set one setting: P=<position> T=<type> V=<value>
[ESP402]SD_CARD + UPDATEGet / set “check update at boot” (ON / OFF)
[ESP420]—Current status; debug adds diagnostics (heap, dbg:reset_reason, build variant…)
[ESP421]DISPLAYLVGL internal memory pool statistics (total / used / peak / free)
[ESP444]—RESET (settings), RESTART, FACTORY (boot to the factory app, FACTORY builds; otadata backup shared with the PiBot custom bootloader)
[ESP800]—Firmware / target info; also receives time=, version=, setup= from the WebUI
CommandGuardDescription
[ESP100]WIFI or BTGet / set STA SSID, or BT device name (WIFI= / BTSERIAL= / BTBLE=)
[ESP101]WIFI or BTSet STA password, or BT password (WIFI= / BTSERIAL= / BTBLE=)
[ESP102]WIFISTA IP mode (DHCP / STATIC)
[ESP103]WIFISTA static IP / mask / gateway / DNS
[ESP104]WIFISTA fallback mode at boot: BT, WIFI-SETUP (was CONFIG), OFF, STA
[ESP105] / [ESP106]WIFIAP SSID / AP password
[ESP107] / [ESP108]WIFIAP IP / AP channel
[ESP109]WIFISTA rejoin from the setup fallback (ON / OFF): the network task looks for the STA SSID every 2 minutes while no station uses the setup AP
[ESP110]—Radio mode at boot: BT, WIFI-SETUP (was CONFIG), STA, AP, OFF. Saved to NVS and applied asynchronously by the network task: ok means accepted, check with [ESP111] or the connection status screen
[ESP111]WIFICurrent IP (ALL for details)
[ESP112]—Hostname
[ESP114]—Radio state at boot (ON / OFF)
[ESP115]—Immediate network state (ON / OFF), applied asynchronously like [ESP110]
[ESP410]WIFI or BTScan: WiFi APs or BT devices (WIFI / BTSERIAL / BTBLE)
CommandGuardDescription
[ESP120] / [ESP121]HTTPHTTP state / port (HTTP= / HTTPS= ports)
[ESP160]HTTP + WS_SERVER_SERVICEWebSocket server state: ON / OFF / CLOSE
[ESP190]HTTP + WEBDAV_SERVICESWebDAV state
CommandGuardDescription
[ESP130] / [ESP131]SOCKET_SERVERSocket (telnet) server state / port
[ESP132] / [ESP133]SOCKET_CLIENT or WS_CLIENT_SERVICEClient target address (IP or hostname) / port
[ESP134]SOCKET_CLIENT or WS_CLIENT_SERVICECNC-over-IP client state (ON / OFF), symmetrical to [ESP130]
[ESP135]WS_CLIENT_SERVICEWebSocket client subprotocol (0 none, 1 webui-v3, 2 esp3d-v1, 3 arduino)
[ESP455]IP_CNC_CLIENT + MDNSDiscover CNC-over-IP services via mDNS (_telnet._tcp, _ws._tcp)

See connection_management.md for the transport lifecycle model.

CommandDescription
[ESP140]Sync / set / get time: NTP servers srv1..3, time zone, sync
CommandDescription
[ESP170]Set a camera parameter / list all values
[ESP171]Save a frame to a path / file name
[ESP171] path=<target_path> filename=<target_filename> pwd=<password>
  • Both parameters are optional. Defaults: path = today’s date (YYYY-MM-DD), filename = Unix timestamp + .jpg.
  • Dates are derived with localtime_r() — requires ESP3D_TIMESTAMP_FEATURE or a valid system clock.
  • Fails with "No camera initialized" if esp3d_camera.started() returns false.
  • Delegates the actual capture to esp3d_camera.handle_snap().
  • Minimum auth: user.
CommandGuardDescription
[ESP200]—SD card status; RELEASE, REFRESH
[ESP202]SD_INTERFACE_TYPE == 0 (SPI)SD speed factor (1 2 4 6 8 16 32)
CommandDescription
[ESP210]Sensor type, interval and current value
CommandGuardDescription
[ESP214]HAS_STATUS_BARWrite a text to the screen status bar
[ESP216]SNAPSHOTScreen snapshot
[ESP250]BUZZERPlay a sound: F=<frequency> D=<duration>
[ESP270]BRIGHTNESS_CONTROLBrightness (0–100)
[ESP280]—Orientation (0 / 90 / 180 / 270)
[ESP281]—Theme (1..THEME_COUNT)
[ESP460]—UI language; DUMP outputs a translation pack template (all labels)
CommandDescription
[ESP300]Run a Lua script asynchronously (admin)
[ESP301]Script status; action=PAUSE / RESUME / ABORT
CommandDescription
[ESP450]List the ESP3D devices found on the network
CommandDescription
[ESP500]Authentication status / log in (pwd=); [ESP500]LOGOUT closes the session
[ESP510]Session inactivity timeouts in minutes (0–255, 0 = no expiry): HTTP= (web session) and STREAM= (telnet, /wsdata)
[ESP550]Change the admin password
[ESP555]Change the user password
CommandDescription
[ESP600]Send a notification
[ESP610]Notification settings: type= NONE / PUSHOVER / EMAIL / IFTTT / WHATSAPP / HOMEASSISTANT, tokens, settings
CommandGuardDescription
[ESP700]—Read / stream / process a file (gcode host stream)
[ESP701]—Query and control the [ESP700] stream: action=PAUSE / RESUME / ABORT / ABORT_ALL
[ESP702]—Scripts run when the stream is paused / stopped / resumed
[ESP710]—Format the flash file system (FORMATFS)
[ESP720]—List the flash file system
[ESP730]—Action on the flash file system (<Action>=<path>)
[ESP740]SD_CARDList the SD file system
[ESP750]SD_CARDAction on the SD file system
[ESP780]—List the global file system
[ESP790]—Action on the global file system
[ESP720] <path> json=<no> pwd=<password>
  • Default path: / (root of the flash partition).
  • Requires flashFs.accessFS() — blocks if another task holds the mutex.
  • Two-pass readdir loop: directories emitted first, files second.
  • Reports: file count, directory count, total / used / free space.
  • Optional per-file timestamps when ESP3D_TIMESTAMP_FEATURE is enabled.
  • Response is streamed as head → N × core → tail to avoid single large allocations.
  • Space values formatted by esp3d_string::formatBytes().
[ESP740] <path> json=<no> pwd=<password>
  • Same two-pass streaming pattern as ESP720, using sd.accessFS() / sd.readdir().
  • Space reported as uint64_t (SD cards can exceed 4 GB).
  • Distinct error strings: "SD busy" when sd.getState() == ESP3DSdState::busy, "No SD" otherwise.
[ESP780] <path> json=<no> pwd=<password>
  • Operates on ESP3DGlobalFileSystem — the unified VFS that routes paths to Flash or SD depending on the mount prefix.
  • Uses path-aware locking: globalFs.accessFS(path) / globalFs.releaseFS(path).
  • Same output format as ESP720/ESP740; space query passes the path for per-mount resolution.
  • Error string on failure: "Filesystem not available".
CommandGuardDescription
[ESP900]SERIALSerial communication state: ENABLE / DISABLE
[ESP901]—Serial baud rate (UART0; UART0= explicit)
[ESP902]USB_SERIALUSB serial (OTG host) baud rate
[ESP935]USB_CDC_DEVICENative USB CDC device client: ENABLE / DISABLE (applies at next boot) / CLOSE (stops until boot or ENABLE)
[ESP950]BT, USB serial, socket…Default output client: SERIAL, USB-OTG (was USB, still accepted), USB-CDC, BTSERIAL, BTBLE, SOCKET, WSOCK, UARTEXT
CommandDescription
[ESP910]Sound state: ENABLE / DISABLE

ESP720, ESP740, and ESP780 share an identical internal pattern. This is the canonical flow using ESP720 as the example:

ESP720 called
│
▼
flashFs.accessFS() ─── fail ──► dispatchAnswer(error)
│
▼
flashFs.opendir(path) ── fail ──► dispatchAnswer("Cannot open")
│
▼
dispatch(msg, head)
"Directory on Flash : /\n" or JSON header with path
│
▼
flashFs.getSpaceInfo()
│
▼
readdir pass 1 — directories only
for each DT_DIR entry:
dispatch(newMsg, core)
"[dirname]\n" or JSON dir object {"name":"…","size":"-1"}
│
▼
flashFs.rewinddir()
│
▼
readdir pass 2 — files only
for each non-DT_DIR entry:
flashFs.stat() ← size + mtime
dispatch(newMsg, core)
"name date size\n" or JSON file object
│
▼
dispatch(newMsg, tail)
totals + space summary or JSON closing with total/used/occupation
│
▼
flashFs.closedir()
flashFs.releaseFS()

The module keeps _lastESP3DCmdOrigin (an ESP3DClientType) to track which transport sent the most recent [ESPxxx] command. This prevents a trailing newline arriving on one transport (e.g., Serial) from being swallowed because a different transport (e.g., BT) had just completed a command.

Each transport’s RX handler runs in a single dedicated task, so origin-keyed state eliminates cross-transport interleave. The enum is byte-sized, so reads and writes do not tear without an explicit lock.


Commands injected by the pendant UI (LVGL task) use ESP3DMessagePriority::high and are placed at the front of the TX queue via addFrontTxData(). Commands arriving from a remote terminal use normal priority and are appended to the back with addTxData().

See esp3d_message_priority_system.md for the full priority model.


DependencyUsed For
ESP3DClient / ESP3DMessage (esp3d_core.md)Base message queue management, copyMsgInfos(), newMsg()
ESP3DAuthenticationLevel enforcement, session tokens
ESP3DSettings (esp3d_core.md)NVS-backed settings read/write for ESP400/ESP401 and per-command settings
ESP3DValues (values.md)Publishing runtime value updates observable by the UI
ESP3DFlashInternal flash FS operations (ESP700–ESP730)
ESP3DSDSD card FS operations (ESP740, ESP750)
ESP3DGlobalFileSystemUnified VFS (ESP780, ESP790)
esp3d_cameraCamera snapshot (ESP171)
ESP3DSound (esp3d_sound, buzzer.md)Sound playback and enable state (ESP250, ESP910)
UIManager / LVGLStatus bar, theme, language (ESP214, ESP280, ESP281)
ESP3DmDNSService discovery (ESP450, ESP455)
ESP3DNotificationsServicePush notifications (ESP600, ESP610)
TimeServiceNTP sync, timestamps (ESP140, file listings)
EspLuaEngine (lua_engine.md)Lua script execution (ESP300, ESP301)
esp3d_logesp3d_log() / esp3d_log_e() throughout all handlers

C Preprocessor DefineCommands Enabled
ESP3D_WIFI_FEATUREESP100–109, ESP111, ESP410 (ESP110, ESP112, ESP114, ESP115 are always compiled)
ESP3D_BT_SERIAL_FEATURE or ESP3D_BT_BLE_FEATUREESP100, ESP101, ESP410, ESP950
ESP3D_HTTP_FEATUREESP120, ESP121, ESP160, ESP170, ESP171, ESP190
ESP3D_SOCKET_SERVER_FEATUREESP130, ESP131
ESP3D_SOCKET_CLIENT_FEATURE or ESP3D_WS_CLIENT_SERVICE_FEATUREESP132–134
ESP3D_WS_CLIENT_SERVICE_FEATUREESP135
ESP3D_TIMESTAMP_FEATUREESP140; file timestamps in ESP720/ESP740/ESP780
ESP3D_CAMERA_FEATUREESP170, ESP171
ESP3D_WEBDAV_SERVICES_FEATUREESP190
ESP3D_SD_CARD_FEATUREESP200, ESP202, ESP402, ESP740, ESP750
ESP3D_SENSOR_FEATUREESP210
ESP3D_DISPLAY_FEATUREESP214, ESP216, ESP250, ESP270, ESP280, ESP281, ESP290, ESP421, ESP460
ESP3D_HAS_STATUS_BARESP214
ESP3D_SNAPSHOT_FEATUREESP216
ESP3D_BUZZER_FEATUREESP250, ESP910
ESP3D_BRIGHTNESS_CONTROL_FEATUREESP270
ESP3D_AUTHENTICATION_FEATUREESP500, ESP510, ESP550, ESP555; auth guard in all handlers
ESP3D_NOTIFICATIONS_FEATUREESP600, ESP610
ESP3D_USB_SERIAL_FEATUREESP902, ESP950
ESP3D_USB_CDC_DEVICE_FEATUREESP935; USB-CDC value of ESP950
ESP3D_SERIAL_FEATUREESP900
ESP3D_UPDATE_FEATURE + ESP3D_SD_CARD_FEATUREESP402
ESP3D_MDNS_FEATUREESP450
ESP3D_IP_CNC_CLIENT_FEATURE + ESP3D_MDNS_FEATUREESP455
ESP3D_LUA_INTERPRETER_FEATUREESP300, ESP301
ESP3D_FACTORY_FEATUREFACTORY value of ESP444 (rebootToFactory())
SD_INTERFACE_TYPE == 0ESP202
ESP3D_UART_EXT_FEATUREESP950

Build constraint rules are enforced in cmake/sanity_check.cmake — for example, SOCKET_CLIENT_SERVICE and WEBUI_SERVER are mutually exclusive. See docs/features/feature_resource_matrix.md and docs/features/features.md for the full SKU × feature matrix.


DocumentContent
esp3d_core.mdESP3DClient, ESP3DMessage, ESP3DSettings, ESP3DX — the core platform types this module builds on
connection_management.mdTransport lifecycle, status codes, auth level assignment per transport
esp3d_message_priority_system.mdHigh-priority vs. normal command queuing details
gcode_host_architecture.mdHow non-ESP messages (GCode) are forwarded by the command processor
gcode_host_streaming_flow.mdState machine for GCode streaming that runs alongside command dispatch
shared_sd_mechanism_V2.0.mdSD access locking used by ESP740/ESP750
websockets_protocol.mdWebSocket command framing and the JSON protocol this module emits
authentication_lifecycle.mdFull authentication service lifecycle