Skip to content

Discovery Protocol

GhostTypes edited this page Feb 22, 2026 · 1 revision

Discovery Protocol

FlashForge printers use UDP-based discovery protocols to announce their presence on the network. A robust client implementation must handle both modern and legacy protocols to support the full printer fleet.

Protocol Overview

Family Protocol Type Ports Packet Size Key Identifier
Modern (5M / 5M Pro / AD5X) UDP Broadcast & Multicast 19000 (Multi), 48899 (Broad) 276+ bytes Serial Number (Offset 0x92)
Legacy (A3 / A4 Pro) UDP Multicast 8899 140 bytes Machine Name (Offset 0x00)

Multicast Group: 225.0.0.9

Modern Protocol (5M / 5M Pro / AD5X)

Discovery Mechanism

Modern printers listen on both multicast and broadcast addresses:

Type Address Port
Multicast 225.0.0.9 19000
Broadcast 255.255.255.255 48899

Probe: Send any UDP packet (payload ignored) to either address.

Response: Fixed-size binary packet (minimum 276 bytes).

Packet Structure

Total Size: 276 bytes minimum (Big Endian)

Offset Size Type Description
0x00 132 char[] Machine Name (null-terminated)
0x84 2 uint16 Command Port (TCP) - typically 8899
0x86 2 uint16 VID - typically 0x2B71
0x88 2 uint16 PID - 0x0024 or 0x0026
0x8A 2 uint16 Reserved
0x8C 2 uint16 Product Type (e.g., 0x5A02)
0x8E 2 uint16 HTTP/Event Port - typically 8898
0x90 2 uint16 Status (0=Ready, 1=Busy, 2=Error)
0x92 130 char[] Serial Number (null-terminated)

Detection Logic

Packets with length >= 196 bytes (0xC4) should be parsed as modern protocol.

Legacy Protocol (Adventurer 3 / 4 Pro)

Discovery Mechanism

Legacy printers listen on multicast only:

Type Address Port
Multicast 225.0.0.9 8899

Probe: Send any UDP packet to the multicast address.

Response: Fixed-size binary packet (140 bytes).

Packet Structure

Total Size: 140 bytes (Big Endian)

Offset Size Type Description
0x00 128 char[] Machine Name (null-terminated)
0x80 2 uint16 Status Code
0x82 2 uint16 TCP Port - typically 8899
0x84 2 uint16 Secondary Port - often 8
0x86 2 uint16 HTTP Port (Camera) - 19000 or 8080
0x88 4 bytes Unknown/Padding

Detection Logic

Packets with length == 140 bytes should be parsed as legacy protocol.

Important Limitation

The legacy packet does not contain the Serial Number. To retrieve the SN for unique identification, you must:

  1. Connect via TCP to port 8899
  2. Send ~M115
  3. Parse the Serial Number from the response

Unified Implementation Strategy

To auto-discover any FlashForge printer:

1. Create UDP Socket

Bind a UDP socket capable of receiving from multiple interfaces.

2. Send Probes

Send discovery probes to all known addresses:

225.0.0.9:19000   (Modern Multicast)
255.255.255.255:48899   (Modern Broadcast)
225.0.0.9:8899    (Legacy Multicast)

3. Parse Responses

Parse responses based on packet length:

Packet Length >= 196  --> Modern Protocol
Packet Length == 140  --> Legacy Protocol

4. Handle Legacy Printers

For legacy printers, initiate a TCP connection to retrieve the serial number.

Implementation Example

import dgram from 'dgram';

interface DiscoveredPrinter {
  family: 'Modern' | 'Legacy';
  name: string;
  serialNumber: string | null;
  ip: string;
  tcpPort: number;
  apiPort: number;
}

function parseDiscoveryPacket(packet: Buffer, rinfo: { address: string }): DiscoveredPrinter | null {
  if (packet.length >= 196) {
    // Modern Protocol
    const name = packet.toString('utf8', 0, 132).replace(/\0/g, '').trim();
    const serialNumber = packet.toString('utf8', 0x92, 0x92 + 130).replace(/\0/g, '').trim();
    const tcpPort = packet.readUInt16BE(0x84);
    const httpPort = packet.readUInt16BE(0x8E);

    return {
      family: 'Modern',
      name,
      serialNumber,
      ip: rinfo.address,
      tcpPort: tcpPort || 8899,
      apiPort: httpPort || 8898
    };
  } else if (packet.length === 140) {
    // Legacy Protocol
    const name = packet.toString('utf8', 0, 128).replace(/\0/g, '').trim();
    const tcpPort = packet.readUInt16BE(0x82);
    const cameraPort = packet.readUInt16BE(0x86);

    return {
      family: 'Legacy',
      name,
      serialNumber: null, // Requires TCP M115 query
      ip: rinfo.address,
      tcpPort: tcpPort || 8899,
      apiPort: cameraPort || 8080
    };
  }

  return null;
}

async function discoverPrinters(timeout: number = 5000): Promise<DiscoveredPrinter[]> {
  const socket = dgram.createSocket('udp4');
  const printers: Map<string, DiscoveredPrinter> = new Map();

  return new Promise((resolve) => {
    socket.on('message', (msg, rinfo) => {
      const printer = parseDiscoveryPacket(msg, rinfo);
      if (printer && !printers.has(printer.ip)) {
        printers.set(printer.ip, printer);
      }
    });

    socket.bind(() => {
      socket.setBroadcast(true);
      socket.addMembership('225.0.0.9');

      // Send probes
      const probe = Buffer.from([]);
      socket.send(probe, 19000, '225.0.0.9');
      socket.send(probe, 48899, '255.255.255.255');
      socket.send(probe, 8899, '225.0.0.9');

      // Wait for responses
      setTimeout(() => {
        socket.close();
        resolve(Array.from(printers.values()));
      }, timeout);
    });
  });
}

Discovery Response Summary

Field Modern (276+ bytes) Legacy (140 bytes)
Machine Name Yes (offset 0x00) Yes (offset 0x00)
Serial Number Yes (offset 0x92) No (requires TCP)
TCP Port Yes (offset 0x84) Yes (offset 0x82)
HTTP Port Yes (offset 0x8E) Camera only (offset 0x86)
Status Yes (offset 0x90) Yes (offset 0x80)
VID/PID Yes (offsets 0x86, 0x88) No
Product Type Yes (offset 0x8C) No

Troubleshooting

No Responses Received

  1. Verify the printer is powered on and connected to the network
  2. Check firewall settings allow UDP traffic on discovery ports
  3. Ensure the client is on the same network segment as the printer
  4. Try direct IP connection if discovery fails

Multiple Responses

A single printer may respond to multiple probe addresses. Use the IP address or serial number to deduplicate responses.

Legacy Printer Identification

For legacy printers, always fetch the serial number via TCP ~M115 before caching or displaying printer details. The machine name alone may not be unique across multiple printers.

Clone this wiki locally