Dialog Tutorial

When you want to replace a printer controlled display you might want to show some dialogs triggered by some actions or printer responses. For this purpose the server supports some server commands that show a dialog on the touchscreen, regular gui and Repetier-Server Monitor if the printer is active.

The same dialogs also get used if the firmware supports the host prompts. Then you will see the firmware generated dialog the same way. But this happens automatically, so we will ignore that in this tutorial and concentrate on dialogs that are generated through special printer configuration.

Basic dialogs

The server supports 3 standard dialogs that just show a message – info, warning and error dialogs. To create them just add the command like this:

@info Some message text
@warning Some warning text
@error Some error text

Now that you know how to show them the big question is where to add them. While you can add them anywhere they should of course only appear when there is a reason. In the generated g-code you might want  to add a info at some special places, e.g. a warning that you need to do xy soon or before a @pause command to inform the user why you are going to pause.

More likely is that you want some printer action trigger a message. So it is now time to learn the more advanced settings in the Printer Settings->G-Code tab. There is a sub tab called Response to Event which you will need. Lets assume you have added a trigger to your printer that detects when the spool has only 90% capacity. When that is reached the firmware writes “filament_low” once. We want to get a warning when this happens without watching the console constantly.

So you add a event – the event name must not contain spaces! It is a message send to all connected interfaces so you can also use this to trigger some other functions. In this case it is not relevant.

Next is the regular expression that should match the output. In our case the expression is “^filament_low$”. The ^ means the line must start with this. The $ marks the end of the line. So only lines that exactly contain that term are matched. If you omit these chars any line containing the text “filament_low” anywhere would match. If you are unsure I advise to pretest your expression in an online tool like https://regex101.com/. If you are unfamiliar with regular expressions, there are many tutorials or just ask wikipedia.

Last block is G-code to execute. Here we enter our warning:

@warning Filament is low. Make sure you have a replacement

Now save the new settings and try to trigger it. You should then see the warning.


If you need some interactivity, you need to use server dialogs. These work the same like the host prompt support some firmwares offer, just completely handled by the server. First you create the dialog. Here a simple Homing example that lets you choose which axis to home:

@dialogStart "Select the axis for homing" "Home"
@dialogButton All "G28"
@dialogButton X "G28 X0"
@dialogButton Y "G28 Y0"
@dialogButton Z "G28 Z0"
@dialogButton Cancel

So how does it work? With @dialogStart you initiate the creation of a dialog box. The first parameter is the messege in the dialog and the second one the header text. If the text contains spaces, put it in double quotes like shown in the example.

Next step is defining the buttons. There is no limit but too many might look not so nice. They again take two commands. The first is the button text and the second one is the g-code to execute. Put it in quotes and split commands with \n.

Last step is calling @dialogShow which finally shows the dialog to all users that are on the printer interface. If they are in a global window they won’t see the dialog until they switch to printer. In Repetier-Server Monitor dashboard you will see a warning icon when dialogs from printer are available.

The user can now move the dialog around dragging it at the header (except on the touch interface) and select one of the buttons. Any selection of a button closes the dialog for all users and executes the g-code associated with that button. If a button has no g-code like the “Cancel” button in this example only the dialog gets closed.

The two typical places are in Printer  Configuration -> G-Code -> Quick Commands or Wizards. Here you can use them to define more complex g-code sequences.

In the following example we explain the manual bed levelling script:

The procedure of this script is divided into 4 steps:

  • Opening a dialogue
  • Identifying the printer type
  • Calculating the position
  • Moving to calculated position


In order to better structure these steps, we create functions. With functions you can bundle certain commands and make them available with one command.

First, you should check whether the printing bed is free of objects, because the printer has to home.
A dialogue is created for this purpose:

@dialogStart "This wizard is meant for manual bed leveling. It will offer buttons to quickly move to the edges and center. At first it will home, so please make sure bed is free of obstacles." "Manual Bed Leveling"
@dialogIcon '<svg version="1.1" viewBox="-10 0 1011 1000"> <path fill="currentColor" d="M494.27 425.45c41.6104 33.8623 68.2715 54.5059 88.3301 102.375c24.0908 57.4873 18.9805 92.1377 18.25 155.138l-116.069 -0. 788086c0.729492 -44.0996 8.93066 -57.5654 -6.57031 -96.8623c-14.5996 -37.0127 -32.8496 -49.6123 -60.5898 -77. 9629zM2.91016 800.85l713.939 -787.5l81.7607 85.0508l-534.36 581.175h726.05v121.274h-987.39z"></path></svg>'
@dialogButton "Bed cleared - Start" "@call MBLStart"
@dialogButton "Cancel"

In this section, a dialogue is created with the @dialogStart and @dialogShow server commands. Elements can be set between these commands. In this case, a button is added which executes the server command @call MBLStart, which runs the named fuction MBLStart.

The function MBLStart will then check which printer model is being used, as delta printers are leveled differently than carthesian models. This can be easily checked as we know which print bed shape each machine has. We make this distinction with a condition.

@func MBLStart
@if {{config.bed_shape == "circle"}}
@call MBLDelta
@call MBLCartesian

Inside double curly brackets you can write expressions using variables and mathematical operators. See in manual unter computed expressions for more details. The server command is the executed with evaluated expression. Here in the if condition we compare the variable bed_shape with the word circle. The result is 1 or 0.  This variable can have “circle”, “rectangle” and “belt” as values. For “circle” the function MBLDelta is called, otherwise (else) the function MBLCartesian.

In this example we assume that the machine is a cartesian machine. The following function MBLCartesian looks like this:

