This page describes the underlying protocols used by the Python client. For recommended public entry points, see client.md. For cross-language expectations, see parity.md.
FlashForge printers use a hybrid communication strategy with TCP, HTTP, and UDP protocols. Understanding these protocols is helpful for debugging and advanced usage.
The TCP protocol provides low-level control and real-time status information.
- Port:
8899 - Format: ASCII G-code commands terminated by
\n - Response: Text-based, typically ending with
ok
| Command | Description |
|---|---|
~M119 |
Get endstop status and machine state |
~M105 |
Get temperature readings |
M115 |
Get machine information |
~M27 |
Get print progress |
~M661 |
List files on printer |
~M662 <filename> |
Get thumbnail for file |
~G28 |
Home all axes |
~M104 S<temp> |
Set extruder temperature |
~M140 S<temp> |
Set bed temperature |
~M146 r255 g255 b255 F0 |
Turn LEDs on |
~M146 r0 g0 b0 F0 |
Turn LEDs off |
The TCP client maintains a persistent connection with automatic keep-alive:
- Interval: 5-10 seconds (adjusts based on error count)
- Method: Periodic status command (
M27) - Purpose: Prevents printer from timing out the session
- Management: Automatic (started by
init_control(), stopped bydispose())
Commands are prefixed with ~ and terminated with \n:
~M119\n
Responses are multi-line text ending with ok:
Endstop X-max:0 Y-max:0 Z-min:1
MachineStatus: READY
MoveMode: READY
Status S:0 L:0 J:0 F:0
LED: 1
CurrentFile:
ok
The low-level TCP client is accessible via client.tcp_client:
# Send raw command
response = await client.tcp_client.send_command_async("~M119")
# Use parser methods
printer_info = await client.tcp_client.get_printer_info()
temp_info = await client.tcp_client.get_temp_info()
endstop_status = await client.tcp_client.get_endstop_status()The HTTP API provides high-level operations and structured JSON responses.
- Port:
8898 - Protocol: HTTP/1.1
- Format: JSON payloads
- Endpoints: REST-like endpoints
| Endpoint | Method | Description |
|---|---|---|
/command |
POST | Send control commands |
/product |
POST | Get product/control states |
/info |
POST | Get detailed machine info |
/gcodeList |
POST | Get recent file list |
/gcodeThumb |
POST | Get file thumbnail |
/upload |
POST | Upload G-code file |
Commands are sent via POST with JSON payloads:
{
"serialNumber": "SN123456",
"checkCode": "CHECK_CODE",
"payload": {
"cmd": "control",
"args": {
"command": "home"
}
}
}Responses include a status code and data:
{
"code": 0,
"msg": "success",
"data": {
"status": "ready",
"temperature": 25.0
}
}Simple authentication using serial number and check code:
- Serial Number: Required for all HTTP requests
- Check Code: Required for modern LAN-mode HTTP control
- Purpose: Identifies the printer and authorizes commands
The HTTP layer is abstracted by control modules:
# High-level methods use HTTP internally
await client.control.set_led_on()
await client.job_control.pause_print_job()
await client.temp_control.set_bed_temp(60)
# File operations
files = await client.files.get_recent_file_list()
thumbnail = await client.files.get_gcode_thumbnail("model.gcode")Discovery uses UDP broadcasting to find printers on the local network.
- Broadcast Port:
48899 - Listen Port:
18007(client listens here for responses) - Protocol: UDP broadcast
- Packet: 20-byte "magic" packet
The discovery packet starts with www.usr and contains specific bytes:
Bytes: 77 77 77 2e 75 73 72 ... (20 bytes total)
Printers respond with their information:
Name: Adventurer 5M Pro
Serial: SN123456
IP: 192.168.1.100
from flashforge import PrinterDiscovery, DiscoveryOptions
discovery = PrinterDiscovery()
printers = await discovery.discover(
DiscoveryOptions(
timeout=3000,
idle_timeout=1000,
max_retries=3,
)
)FlashForgePrinterDiscovery is still exported as a compatibility wrapper for older Python callers, but PrinterDiscovery is the preferred modern API.
- Network Scope: Only finds printers on same subnet
- Firewall: May be blocked by firewall rules
- VLAN: Won't work across VLANs
- Solution: Use manual connection with IP address if discovery fails
The FlashForgeClient automatically selects the appropriate protocol:
| Operation | Protocol | Reason |
|---|---|---|
| Get temperatures | TCP | Real-time, low latency |
| Get machine info | HTTP | Structured JSON data |
| Control LEDs | HTTP or TCP | HTTP preferred, TCP fallback available |
| Home axes | TCP | Direct G-code control |
| Upload file | HTTP | File transfer |
| Get file list | TCP | Legacy compatibility |
| Get recent files | HTTP | Metadata available |
The client uses both protocols simultaneously:
FlashForgeClient
├── HTTP Layer (port 8898)
│ ├── Control commands
│ ├── File operations
│ └── Status queries
│
└── TCP Layer (port 8899)
├── G-code commands
├── Real-time status
└── Keep-alive
- HTTP: Send product command to get control states
- TCP: Connect and send login command
- TCP: Get printer info
- TCP: Start keep-alive mechanism
Both protocols can be used concurrently:
# HTTP and TCP operations can run in parallel
temps, status = await asyncio.gather(
client.get_temperatures(), # TCP
client.get_printer_status() # HTTP
)import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('flashforge')
logger.setLevel(logging.DEBUG)# Send raw TCP command
response = await client.tcp_client.send_command_async("~M119")
print(f"Response: {response}")The HTTP client logs all requests when debug logging is enabled.
| Protocol | Port | Purpose |
|---|---|---|
| TCP | 8899 | G-code commands, real-time control |
| HTTP | 8898 | REST API, file operations |
| UDP | 48899 | Discovery broadcast |
| UDP | 18007 | Discovery response listening |
- API Reference - Complete API documentation
- Getting Started - Quick start guide
- Advanced Topics - Connection management details