Duet 2 and Duet Web Control

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)

Telnet

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.

grafik.png grafik.png

Connecting by telnet is easy:

telnet duetboard.fritz.box 23
Trying 192.168.1.67...
Connected to due.fritz.box.
Escape character is '^]'.
RepRapFirmware Telnet interface

Please enter your password:
> ULTRAHARDTOCRACKPASSWORD
Log in successful!

Telnet should not be used due to its plaintext unsecure communication → https://netsyshorizon.blogspot.com/2015/03/capture-sniffing-telnet-password-capturing.html

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

#get regular temperature info from Duet by simple cat:
cat /dev/ttyUSB-DUET2ETHERNET
ok T:24.1 /0.0 T0:24.1 /0.0

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

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
SHELL=/bin/bash
PATH=/usr/lib/sysstat:/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * root /opt/duet_network_mode.sh > /dev/null 2>&1
vim /opt/duet_network_mode.sh
#!/bin/bash
#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
else
    source /opt/repetier-conf.sh

    #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
    #fi

    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
        ERROR_STATE=1
    else
        jq -r '.' <<< $(echo ${CURL_DATA})
        ERROR_STATE=$?
    fi

    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" some_mail@domain.de
            #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
        else
            echo "Setting Duet to mesh mode. Please wait 60 seconds"
            send_gcode "M552 S0 ;disable network"
            send_gcode "M552 S1 P0.0.0.0"
            echo "" | mail -s "Setting Duet to mesh mode" some_mail@domain.de
            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
        fi
    else
        echo "Duet 2 was pinged successfully"
        exit 0 #everyting is fine. Nothing to do
    fi
fi

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>

<IfModule mod_gnutls.c>
</IfModule>

# 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
      ServerAdmin some_mail@domain.de
      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/
      </Location>
      ErrorLog ${APACHE_LOG_DIR}/error-dwc.log
      CustomLog ${APACHE_LOG_DIR}/access-dwc.log combined
</VirtualHost>
#generate user
htpasswd -B -c /etc/apache2/htusers THEUSERNAME

The htuser is shared with Repetier Server. See Repetier Server

 

grafik.png grafik.png grafik.png

Strange looking values

grafik.png

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.

grafik.png

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.

grafik.png

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

# response from above should be:
"{"err":0,"sessionTimeout":8000,"boardType":"duetethernet102"}"

# 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

Troubleshooting

"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

You can check unparsable JSON at https://jsonlint.com.

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

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

grafik.png

Solution:

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

Description

Solution

#we use the aliases of root user
psu_off
usb_off
#wait some time
psu_on
usb_on

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:

rr_connect?password=XXX&time=YYY

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.

rr_disconnect

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.

rr_status?type=XXX

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:

rr_code?gcode=XXX

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.

rr_upload?name=XXX&time=YYY

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.

rr_download?name=XXX

Download a specified file from the SD card.

rr_delete?name=XXX

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

rr_filelist?dir=XXX

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":[type],"name":"[name]","size":[size],"lastModified":"[datetime]"}

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.

rr_fileinfo?name=XXX

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.

rr_move?old=XXX&new=YYY

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.

rr_mkdir?dir=XXX

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

rr_config

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

grafik.png

For this job two syntax variants can be used

  1. Enter https://htupser:htpassword@your.domain.de/rr_connect?password=yourpassword in URL field and leave password field empty
  2. Enter https://htupser:htpassword@your.domain.de and enter your Duet password in "password" field

Version #1
Erstellt: 2026-06-08 14:56:34 CEST von Mario Voigt
Zuletzt aktualisiert: 2026-06-08 15:02:14 CEST von Mario Voigt