@func MBLCartesian
@set local.middleX {{(config.bed_x_min + config.bed_x_max) / 2}}
@set local.middleY {{(config.bed_y_min + config.bed_y_max) / 2}}
@dialogStart "Offset x and y are the distances of the points to the bed border. If you measure with a piece of paper, you should level for z height 0. If you have a block of known height that you push between bed and nozzle, enter the object height instead. With z hop printer raises head when traveling between the points." "Manual Bed Leveling"
@dialogIcon '<svg version="1.1" viewBox="-10 0 1011 1000"> <path fill="currentColor" d="M494.27 425.45c41.6104 33.8623 68.2715 54.5059 88.3301 102.375c24.0908 57.4873 18.9805 92.1377 18.25 155.138l-116.069 -0.788086c0.729492 -44.0996 8.93066 -57.5654 -6.57031 -96.8623c-14.5996 -37.0127 -32.8496 -49.6123 -60.5898 -77.9629zM2.91016 800.85l713.939 -787.5l81.7607 85.0508l-534.36 581.175h726.05v121.274h-987.39z"></path></svg>'
@dialogInputDouble "Offset X [mm]" perm.manBedLevXoffset default({{get("perm","manBedLevXoffset","20")}}) min(0) max({{local.middleX}})
@dialogInputDouble "Offset Y [mm]" perm.manBedLevYoffset default({{get("perm","manBedLevYoffset","20")}}) min(0) max({{local.middleY}})
@dialogInputDouble "Measure Z at [mm]" perm.manBedLevZoffset default({{get("perm","manBedLevZoffset","0")}}) min(0) max({{config.move_z_max}})
@dialogInputDouble "Z Hop [mm]" perm.manBedLevZhop default({{get("perm","manBedLevZhop","5")}}) min(0) max({{config.move_z_max}})
@dialogButton "Top-Left" "@call MBLDriveTo {{config.bed_x_min + perm.manBedLevXoffset}} {{config.bed_y_max - perm.manBedLevYoffset}}"
@dialogButton "Top-Right" "@call MBLDriveTo {{config.bed_x_max - perm.manBedLevXoffset}} {{config.bed_y_max - perm.manBedLevYoffset}}"
@dialogButton "Center" "@call MBLDriveTo {{(config.bed_x_min + config.bed_x_max) / 2}} {{(config.bed_y_min + config.bed_y_max) / 2}}"
@dialogButton "Bottom-Left" "@call MBLDriveTo {{config.bed_x_min + perm.manBedLevXoffset}} {{config.bed_y_min + perm.manBedLevYoffset}}"
@dialogButton "Bottom-Right" "@call MBLDriveTo {{config.bed_x_max - perm.manBedLevXoffset}} {{config.bed_y_min + perm.manBedLevYoffset}}"
@dialogButton "Finished"

Here 2 new variables are created: local.middleX and local.middleY. The local scope defines variables, which can only be accessed and retrieved within the defining function.

The following input fields were defined here:

  • Offset X [mm] – stores value in variable perm.manBedLevXoffset
  • Offset Y [mm] – stores value in variable perm.manBedLevYoffset
  • Measure Z at [mm] – stores value in variable perm.manBedLevZoffset
  • Z-hop [mm] – stores value in variable perm.manBedLevZhop

The perm scope is a scope in which variables can be stored permanently, they even exist even after a server reboot. We do this because we try to retrieve the variables in the individual input fields as default values so that the last values entered are suggested again. The default value shown is set with the parameter default for the individual inputs. Now there is the case that these variables are not yet defined, because they are only created after the first closing of the dialogue. For this case we use the inline function get, which provides as parameters the scope, the variable name and a default value, for the case that the variable does not yet exist. This function returns the value of the variable or the set default value.

When a button gets pressed the values get stored in the variable named in the input fields. For @dialogInputDouble this is the second parameter. As you see these are the perm.* described above.

Further parameters of the individual input fields are min and max. These define the minimum and maximum values that can be entered.

In addition to the input fields, there are the following buttons which call the function MBLDriveTo with calculated X and Y parameters:

  • Top-Left
  • Top-Right
  • Centre
  • Bottom-Left
  • Bottom-Right

When a button gets pressed the server exectues the command in the last parameter. For the positioning buttons you see thet we call the MBLDriveTo function, where the X and Y positions get computed using the printer configuration and the entered values.

Finally, there is a Finished button that does not call anything. We will come to this later.

If you have now pressed a position button and thus called up MBLDriveTo with the corresponding positions, the coordinates are now inserted into g-code:

@func MBLDriveTo x y
G1 Z{{fixed(min(perm.manBedLevZhop + perm.manBedLevZoffset, config.move_z_max),3)}} F{fixed(config.speed_z_per_minute,0)}}
G1 X{{fixed(local.x,2)}} Y{{fixed(local.y,2)}} F{{fixed(config.speed_xy_per_minute,0)}}
G1 Z{{fixed(local.manBedLevZoffset,3)}} F{{fixed(config.speed_z_per_minute,0)}}
@call MBLCartesian

You see in the @func line that this function expects the two parameters X and Y. Function parameter get stored in the local scope, so that you can access them with local.x and local.y.

Here, a Z-hop is made at the specified height, as long as the set Z-offset and the z-hop together are not higher than the set total Z-height. The min function is used here. The function min returns the smaller of the two defined values. Then X and Y are moved to the position with the highest possible speed. Finally, Z is brought back to the defined Z position. The inline function fixed rounds the values to the specified decimal precision.

After moving, the function MBLCartesian is called again. This opens the dialogue again and a new position can be selected. This continues until the button Finished is pressed, which does not execute anything and lets the function run out. After that, the script is finished.