back to index

Anycubic Photon 3d-printer network control


Why
How
Usage
      Examples of use
Downloads
Configuration
Supervision via MQTT
      mqtt_PhotonMonitor.sh
      /etc/crontab line
Protocol
      G-codes
            Movements
            See also:
      Printer autodetection
      Printer status
      Files
            List files
            Remove file
            Send/receive file protocol
            send small file (single packet)
            send larger file (multiple packets)
            receive small file (single packet)
            receive larger file (multiple packets)
            read nonexistent file
      Sample config file for Anycubic Photon
Todo
      Suggested printer modifications

Why

Because putzing with the USB disk is annoying. Because the connector tends to wear.


How

The printer has an Ethernet interface on its controller board. In older versions of firmware it is unused. More modern (4.2.19 for certain) allow setting the IP address (fixed one manually from screen, or more comfortably via DHCP) and communicate over a simple UDP-based protocol.

The communication is based on G-code. UDP packet is sent to printer, response is sent back.

The printer listens on UDP port 3000.

There is no password or other security. Use a port-based VLAN and an authorization proxy if this is a concern.

The G-code was partially observed partially read partially reverse-engineered (especially the file upload/download state machine) from Universal Photon Network Controller; that one did not work well on a Windows laptop, the connection kept crashing, the GUI couldn't be used in scripts nor in a terminal. (GUI? Phooey!)

A simple Python script was written to facilitate the communication.

It works for Anycubic Photon printer, CBD motherboard v1.4.1, firmware version V4.2.19.3_LCD.

It should work for many CBD-Tech based SLA 3D printers (Anycubic Photon, ChiTu printers...).[ref] If the machine autodetects, it's likely it will respond to the rest of the commands.

For a suite of utilities to control FDM printers via OctoPrint see sw_8control.


Usage

The general command syntax is

 photon.py [connection parameters] <command> [filename] [parameters]

The connection parameters are:

Only one can be specified.

The commands are:

Some commands have several common synonyms so the operator doesn't have to precisely remember the correct one.

The other parameters are:

(Connection parameter is checked for and parsed first. Then command and its parameter is checked. The rest of the line is then parsed by argparse.)

Printer's response to received and processed command is ok N:0, response to received but unrecognize command is ok.

Examples of use

list printers on the network

 photon.py detect
send file printout.photon
 photon.py put printout.photon
send file printout.photon, with in-printer name obj.photon
 photon.py put printout.photon -r obj.photon
delete remote file obj.photon
 photon.py rm obj.photon
get list of files on the printer
 photon.py ls
get list of files on the printer, autodetect it on the network
 photon.py -a ls
get list of files on the printer named "photon2"
 photon.py -n photon2 ls

set photon commands for two different printers:

 alias photon1="photon.py -n photon_no_1"
 alias photon2="photon.py -n photon_no_2"
then list files on printer 1, check status on printer 2
 photon1 ls
 photon2 stat


Downloads


Configuration

By default, the printer is accessed via its hardcoded network name, photon1.

The IP address can be configured on unixes in /etc/hosts file, or its windows equivalent. It can also be provided by local DNS or other means.


Supervision via MQTT

For various dashboards, data feed via MQTT is common.

The printer does not have facilities for reporting its status on its own, but can be periodically polled. Practical results are achieved with running the polling script from cron, once per minute or two.

Printing:

photon.py stat
SD printing byte 7675284/9740462
Percent: 78.8

Not printing:

photon.py stat
Error:It's not printing now!

mqtt_PhotonMonitor.sh

#!/bin/bash
TOPIC=shop/photon/progress STATE=`photon.py stat|tail -n 1` if [ "${STATE:0:8}" == "Percent:" ]; then mosquitto_pub -m ${STATE:10} -t $TOPIC else mosquitto_pub -m "-" -t $TOPIC fi

/etc/crontab line

 */1 * * * * user /script/location/mqtt_PhotonMonitor.sh

Protocol

The machine's board is based on the Chitu-class motherboard. These boards are common in 3d printers both FDM and SLA.[ref]

G-codes

<filename> refers to relative path in currently selected directory, :<filename> refers to absolute path

Movements

