Network configuration

The Duet controller is attached to Raspberry Pi by USB and by LAN to router. This gives great flexibility. The LAN settings can be done like described in Duet 2 Ethernet Web Control (DWC).

Sample configuration for LAN

;Networking Stuff

;Web Interface / IP-Adress
M552                   ; show status of network interface
M552 S0			       ; disable network interface
M552 S1 P0.0.0.0 R565  ; wait 10-30 seconds to obtain an IP address (Port 565)

M586                   ; show status of telnet interface
M586 P2 S1 T0          ; enable Telnet (SSH not implemented yet) (Port 23 if not changed)


(info) Telnet is highly insecure that's why we do not use it. But we tested it. Only one Telnet connection can be established at a time. If the console output "telnet: Unable to connect to remote host: Connection refused", then it is likely that Repetier Server is trying to establish a connection. This can be easily disabled in Repetier Server.

Connecting by telnet is easy:

telnet 23
Connected to
Escape character is '^]'.
RepRapFirmware Telnet interface

Please enter your password:
Log in successful!

(warning) Telnet should not be used due to its plaintext unsecure communication →

USB Serial Connection from bash

screen /dev/ttyUSB-DUET2ETHERNET 115200

#enter some GCode like M552 to test it
#unsvoled nasty thing: how to correctly set tty to do newlines? textual output is fragmented

IP address, MAC address and device name

Sometimes Freifunk DNS or other services fail. It's required to access the devices by their IP address then. By using Freifunk it's not so easy to get the current IP address of Duet 2 Ethernet board.

A lot of commands were tested

  • "batctl dc" on Freifunk Router does not always work. It sometimes returns no value for the known (fixed) device MAC address
  • "batctl ping <MAC|IP>" on Freifunk Router does not work because it does not return results for clients but for originators
  • "arp" on Freifunk Router does not return usable values (only in rare cases)
  • "arp" on Raspberry Pi works only for known IP addresses
  • "traceroute" on Freifunk Router does not work for MAC addresses but IP addresses. Without knowing the recent IP it's not useful
  • "arp-scan" on Raspberry Pi works best, but comsumes a lot of CPU compute power
  • Sending M-command to Duet and grab the result from Repetier Server console (remember that it's not possible to send M command to Duet's DWC API URL over network if it cannot be resolved. So the only proper way is to utilize the USB connection by Repetier Server!)

Freifunk network mode switch and automatic mode detection

Duet 2 is configured to get an IP address from Freifunk dynamically. This IP address can also set to be static. Because it's sometimes instable to work in ffcmesh domain we have to make the LAN clients available to each other without lagging. This can be done by setting the router into switch mode. To have a network communication and to make Duet Web Control accesible it's advised to reconfigure Duet by command M552. It was tested that Duet does not automatically obtain an IP address from Freifunk router in case the switch mode was activated. So we apply a static IP address manually. This was added as Macro in Repetier Server. As soon as Duet obtained it's IP DWC interface will be available again. For better handling a cronjob was created which runs a script which checks the current network state and adjusts the mode automatically:

vim /etc/cron.d/duet_network_mode
* * * * * root /opt/ > /dev/null 2>&1
vim /opt/
#IP_ADDR=$(/sbin/ip route | awk '/default/ { print $3 }')
IP_ADDR=$(ip route | grep default | grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
echo current hangdevice IP is $IP_ADDR
SCRIPT_FILE="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
CONCURRENT=$(ps -C ${SCRIPT_FILE} --no-headers | wc -l) #get the count of recently running script instances
if [[ $CONCURRENT != 0 ]]; then
        echo "Already running. Cannot execute start script multiple times simultaneously"
    exit 1
        source /opt/

        #echo "Pinging Duet 2"
        #if [[ $IP_ADDR == "169.254.XXX."* ]]; then #if local net (switch mode) ping must respond quickly
        #       ping -c 1 yourduet
        #else #if mesh mode the latency might get huge so we allow timeout of 5 seconds
        #       ping -c 1 -w 5 yourduet

        echo "Checking Duet state by curl within max 1 second"
        CURL_DATA=$(curl --silent --max-time 1 "yourduet/rr_connect?password=thePassword")

        if [[ -z ${CURL_DATA} ]]; then
                jq -r '.' <<< $(echo ${CURL_DATA})

        if [[ $ERROR_STATE != 0 ]]; then # Duet is not reachable or json output could not be parsable ("Warning: Binary output can mess up your terminal")
                # by checking the mode we can send the correct network GCode to Duet to fix the network state
                if [[ $IP_ADDR == "169.254.XXX."* ]]; then #check if IP begins with 169.254.XXX. This means switch mode
            echo "Setting Duet to switch mode"
                send_gcode "M552 S0 ;disable network"
                send_gcode "M553 P255.255.255.0 ;set netmask"
            send_gcode "M552 S1 P169.254.XXX.XXX ;set static IP"
                echo "" | mail -s "Setting Duet to switch mode"
                        #update etc hosts file accordingly
                        sed -i -e '7d' "/etc/hosts"
                        echo " 169.254.XXX.XXX yourduet.ffcmesh yourduet" >> "/etc/hosts" #define static IP in hosts
                        sleep 5 #wait some seconds until Duet is online
            echo "Setting Duet to mesh mode"
                send_gcode "M552 S0 ;disable network"
                send_gcode "M552 S1 P0.0.0.0"
            echo "" | mail -s "Setting Duet to mesh mode"
                        sleep 60 #wait a minute to let optain new public IP address
                        #sed -i -e '7d' "/etc/hosts" #clear old ip
                        ping -c 1 yourduet #trying another ping - this might still fail if /etc/hosts did not update in the meantime
                echo "Duet 2 was pinged successfully"
                exit 0 #everyting is fine. Nothing to do

Other scripts

#get MAC address -> M550 configures the device name yourduet
arp | grep yourduet.ffcmesh #might fail due to old cache on DNS server

#get IP address by ping / check state
ping yourduet.ffcmesh #might me not available if ffcmesh domain keeps older IP address for the device name

#Portscan on Duet - just to ensure some things against it's own configuration
apt install knocker
knocker --host $DUET_IP_ADDR 

#manually update DNS if Duet is not available on ffcmesh domain
#delete line number 7 from hosts file; then add new host entry with recent IP address. Ensure it's always on line 7
sed -i -e '7d' /etc/hosts && DUET_IP_ADDR=$(arp -a | grep "<DUET-MAC>" | awk -F ' ' '{print $2}') && DUET_IP_ADDR=${DUET_IP_ADDR:1:-1} && echo $DUET_IP_ADDR "yourduet.ffcmesh yourduet" >> /etc/hosts

#flush DNS cache
ip -s -s neigh flush all
arp -n

Duet Web Control forwarding and security

vim ports.conf
# If you just change the port or add more ports here, you will likely also
# have to change the VirtualHost statement in
# /etc/apache2/sites-enabled/000-default.conf

<IfModule ssl_module>
    Listen 81 # Duet Web Control

<IfModule mod_gnutls.c>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Apache virtual host

See mkcert & Go for SSL cert generation

vim /etc/apache2/sites-available/dwc.conf
<VirtualHost *:81>
      ServerName localhost
      SSLEngine on
      SSLCertificateFile /etc/ssl/certs/trikarus.pem
      SSLCertificateKeyFile /etc/ssl/private/trikarus-key.pem
    <Location "/">
        AuthType Basic
        AuthName "Authentication Required"
        AuthUserFile "/etc/apache2/htusers"
        Require valid-user
        ProxyPass http://yourduet.ffcmesh/
        ProxyPassReverse http://yourduet.ffcmesh/
      ErrorLog ${APACHE_LOG_DIR}/error-dwc.log
      CustomLog ${APACHE_LOG_DIR}/access-dwc.log combined
#generate user
htpasswd -B -c /etc/apache2/htusers THEUSERNAME

(info) The htuser is shared with Repetier Server. See Repetier Server

Strange looking values

This is normal → "G92 E0 resets the virtual extruder position. This command is generated by slicers frequently when they use absolute extrusion, to avoid the build up of rounding error. However, the virtual extruder position is not useful to an end user, so DWC shows the total net extrusion instead, separately for each extruder. If you really want to check the virtual extruder position, use M114."

Troubleshooting "Error: Bad command"

This message sometimes happens permanently on every entered command after one command before was typed wrong. There is no known solution yet.

Security and access by external tools

Duet can be secured by password to omit unauthorized access. This prevents unwanted re-configuring by person from the local network.

# authorize first
curl -u 'someUser:somePassword' --insecure https://hangdevice:81/rr_connect?password=thePassword

# response from above should be:

# do some things (examples)
curl -u 'user:password' --insecure http://yourduet.local/rr_gcode?gcode=M114
curl -u 'user:password' --insecure http://yourduet.local/rr_download?name=0:/sys/config.g
curl -u 'user:password' --insecure http://yourduet.local/rr_status?type=3
curl -u 'user:password' --insecure http://yourduet.local/rr_filelist?dir=sys


"The connection between the browser and your machine has been interrupted."

Sometimes DWC can not be accessed because "Reason: Unknown (SyntaxError: JSON.parse: unterminated fractional number at line 1 column 125 of the JSON data)" occcures. This can be fixed by sending "G92 X0 Y0 Z0" by Repetier Server console or by DWC JSON API (required to be authenticated previously)

curl -k yourduet.ffcmesh/rr_gcode?gcode=G92+X0+Y0+Z0

(info) You can check unparsable JSON at

"You are about to log in to the site "$" with the username "$", but the website does not require authentication. This may be an attempt to trick you

The following message might appear in Firefox


  1. Go to "about:config"
  2. Enter "network.http.phishy-userpass-length" and create a new value with "Number". Put in "255"

  3. Restart Firefox
Duet board does not respond


  • Board is not available on LAN and does not update dynamic IP address, or
  • Repetier does not show Duet fully available (if correctly available the symbol is green but in this case it is red "broken" or orange "trying to connect")


  • turn off PSU and turn off USB - we need to perform hard reset

    #we use the aliases of root user
    #wait some time

Communication to the firmware

Since RepRapFirmware can only process one HTTP request at a time (excluding rr_fileinfo and rr_upload on certain platforms), DuetWebControl should attempt to avoid parallel requests. In general, the communication between the web interface and RepRapFirmware looks like this:

  1. Establish a connection (via rr_connect)
  2. Send an extended status request (rr_status?type=2) and start status update loop
  3. Load macros (rr_filelist?dir=/macros)
  4. (User switches to “G-Code Files” tab)
  5. Stop automatic status updates
  6. Load G-code filelist (rr_filelist?dir=/gcodes)
  7. File info about each file is requested (unless cached values are available)
  8. Start automatic status requests again
  9. (User does something else)
  10. DWC disconnects (via rr_disconnect)

Note the interrupt of live updates while multiple long requests are processed. DWC implements two particular functions (stopUpdates and startUpdates) which can - and should - be used to stop status requests while long-running HTTP requests are being executed. The update loop is stopped when file uploads are started, too, however it is not required to interrupt the update loop while short requests (e.g. rr_gcode) are sent.

Some requests may send or expect date and time values. These values are represented by the format “YYYY-MM-DDTHH:MM:SS” similar to the ISO-8601 format.

List of HTTP requests

All HTTP requests, except for rr_upload, are simple GET requests that return JSON objects, which makes it easy to deal with them using JavaScript code. Here the list of all currently used requests:


Create an initial connection between DWC and RRF. - On success, the firmware sends out a response like: {“err”:0,“sessionTimeout”:[time in ms],“boardType”:“[board type]”} This way DWC can adjust the AJAX timeout value and set board-specific options. The “time” value should represent the client’s date and time to set the on-board RTC if necessary. - If anything goes wrong, the firmware only responds with an {“err”:[code]} object. If code is 1, then the specified password is wrong. If it is 2, then the firmware cannot allocate enough resources to accomodate another session.


Delete an existing HTTP session. This should be used to log off manually, however sessions are usually purged automatically if no communication takes place within the time specified in “sessionTimeout” above.


Request a status response from the firmware which usually includes all the machine parameters that are expected to change from time to time. This makes it possible to display live values like XYZ position and heater temperatures. This type of request is usually sent to the firmware in rather short intervals (250ms by default). At this time there are three different supported status request types, which may be polled in different intervals:

  • Type 1: Regular status request. The response for this is usually rather compact and only includes values that are expected to change quickly. The following types 2 and 3 include those values under any circumstances to keep the web interface up-to-date.
  • Type 2: Extended status request. This type of request is polled right after a connection has been established. This response provides information about the tool mapping and values that can change.
  • Type 3: Print status request. Unlike type 2, this type of request is always polled when a file print is in progress. It provides print time estimations and other print-related information which can be shown on the print status page.


Send a G-code to the firmware. Since RepRapFirmware is generally only controlled by G-codes, this provides an interface to transmit codes from the web interface. This request returns the amount of currently available buffer space for incoming G-codes, however DWC does not actively use this response yet.


Upload a file to path XXX with the last modified date and time using an HTTP POST request. This is the only supported POST request in RepRapFirmware, however be aware that the POST request is no standard HTTP request. To make this work in the firmware, the payload (ie. file) has to be send in one chunk right after the HTTP header without any encapsulation. This mechanism is used to speed up transfers. Once complete, the firmware responds with {“err”:[code]}. If everything goes well, the error code will be 0 and 1 on failure.


Download a specified file from the SD card.


Delete a file from the SD card. The firmware responds again with {"err":[code]} and the error code will be 0 on success.


Request a file list from the directory XXX. Unlike rr_files, which was used in past web interface versions, this request returns a JSON object which encapsulates each file in the following format:


Type can be either ’d’ if it is a directory or ‘f’ if it is a regular file. The size is reported in bytes.

If an error occurs, the firmware will respond with {"err":[code]}. If the code is 1, the directory doesn’t exist. If it is 2, the requested volume is not mounted.


Parse G-code file information from file XXX or return file information about the file being printed if the key is omitted. RepRapFirmware implements a dedicate function to retrieve information from a G-code file (see also M36) which may be used on the G-code file list and on the print status page.


Move a file on the SD card from XXX to YYY. Returns {“err”:[code]} after completion where code will be 0 if the request was successful.


Create a new directory. Returns {“err”:[code]} with code being 0 if the directory could be created.


Get the configuration response. Some printer information do not need to be requested for regular usag but to obtain machine properties and firmware versions this request can be used.

Upload by PrusaSlicer

For this job two syntax variants can be used

  1. Enter in URL field and leave password field empty
  2. Enter and enter your Duet password in "password" field
  • No labels
Write a comment…