-
Notifications
You must be signed in to change notification settings - Fork 0
State Machines
FlashForge printers use different internal state models depending on the firmware generation. This document maps these states to a unified client model for consistent application behavior across all printer families.
| Family | State Source | Format |
|---|---|---|
| Modern (5M / AD5X) | HTTP /detail endpoint |
JSON status field |
| Legacy (A3 / A4) | TCP M27 / M119 commands | Text response |
Applications should normalize printer status into these high-level states for consistent behavior:
| Unified State | Description | Client Action |
|---|---|---|
| IDLE | Ready to accept jobs | Enable job submission |
| PRINTING | Actively printing | Show progress, enable pause |
| PAUSED | Job suspended, heaters active | Enable resume/cancel |
| ERROR | Machine halted due to fault | Display error, require intervention |
| BUSY | Internal processing | Wait, poll for state change |
Source: HTTP POST /detail
Field: status (string)
| Internal Status |
/detail Value |
Unified State | Notes |
|---|---|---|---|
| Ready | ready |
IDLE | Printer idle and ready |
| Building |
building, working, printing
|
PRINTING | Main printing state |
| Busy | busy |
BUSY | Non-printing operation |
| Pause |
pause, paused
|
PAUSED | Job suspended |
| Error | error |
ERROR | Fault condition |
| Completed | completed |
IDLE | Job finished successfully |
| Canceling |
canceling, cancel
|
BUSY | Transient state during stop |
| Heating | heating |
PRINTING | Pre-print heating phase |
| Pausing | pausing |
PRINTING | Transition to paused |
| Calibration | calibrate_doing |
BUSY | Calibration in progress |
The canceling state is sometimes used transiently during a PAUSE sequence, not just during cancellation.
Recommendation: Treat canceling as BUSY and continue polling.
Method: Poll /detail every 1-2 seconds
POST /detail HTTP/1.1
Content-Type: application/json
{
"serialNumber": "SNADVA5MXXXXX",
"checkCode": "12345"
}Response:
{
"code": 0,
"message": "Success",
"detail": {
"status": "printing",
"printProgress": 0.45,
"printLayer": 50,
"printFileName": "Benchy.gcode"
}
}ready -> heating -> printing -> completed -> ready
ready -> heating -> printing -> pausing -> pause -> printing
ready -> heating -> printing -> canceling -> ready
ready -> busy -> ready
printing -> error
Source: TCP commands ~M27 or ~M119
Format: Text response
CMD M27 Received.
SD printing byte 0/100
Layer: 0/0
ok
The last line before ok contains the state information.
CMD M119 Received.
Endstop: X-max: 110 Y-max: 110 Z-min: 0
MachineStatus: READY
MoveMode: READY
Status: S:1 L:0 J:0 F:0
LED: 1
CurrentFile:
ok
Key Field: MachineStatus
| M27/M119 Response | Unified State | Notes |
|---|---|---|
| IDLE | IDLE | No job active |
| READY | IDLE | File selected, waiting for M24 |
| PRINTING | PRINTING | Job in progress |
| BUILDING | PRINTING | Alternative printing state |
| BUILDING_FROM_SD | PRINTING | SD card printing |
| PAUSED | PAUSED | Job suspended |
| ERROR | ERROR | Fault condition |
| BUSY | BUSY | Internal operation |
READY is a distinct state meaning "M23 (File Select) successful". It effectively means IDLE but prepared to print.
Recommendation: Treat READY as IDLE.
Cloud print states (BUILDING_FROM_SD) may leak into local queries on some firmware versions.
Recommendation: Treat any "BUILDING*" string as PRINTING.
Method: Poll ~M27 every 1-2 seconds via TCP port 8899
Send: ~M27
Response:
CMD M27 Received.
SD printing byte 45234/123456
Layer: 23/100
ok
Parse the last line of the response for the state string.
function normalizeState(status: string, isModern: boolean): UnifiedState {
const lowerStatus = status.toLowerCase();
// Modern firmware states
if (isModern) {
if (lowerStatus === 'ready' || lowerStatus === 'completed') return 'IDLE';
if (lowerStatus === 'printing' || lowerStatus === 'building' ||
lowerStatus === 'working' || lowerStatus === 'heating' ||
lowerStatus === 'pausing') return 'PRINTING';
if (lowerStatus === 'pause' || lowerStatus === 'paused') return 'PAUSED';
if (lowerStatus === 'error') return 'ERROR';
if (lowerStatus === 'busy' ||
lowerStatus === 'canceling' || lowerStatus === 'cancel' ||
lowerStatus === 'calibrate_doing') return 'BUSY';
}
// Legacy firmware states
if (lowerStatus === 'idle' || lowerStatus === 'ready') return 'IDLE';
if (lowerStatus === 'printing' || lowerStatus.startsWith('building')) return 'PRINTING';
if (lowerStatus === 'paused') return 'PAUSED';
if (lowerStatus === 'error') return 'ERROR';
if (lowerStatus === 'busy') return 'BUSY';
// Unknown state - treat as busy for safety
return 'BUSY';
} +-------+
| IDLE |
+-------+
|
| Start Print (M23/HTTP printGcode)
v
+-------+
| BUSY | (heating, file prep)
+-------+
|
| Print begins
v
+------------+
| PRINTING |<--------+
+------------+ |
| |
| Pause | Resume
v |
+---------+ |
| PAUSED |----------+
+---------+
|
| Cancel or Complete
v
+-------+
| IDLE |
+-------+
[Any State]
|
| Error occurs
v
+---------+
| ERROR |
+---------+
|
| User intervention / Clear
v
+-------+
| IDLE |
+-------+
| State | Poll Interval | Rationale |
|---|---|---|
| IDLE | 5-10 seconds | Lower frequency when idle |
| PRINTING | 1-2 seconds | Frequent progress updates |
| PAUSED | 2-3 seconds | Medium frequency |
| BUSY | 1-2 seconds | Detect state change quickly |
| ERROR | 10+ seconds | Wait for user intervention |
Track previous state to detect transitions:
interface PrinterStateTracker {
previousState: UnifiedState;
currentState: UnifiedState;
stateChangedAt: Date;
onStateChange: (old: UnifiedState, new: UnifiedState) => void;
}
function updateState(tracker: PrinterStateTracker, newState: UnifiedState) {
if (tracker.previousState !== newState) {
tracker.onStateChange(tracker.previousState, newState);
tracker.previousState = newState;
tracker.stateChangedAt = new Date();
}
tracker.currentState = newState;
}If an unrecognized state is encountered:
- Log the raw state value for debugging
- Treat as BUSY (safe default)
- Continue polling
- Update state mapping as needed
When building applications that support multiple printer families:
- Always normalize to the Unified Client Model
- Handle both modern and legacy state sources
- Use discovery protocol to identify printer family
- Select appropriate state query method based on family