The printer head can be moved directly. The G0/G1, G28, G90/G91 codes are supported.

During printing, the printer is in relative mode (G91). This leads some to believe that absolute/relative mode is not supported. It is at least in 4.2.19.

The G0/G1 requires both the Z and F parameter. Without it the head doesn't want to move. The F-speed is clamped by the M8013 Ixx max speed limit. The limit is in mm/s (default value can be 5 but steps aren't being lost up to 10), the speed is in mm/min; the corresponding limit speed to I10 is therefore F600. Higher values will be treated like the limit value.

Repeated reciprociated movements of the printer head can be used for stirring the resin - many resins contain fillers or pigments which tend to settle on the bottom of the vat. The buildplate moves back and forth in the resin bath, causing turbulent flow that stirs the sediment back into suspension.

G28 Z0 will move the head to the bottom endstop.

See also:

Printer autodetection

BROADCAST: b'M99999'
RECV: b'ok MAC:00:e0:4c:35:02:15 IP:192.168.1.231 VER:V1.4.1 ID:15,00,42,00,25,55,41,28 NAME:ZWLF\r\n'

Printer status

send M27 to printer, receive text string with printer status and position in current file as response

SEND: b'M27'
RECV: b"Error:It's not printing now!\r\n"

send M114 to printer, receive current head position (only Z: is relevant)

SEND: b'M114'
RECV: b'ok C: X:0.400050 Y:0.000000 Z:151.899994 E:0.000000\r\n'

Files

List files

send M20, receive several UDP packets in sequence

SEND: b'M20'
RECV: b'Begin file list\r\n'
RECV: b'<filename> <filesize>\r\n'
RECV: b'_cookiecut.photon 6429960\r\n'
RECV: <rest of files...>
RECV: b'End file list\r\n'
RECV: b'ok L:<num of files>\r\n'

Remove file

SEND: b'M30 nonexistent.filename'
RECV: b'Delete failed :nonexistent.filename\r\n'
RECV: b'ok N:0\r\n'

Send/receive file protocol

G-code commands:

File packets contain payload and appended 6 bytes of a "tailer". (Like a header but on the tail.)

The tailer has format [O3][O2][O1][O0][XX][MM] , where

The software always sends M22 before starting the file operation, in order to close eventual hanging-open file (e.g. if an earlier transaction was interrupted).

Communication is described in python syntax for byte arrays. Except the tailer structure where the binary bytes are written as [hex] numbers.

send small file (single packet)

SEND: b'M28 <filename>'
RECV: b'ok N:0\r\n'
SEND: b'<binary data packet><tailer:[00][00][00][00][XX][83]>'
RECV: b'ok\r\n'
SEND: b'M29'
RECV: b'Done saving file!\r\n// <filename>\r\n'
RECV: b'ok N:0\r\n'

send larger file (multiple packets)

send send-file request with filename

SEND: b'M28 <filename>'
RECV: b'ok N:0\r\n'
send first packet, offset 0 (0x0000-0000)
SEND: b'<binary data packet 1><tailer:[00][00][00][00][XX][83]>'
RECV: b'ok\r\n'
send second packet, offset 1280 (0x0000-0500)
SEND: b'<binary data packet 2><tailer:[00][05][00][00][XX][83]>'
RECV: b'ok\r\n'
send third packet, offset 2560 (0x0000-0A00)
SEND: b'<binary data packet 3><tailer:[00][0a][00][00][XX][83]>'
RECV: b'ok\r\n'
send third packet, offset 3840 (0x0000-0F00)
SEND: b'<binary data packet 4><tailer:[00][0f][00][00][XX][83]>'
RECV: b'ok\r\n'
we sent it all, so close file
SEND: b'M29'
RECV: b'Done saving file!\r\n// <filename>\r\n'
RECV: b'ok N:0\r\n'

receive small file (single packet)

SEND: b"M6032 \'<filename>\'"
RECV: b'ok L:825\r\n'
SEND: b'M3000'
RECV: b'<binary data packet><tailer:[00][00][00][00][XX][83]>'
SEND: b'M22'
RECV: b'ok N:0\r\n'

receive larger file (multiple packets)

send receive-file request in filename in quotes

SEND: b"M6032 \'<filename>\'"
receive that file exists, and its length
RECV: b'ok L:4239\r\n'
send chunk request
SEND: b'M3000'
receive binary chunk at offset 0 (0x0000-0000)
RECV: b'<binary data packet 1><tailer:[00][00][00][00][XX][83]>'
send chunk request
SEND: b'M3000'
...and error happens...
<timeout>
...so we send retry request, with explicit offset (1280 bytes)
SEND: b'M3001 I1280'
...and retry works, receive binary chunk at offset 1280 (0x0000-0500)
RECV: b'<binary data packet 2><tailer:[00][05][00][00][XX][83]>'
send chunk request
SEND: b'M3000'
receive binary chunk at offset 2560 (0x0000-0A00)
RECV: b'<binary data packet 3><tailer:[00][0a][00][00][XX][83]>'
send chunk request
SEND: b'M3000'
receive binary chunk at offset 3840 (0x0000-0F00)
RECV: b'<binary data packet 4><tailer:[00][0f][00][00][XX][83]>'
we received enough bytes to match the length from earlier, so close file
SEND: b'M22'
RECV: b'ok N:0\r\n'

read nonexistent file

SEND: b"M6032 \'<filename>\'"
RECV: b"Error,Cann't open file:<filename>\r\n"

Sample config file for Anycubic Photon

obtained by M8512 'cfg.g', then machine-translated (the original comments are in Chinese) and reformatted by adding spaces to align comments

;; Version: V4.2.19.3_LCD.0 /1440x2560 /F2.9';' followed by a comment
M8513;             Clear the previous configuration parameters, restore the parameters to the factory settings, and reconfigure the parameters
M8004 I-1;         Z motor direction (-1=ccw)
M8005 Z0;          Z axis 0: extrusion head movement 1: platform movement
M8006 I30;         starting speed (speed limit)
M8007 I15;         track bending speed (jerk)
M8008 I900;        acceleration
M8010 S0.000625;   z mm per step
M8013 I5;          Z maximum speed
M8015 I3;          Z first zero speed
M8016 I3;          Z second zero speed
M8015 P2.000000;   Z slow rising speed
M8016 P3.000000;   Z rapid rise and fall speed
M8016 D10;         Number of milliseconds to wait after Z rises
M8030 T-1;         Fan 2 control, 1: follow exposure 0: normally closed -1: normally open
M8030 S4;          LED control, 1: normally open 0: normally closed 2: follow the model to print
M8070 S3.000000;   the moving distance of each Z slow ascent
M8071 X1440 Y2560; projection resolution
M8070 T0;          projector warm-up time
M8070 Z6.000000;   the distance moved each time Z rises
M8070 I9600;       projector baud rate
M8026 I155.000000; Z maximum stroke
M8029 I0;          XY limit 0: minimum limit 1: maximum limit 2: bilateral limit
M8029 T0;          limit wiring 0: limit normally open 1: limit normally closed
M8029 S0;          Z limit type 0: minimum limit 1: maximum limit
M8029 C0;          XYZ moves after homing 0: return to zero (0,0,0) 1: stop at the limit position
M8030 C0;          XYZ moves after homing 0: Return to zero (0,0,0) 1: Stop at the limit position
M8030 I-2;         fan self-starting temperature
M8034 I1;          folder support or not
M8083 I1;          whether to enable auto leveling
M8084 Z1.300000;   Delta Z offset, 0: Offset is prohibited, the stroke is determined by setting Z to zero, non-zero, the stroke is triggered by the leveling trigger position + offset value
M8085 I5000;       duration of boot logo, minimum 100ms, maximum 6000ms
M8085 T0;          screen saver standby wait time, in seconds
M8087 I0 T0;       I: time from direction valid to pulse valid (ns), T: shortest pulse hold time (ns). If there is no external drive, please set all to 0
M9003 "ZWLF"
M8500;             save configuration

M8084 is set manually by leveling, remove if it's too off to avoid collision of buildplate to display.


Todo

Also, for FDM printers with the same controller board kind:

Suggested printer modifications


If you have any comments or questions about the topic, please let me know here:
Your name:
Your email:
Spambait
Leave this empty!
Only spambots enter stuff here.
Feedback: