1064 lines
32 KiB
Markdown
1064 lines
32 KiB
Markdown
# API
|
|
|
|
Most API methods are supported over both the Websocket and HTTP transports.
|
|
File Transfer and "/access" requests are only available over HTTP. The
|
|
Websocket is required to receive printer generated events such as gcode
|
|
responses. For information on how to set up the Websocket, please see the
|
|
Appendix at the end of this document.
|
|
|
|
Note that all HTTP responses are returned as a json encoded object in the form
|
|
of:
|
|
|
|
`{result: <response data>}`
|
|
|
|
Arguments sent via the HTTP APIs may either be included in the query string
|
|
or as part of the request's body. All of the examples in this document
|
|
use the query string for arguments.
|
|
|
|
Websocket requests are returned in JSON-RPC format:
|
|
`{jsonrpc: "2.0", "result": <response data>, id: <request id>}`
|
|
|
|
HTML requests will recieve a 500 status code on error, accompanied by
|
|
the specific error message.
|
|
|
|
Websocket requests that result in an error will receive a properly formatted
|
|
JSON-RPC response:
|
|
`{jsonrpc: "2.0", "error": {code: <code>, message: <msg>}, id: <request_id>}`
|
|
Note that under some circumstances it may not be possible for the server to
|
|
return a request ID, such as an improperly formatted json request.
|
|
|
|
The `test\client` folder includes a basic test interface with example usage for
|
|
most of the requests below. It also includes a basic JSON-RPC implementation
|
|
that uses promises to return responses and errors (see json-rcp.js).
|
|
|
|
## Printer Administration
|
|
|
|
### Get Klippy host information:
|
|
- HTTP command:\
|
|
`GET /printer/info`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.info", id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object containing the build version, cpu info, Klippy's current state.
|
|
|
|
```json
|
|
{
|
|
state: "<klippy state>",
|
|
state_message: "<current state message>",
|
|
hostname: "<hostname>",
|
|
software_version: "<version>",
|
|
cpu_info: "<cpu_info>",
|
|
klipper_path: "<moonraker use only>",
|
|
python_path: "<moonraker use only>",
|
|
log_file: "<moonraker use only>",
|
|
config_file: "<moonraker use only>",
|
|
}
|
|
```
|
|
|
|
### Emergency Stop
|
|
- HTTP command:\
|
|
`POST /printer/emergency_stop`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.emergency_stop", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
### Restart the host
|
|
- HTTP command:\
|
|
`POST /printer/restart`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.restart", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
### Restart the firmware (restarts the host and all connected MCUs)
|
|
- HTTP command:\
|
|
`POST /printer/firmware_restart`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.firmware_restart", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
## Printer Status
|
|
|
|
### List available printer objects:
|
|
- HTTP command:\
|
|
`GET /printer/objects/list`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.objects.list", id: <request id>}`
|
|
|
|
- Returns:\
|
|
An a list of "printer objects" that are currently available for query
|
|
or subscription. This list will be passed in an "objects" parameter.
|
|
|
|
```json
|
|
{ objects: ["gcode", "toolhead", "bed_mesh", "configfile",....]}
|
|
```
|
|
|
|
### Query printer object status:
|
|
- HTTP command:\
|
|
`GET /printer/objects/query?gcode`
|
|
|
|
The above will fetch a status update for all gcode attributes. The query
|
|
string can contain multiple items, and specify individual attributes:
|
|
|
|
`?gcode=gcode_position,busy&toolhead&extruder=target`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.objects.query", params:
|
|
{objects: {gcode: null, toolhead: ["position", "status"]}},
|
|
id: <request id>}`
|
|
|
|
Note that an empty array will fetch all available attributes for its key.
|
|
|
|
- Returns:\
|
|
An object where the top level items are "eventtime" and "status". The
|
|
"status" item contains data about the requested update.
|
|
|
|
```json
|
|
{
|
|
eventtime: <klippy time of update>,
|
|
status: {
|
|
gcode: {
|
|
busy: true,
|
|
gcode_position: [0, 0, 0 ,0],
|
|
...},
|
|
toolhead: {
|
|
position: [0, 0, 0, 0],
|
|
status: "Ready",
|
|
...},
|
|
...}
|
|
}
|
|
```
|
|
See [printer_objects.md](printer_objects.md) for details on the printer objects
|
|
available for query.
|
|
|
|
### Subscribe to printer object status:
|
|
- HTTP command:\
|
|
`POST /printer/objects/subscribe?connection_id=123456789&
|
|
gcode=gcode_position,bus&extruder=target`
|
|
|
|
Note: The HTTP API requires that a `connection_id` is passed via the query
|
|
string or as part of the form. This should be the
|
|
[ID reported](#get-websocket-id) from a currently connected websocket. A
|
|
request that includes only the `connection_id` argument will cancel the
|
|
subscription on the specified websocket.
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.objects.subscribe", params:
|
|
{objects: {gcode: null, toolhead: ["position", "status"]}},
|
|
id: <request id>}`
|
|
|
|
Note that if `objects` is an empty object then the subscription will
|
|
be cancelled.
|
|
|
|
- Returns:\
|
|
Status data for objects in the request, with the format matching that of
|
|
the `/printer/objects/query`:
|
|
|
|
```json
|
|
{
|
|
eventtime: <klippy time of update>,
|
|
status: {
|
|
gcode: {
|
|
busy: true,
|
|
gcode_position: [0, 0, 0 ,0],
|
|
...},
|
|
toolhead: {
|
|
position: [0, 0, 0, 0],
|
|
status: "Ready",
|
|
...},
|
|
...}
|
|
}
|
|
```
|
|
See [printer_objects.md](printer_objects.md) for details on the printer objects
|
|
available for subscription.
|
|
|
|
Status updates for subscribed objects are sent asynchronously over the
|
|
websocket. See the `notify_status_update` notification for details.
|
|
|
|
### Query Endstops
|
|
- HTTP command:\
|
|
`GET /printer/query_endstops/status`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.query_endstops.status", id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object containing the current endstop state, with each attribute in the
|
|
format of `endstop:<state>`, where "state" can be "open" or "TRIGGERED", for
|
|
example:
|
|
|
|
```json
|
|
{x: "TRIGGERED",
|
|
y: "open",
|
|
z: "open"}
|
|
```
|
|
|
|
### Query Server Info
|
|
- HTTP command:\
|
|
`GET /server/info`
|
|
|
|
- Websocket command:
|
|
`{jsonrpc: "2.0", method: "server.info", id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object containing the server's state, structured as follows:
|
|
|
|
```json
|
|
{
|
|
klippy_connected: <bool>,
|
|
klippy_state: <string>,
|
|
plugins: [<strings>]
|
|
}
|
|
```
|
|
Note that `klippy_state` will match the `state` value received from
|
|
`/printer/info`. The `klippy_connected` item tracks the state of the
|
|
connection to Klippy. The `plugins` key will return a list of all
|
|
enabled plugins. This can be used by clients to check if an optional
|
|
plugin is available.
|
|
|
|
### Fetch stored temperature data
|
|
- HTTP command:\
|
|
`GET /server/temperature_store`
|
|
|
|
- Websocket command:
|
|
`{jsonrpc: "2.0", method: "server.temperature_store", id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object where the keys are the available temperature sensor names, and with
|
|
the value being an array of stored temperatures. The array is updated every
|
|
1 second by default, containing a total of 1200 values (20 minutes). The
|
|
array is organized from oldest temperature to most recent (left to right).
|
|
Note that when the host starts each array is initialized to 0s.
|
|
|
|
### Fetch stored gcode info
|
|
- HTTP command:\
|
|
`GET /server/gcode_store`
|
|
|
|
Optionally, a `count` argument may be added to specify the number of
|
|
responses to fetch. If omitted, the entire gcode store will be sent
|
|
(up to 1000 responses).
|
|
|
|
`GET /server/gcode_store?count=100`
|
|
|
|
- Websocket command:
|
|
`{jsonrpc: "2.0", method: "server.gcode_store", id: <request id>}`
|
|
|
|
OR
|
|
`{jsonrpc: "2.0", method: "server.gcode_store",
|
|
params: {count: <integer>} id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object with the field `gcode_store` that contains an array
|
|
of objects. Each object will contain a `message` field and a
|
|
`time` field:
|
|
```json
|
|
{
|
|
gcode_store: [
|
|
{
|
|
message: <string>,
|
|
time: unix_time_stamp
|
|
}, ...
|
|
]
|
|
}
|
|
```
|
|
Each `message` field contains a gcode response received at the time
|
|
indicated in the `time` field. Note that the time stamp refers to
|
|
unix time (in seconds). This can be used to create a JavaScript
|
|
`Date` object:
|
|
```javascript
|
|
for (let resp of result.gcode_store) {
|
|
let date = new Date(resp.time * 1000);
|
|
// Do something with date and resp.message ...
|
|
}
|
|
```
|
|
|
|
### Restart Server
|
|
- HTTP command:\
|
|
`POST /server/restart`
|
|
|
|
- Websocket command:
|
|
`{jsonrpc: "2.0", method: "server.restart", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`"ok"` upon receipt of the restart request. After the request
|
|
is returns, the server will restart. Any existing connection
|
|
will be disconnected. A restart will result in the creation
|
|
of a new server instance where the configuration is reloaded.
|
|
|
|
## Get Websocket ID
|
|
- HTTP command:\
|
|
Not Available
|
|
|
|
- Websocket command:
|
|
`{jsonrpc: "2.0", method: "server.websocket.id", id: <request id>}`
|
|
|
|
- Returns:\
|
|
This connected websocket's unique identifer in the format shown below.
|
|
Note that this API call is only available over the websocket.
|
|
|
|
```json
|
|
{
|
|
websocket_id: <int>
|
|
}
|
|
```
|
|
|
|
## Gcode Controls
|
|
|
|
### Run a gcode:
|
|
- HTTP command:\
|
|
`POST /printer/gcode/script?script=<gc>`
|
|
|
|
For example,\
|
|
`POST /printer/gcode/script?script=RESPOND MSG=Hello`\
|
|
Will echo "Hello" to the terminal.
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.gcode.script",
|
|
params: {script: <gc>}, id: <request id>}`
|
|
|
|
- Returns:\
|
|
An acknowledgement that the gcode has completed execution:
|
|
|
|
`ok`
|
|
|
|
### Get GCode Help
|
|
- HTTP command:\
|
|
`GET /printer/gcode/help`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.gcode.help",
|
|
params: {script: <gc>}, id: <request id>}`
|
|
|
|
- Returns:\
|
|
An object where they keys are gcode handlers and values are the associated
|
|
help strings. Note that help strings are not available for basic gcode
|
|
handlers such as G1, G28, etc.
|
|
|
|
## Print Management
|
|
|
|
### Print a file
|
|
- HTTP command:\
|
|
`POST /printer/print/start?filename=<file name>`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.print.start",
|
|
params: {filename: <file name>, id:<request id>}`
|
|
|
|
- Returns:\
|
|
`ok` on success
|
|
|
|
### Pause a print
|
|
- HTTP command:\
|
|
`POST /printer/print/pause`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.print.pause", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
### Resume a print
|
|
- HTTP command:\
|
|
`POST /printer/print/resume`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.print.resume", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
### Cancel a print
|
|
- HTTP command:\
|
|
`POST /printer/print/cancel`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "printer.print.cancel", id: <request id>}`
|
|
|
|
- Returns:\
|
|
`ok`
|
|
|
|
## Machine Commands
|
|
|
|
### Shutdown the Operating System
|
|
- HTTP command:\
|
|
`POST /machine/shutdown`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "machine.shutdown", id: <request id>}`
|
|
|
|
- Returns:\
|
|
No return value as the server will shut down upon execution
|
|
|
|
### Reboot the Operating System
|
|
- HTTP command:\
|
|
`POST /machine/reboot`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "machine.reboot", id: <request id>}`
|
|
|
|
- Returns:\
|
|
No return value as the server will shut down upon execution
|
|
|
|
|
|
## File Operations
|
|
|
|
Most file operations are available over both APIs, however file upload,
|
|
file download, and file delete are currently only available via HTTP APIs.
|
|
|
|
Moonraker organizes different local directories into "roots". For example,
|
|
gcodes are located at `http:\\host\server\files\gcodes\*`, otherwise known
|
|
as the "gcodes" root. The following roots are available:
|
|
- gcodes
|
|
- config
|
|
- config_examples (read-only)
|
|
|
|
Write operations (upload, delete, make directory, remove directory) are
|
|
only available on the `gcodes` and config roots. Note that the `config` root
|
|
is only available if the "config_path" option has been set in Moonraker's
|
|
configuration.
|
|
|
|
### List Available Files
|
|
Walks through a directory and fetches all files. All file names include a
|
|
path relative to the specified "root". Note that if the query st
|
|
|
|
- HTTP command:\
|
|
`GET /server/files/list?root=gcodes`
|
|
|
|
If the query string is omitted then the command will return
|
|
the "gcodes" file list by default.
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.list", params: {root: "gcodes"}
|
|
, id: <request id>}`
|
|
|
|
If `params` are are omitted then the command will return the "gcodes"
|
|
file list.
|
|
|
|
- Returns:\
|
|
A list of objects containing file data in the following format:
|
|
|
|
```json
|
|
[
|
|
{filename: "file name",
|
|
size: <file_size>,
|
|
modified: <unix_time>,
|
|
...]
|
|
```
|
|
|
|
### Get GCode Metadata
|
|
Get file metadata for a specified gcode file. If the file is located in
|
|
a subdirectory, then the file name should include the path relative to
|
|
the "gcodes" root. For example, if the file is located at:\
|
|
`http://host/server/files/gcodes/my_sub_dir/my_print.gcode`
|
|
Then the filename should be `my_sub_dir/my_print.gcode`.
|
|
|
|
- HTTP command:\
|
|
`GET /server/files/metadata?filename=<filename>`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.metadata", params: {filename: "filename"}
|
|
, id: <request id>}`
|
|
|
|
- Returns:\
|
|
Metadata for the requested file if it exists. If any fields failed
|
|
parsing they will be omitted. The metadata will always include the file name,
|
|
modified time, and size.
|
|
|
|
```json
|
|
{
|
|
filename: "file name",
|
|
size: <file_size>,
|
|
modified: <unix_time>,
|
|
slicer: "Slicer Name",
|
|
slicer_version: "<version>",
|
|
first_layer_height: <mm>,
|
|
first_layer_bed_temp: <C>,
|
|
first_layer_extr_temp: <C>,
|
|
layer_height: <mm>,
|
|
object_height: <mm>,
|
|
estimated_time: <time_in_seconds>,
|
|
filament_total: <mm>,
|
|
thumbnails: [
|
|
{
|
|
width: <in_pixels>,
|
|
height: <in_pixels>,
|
|
size: <length_of_string>,
|
|
data: <base64_string>
|
|
}, ...
|
|
]
|
|
}
|
|
```
|
|
|
|
### Get directory information
|
|
Returns a list of files and subdirectories given a supplied path.
|
|
Unlike `/server/files/list`, this command does not walk through
|
|
subdirectories.
|
|
|
|
- HTTP command:\
|
|
`GET /server/files/directory?path=gcodes/my_subdir&extended=true`
|
|
|
|
If the query string is omitted then the command will return
|
|
the "gcodes" file list by default.
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.get_directory",
|
|
params: {path: "gcodes/my_subdir", extended: true} ,
|
|
id: <request id>}`
|
|
|
|
If the "params" are omitted then the command will return
|
|
the "gcodes" file list by default.
|
|
|
|
The `extended` argument is optional, and defaults to false. If
|
|
specified and set to true, then data returned for gcode files
|
|
will also include metadata if it is available.
|
|
|
|
- Returns:\
|
|
An object containing file and subdirectory information in the
|
|
following format:
|
|
|
|
```json
|
|
{
|
|
files: [
|
|
{
|
|
filename: "file name",
|
|
size: <file_size>,
|
|
modified: <unix_time>
|
|
}, ...
|
|
],
|
|
dirs: [
|
|
{
|
|
dirname: "directory name",
|
|
modified: <unix_time>
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Make new directory
|
|
Creates a new directory at the specified path.
|
|
|
|
- HTTP command:\
|
|
`POST /server/files/directory?path=gcodes/my_new_dir`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.post_directory", params:
|
|
{path: "gcodes/my_new_dir"}, id: <request id>}`
|
|
|
|
Returns:\
|
|
`ok` if successful
|
|
|
|
### Delete directory
|
|
Deletes a directory at the specified path.
|
|
|
|
- HTTP command:\
|
|
`DELETE /server/files/directory?path=gcodes/my_subdir`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.delete_directory", params:
|
|
{path: "gcodes/my_subdir"} , id: <request id>}`
|
|
|
|
If the specified directory contains files then the delete request
|
|
will fail, however it is possible to "force" deletion of the directory
|
|
and all files in it with and additional argument in the query string:\
|
|
`DELETE /server/files/directory?path=gcodes/my_subdir&force=true`
|
|
|
|
OR to the JSON-RPC params:\
|
|
`{jsonrpc: "2.0", method: "get_directory", params:
|
|
{path: "gcodes/my_subdir", force: True}, id: <request id>}`
|
|
|
|
Note that a forced deletion will still check in with Klippy to be sure
|
|
that a file in the requested directory is not loaded by the virtual_sdcard.
|
|
|
|
- Returns:\
|
|
`ok` if successful
|
|
|
|
### Move a file or directory
|
|
Moves a file or directory from one location to another. Note that the following
|
|
conditions must be met for a move successful move:
|
|
- The source must exist
|
|
- The source and destinations must have the same "root" directory
|
|
- The user (typically "Pi") must have the appropriate file permissions
|
|
- Neither the source nor destination can be loaded by the virtual_sdcard.
|
|
If the source or destination is a directory, it cannot contain a file
|
|
loaded by the virtual_sdcard.
|
|
|
|
When specifying the `source` and `dest`, the "root" directory should be
|
|
prefixed. Currently the only supported roots are "gcodes/" and "config/".
|
|
|
|
This API may also be used to rename a file or directory. Be aware that an
|
|
attempt to rename a directory to a directory that already exists will result
|
|
in *moving* the source directory to the destination directory.
|
|
|
|
- HTTP command:\
|
|
`POST /server/files/move?source=gcodes/my_file.gcode
|
|
&dest=gcodes/subdir/my_file.gcode`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.move", params:
|
|
{source: "gcodes/my_file.gcode",
|
|
dest: "gcodes/subdir/my_file.gcode"}, id: <request id>}`
|
|
|
|
### Copy a file or directory
|
|
Copies a file or directory from one location to another. A successful copy has
|
|
the pre-requesites as a move with one exception, a copy may complete if the
|
|
source file/directory is loaded by the virtual_sdcard. As with the move API,
|
|
the source and destination should have the root prefixed.
|
|
|
|
- HTTP command:\
|
|
`POST /server/files/copy?source=gcodes/my_file.gcode
|
|
&dest=gcodes/subdir/my_file.gcode`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.copy", params:
|
|
{source: "gcodes/my_file.gcode", dest: "gcodes/subdir/my_file.gcode"},
|
|
id: <request id>}`
|
|
|
|
### Gcode File Download
|
|
- HTTP command:\
|
|
`GET /server/files/gcodes/<file_name>`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
The requested file
|
|
|
|
### File Upload
|
|
Upload a file. Currently files may be uploaded to the "gcodes" or "config"
|
|
root, with "gcodes" being the default location. If one wishes to upload
|
|
to a subdirectory, the path may be added to the upload's file name
|
|
(relative to the root). If the directory does not exist an error will be
|
|
returned. Alternatively, the "path" argument may be set, as explained
|
|
below.
|
|
|
|
- HTTP command:\
|
|
`POST /server/files/upload`
|
|
|
|
The file to be uploaded should be added to the FormData per the XHR spec.
|
|
The following arguments may be added to the form:
|
|
- root: The root location in which to upload the file. Currently this may
|
|
be "gcodes" or "config". If not specified the default is "gcodes".
|
|
- path: This argument may contain a path (relative to the root) indicating
|
|
a subdirectory to which the file is written. If a "path" is present, the
|
|
server will attempt to create any subdirectories that do not exist.
|
|
Arguments available only for the "gcodes" root:
|
|
- print: If set to "true", Klippy will attempt to start the print after
|
|
uploading. Note that this value should be a string type, not boolean. This
|
|
provides compatibility with Octoprint's legacy upload API.
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
The file name along with a successful response.
|
|
```json
|
|
{'result': "file_name"}
|
|
```
|
|
If the supplied root is "gcodes", a "print_started" attribute is also
|
|
returned.
|
|
```json
|
|
{'result': "file_name", 'print_started': <boolean>}
|
|
```
|
|
|
|
### Gcode File Delete
|
|
Delete a file in the "gcodes" root. A relative path may be added to the file
|
|
to delete a file in a subdirectory.
|
|
- HTTP command:\
|
|
`DELETE /server/files/gcodes/<file_name>`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.delete_file", params:
|
|
{path: "gcodes/<file_name>"}, id: <request id>}`
|
|
|
|
If the gcode file exists within a subdirectory, the relative
|
|
path should be included in the file name.
|
|
|
|
- Returns:\
|
|
The HTTP request returns the name of the deleted file.
|
|
|
|
### Download included config file
|
|
- HTTP command:\
|
|
`GET /server/files/config/<file_name>`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
The requested file
|
|
|
|
### Delete included config file
|
|
Delete a file in the "config" root. A relative path may be added to the file
|
|
to delete a file in a subdirectory.
|
|
- HTTP command:\
|
|
`DELETE /server/files/config/<file_name>`
|
|
|
|
- Websocket command:\
|
|
`{jsonrpc: "2.0", method: "server.files.delete_file", params:
|
|
{path: "config/<file_name>}, id: <request id>}`
|
|
|
|
- Returns:\
|
|
The HTTP request returns the name of the deleted file.
|
|
|
|
### Download a config example
|
|
- HTTP command:\
|
|
`GET /server/files/config_examples/<file_name>`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
The requested file
|
|
|
|
### Download klippy.log
|
|
- HTTP command:\
|
|
`GET /server/files/klippy.log`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
klippy.log
|
|
|
|
### Download moonraker.log
|
|
- HTTP command:\
|
|
`GET /server/files/moonraker.log`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
moonraker.log
|
|
|
|
## Authorization
|
|
|
|
Untrusted Clients must use a key to access the API by including it in the
|
|
`X-Api-Key` header for each HTTP Request. The API below allows authorized
|
|
clients to receive and change the current API Key.
|
|
|
|
### Get the Current API Key
|
|
- HTTP command:\
|
|
`GET /access/api_key`
|
|
|
|
- Websocket command:\
|
|
Not Available
|
|
|
|
- Returns:\
|
|
The current API key
|
|
|
|
### Generate a New API Key
|
|
- HTTP command:\
|
|
`POST /access/api_key`
|
|
|
|
- Websocket command:\
|
|
Not available
|
|
|
|
- Returns:\
|
|
The newly generated API key. This overwrites the previous key. Note that
|
|
the API key change is applied immediately, all subsequent HTTP requests
|
|
from untrusted clients must use the new key.
|
|
|
|
### Generate a Oneshot Token
|
|
|
|
Some HTTP Requests do not expose the ability the change the headers, which is
|
|
required to apply the `X-Api-Key`. To accomodiate these requests it a client
|
|
may ask the server for a Oneshot Token. Tokens expire in 5 seconds and may
|
|
only be used once, making them relatively for inclusion in the query string.
|
|
|
|
- HTTP command:\
|
|
`GET /access/oneshot_token`
|
|
|
|
- Websocket command:
|
|
Not available
|
|
|
|
- Returns:\
|
|
A temporary token that may be added to a requests query string for access
|
|
to any API endpoint. The query string should be added in the form of:
|
|
`?token=randomly_generated_token`
|
|
|
|
## Websocket notifications
|
|
Printer generated events are sent over the websocket as JSON-RPC 2.0
|
|
notifications. These notifications are sent to all connected clients
|
|
in the following format:
|
|
|
|
`{jsonrpc: "2.0", method: <event method name>}`
|
|
|
|
OR
|
|
|
|
`{jsonrpc: "2.0", method: <event method name>, params: [<event parameter>]}`
|
|
|
|
If a notification has parameters, the `params` value will always be
|
|
wrapped in an array as directed by the JSON-RPC standard. Currently
|
|
all notifications available are broadcast with either no parameters
|
|
or a single parameter.
|
|
|
|
### Gcode response:
|
|
All calls to gcode.respond() are forwarded over the websocket. They arrive
|
|
as a "gcode_response" notification:
|
|
|
|
`{jsonrpc: "2.0", method: "notify_gcode_response", params: ["response"]}`
|
|
|
|
### Status subscriptions:
|
|
Status Subscriptions arrive as a "notify_status_update" notification:
|
|
|
|
`{jsonrpc: "2.0", method: "notify_status_update", params: [<status_data>]}`
|
|
|
|
The structure of the status data is identical to the structure that is
|
|
returned from an object query's "status" attribute.
|
|
|
|
### Klippy Ready:
|
|
Notify clients when Klippy has reported a ready state
|
|
|
|
`{jsonrpc: "2.0", method: "notify_klippy_ready"}`
|
|
|
|
### Klippy Disconnected:
|
|
Notify clients when Moonraker's connection to Klippy has terminated
|
|
|
|
`{jsonrpc: "2.0", method: "notify_klippy_disconnected"}`
|
|
|
|
### File List Changed
|
|
When a client makes a change to the virtual sdcard file list
|
|
(via upload or delete) a notification is broadcast to alert all connected
|
|
clients of the change:
|
|
|
|
`{jsonrpc: "2.0", method: "notify_filelist_changed",
|
|
params: [<file changed info>]}`
|
|
|
|
The <file changed info> param is an object in the following format, where
|
|
the "action" is the operation that prompted the change, and the "item"
|
|
contains information about the item that has changed:
|
|
|
|
```json
|
|
{action: "<action>",
|
|
item: {
|
|
path: "<file or directory path>",
|
|
root: "<root_name>",
|
|
size: <file size>,
|
|
modified: "<date modified>"
|
|
}
|
|
```
|
|
Note that file move and copy actions also include a "source item" that
|
|
contains the path and root of the source file or directory.
|
|
```json
|
|
{action: "<action>",
|
|
item: {
|
|
path: "<file or directory path>",
|
|
root: "<root_name>",
|
|
size: <file size>,
|
|
modified: "<date modified>"
|
|
},
|
|
source_item: {
|
|
path: "<file or directory path>",
|
|
root: "<root_name>"
|
|
}
|
|
}
|
|
```
|
|
|
|
The following `actions` are currently available:
|
|
- `upload_file`
|
|
- `delete_file`
|
|
- `create_dir`
|
|
- `delete_dir`
|
|
- `move_item`
|
|
- `copy_item`
|
|
|
|
### Metadata Update
|
|
When a new file is uploaded via the API a websocket notification is broadcast
|
|
to all connected clients after parsing is complete:
|
|
|
|
`{jsonrpc: "2.0", method: "notify_metadata_update", params: [metadata]}`
|
|
|
|
Where `metadata` is an object in the following format:
|
|
|
|
```json
|
|
{
|
|
filename: "file name",
|
|
size: <file size>,
|
|
modified: "last modified date",
|
|
slicer: "Slicer Name",
|
|
first_layer_height: <in mm>,
|
|
layer_height: <in mm>,
|
|
object_height: <in mm>,
|
|
estimated_time: <time in seconds>,
|
|
filament_total: <in mm>,
|
|
thumbnails: [
|
|
{
|
|
width: <in pixels>,
|
|
height: <in pixels>,
|
|
size: <length of string>,
|
|
data: <base64 string>
|
|
}, ...
|
|
]
|
|
}
|
|
```
|
|
|
|
# Appendix
|
|
|
|
## Websocket setup
|
|
All transmissions over the websocket are done via json using the JSON-RPC 2.0
|
|
protocol. While the websever expects a json encoded string, one limitation
|
|
of Eventlet's websocket is that it can not send string encoded frames. Thus
|
|
the client will receive data om the server in the form of a binary Blob that
|
|
must be read using a FileReader object then decoded.
|
|
|
|
The websocket is located at `ws://host:port/websocket`, for example:
|
|
```javascript
|
|
var s = new WebSocket("ws://" + location.host + "/websocket");
|
|
```
|
|
|
|
It also should be noted that if authorization is enabled, an untrusted client
|
|
must request a "oneshot token" and add that token's value to the websocket's
|
|
query string:
|
|
|
|
```
|
|
ws://host:port/websocket?token=<32 character base32 string>
|
|
```
|
|
|
|
This is necessary as it isn't currently possible to add `X-Api-Key` to a
|
|
Websocket object's request header.
|
|
|
|
The following startup sequence is recommened for clients which make use of
|
|
the websocket:
|
|
1) Attempt to connect to `/websocket` until successful using a timer-like
|
|
mechanism
|
|
2) Once connected, query `/printer/info` (or `printer.info`) for the ready
|
|
status.
|
|
- If the response returns an error (such as 404), set a timeout for
|
|
2 seconds and try again.
|
|
- If the response returns success, check the result's `state` attribute
|
|
- If `state == "ready"` you may proceed to request status of printer objects
|
|
make subscriptions, get the file list, etc.
|
|
- If `state == "error"` then Klippy has experienced an error
|
|
- If an error is detected it might be wise to prompt the user. You can
|
|
get a description of the error from the `state_message` attribute
|
|
- If `state == "shutdown"` then Klippy is in a shutdown state.
|
|
- If `state == "startup"` then re-request printer info in 2s.
|
|
- Repeat step 2 until Klipper reports ready.
|
|
- Client's should watch for the `notify_klippy_disconnected` event. If it reports
|
|
disconnected then Klippy has either been stopped or restarted. In this
|
|
instance the client should repeat the steps above to determine when
|
|
klippy is ready.
|
|
|
|
## Basic Print Status
|
|
An advanced client will likely use subscriptions and notifications
|
|
to interact with Moonraker, however simple clients such as home automation
|
|
software and embedded devices (ie: ESP32) may only wish to monitor the
|
|
status of a print. Below is a high level walkthrough for receiving print state
|
|
via polling.
|
|
|
|
- Set up a timer to poll at the desired interval. Depending on your use
|
|
case, 1 to 2 seconds is recommended.
|
|
- On each cycle, issue the following request:
|
|
- `GET http://host/printer/objects/query?webhooks&virtual_sdcard&print_stats`\
|
|
Or via json-rpc:\
|
|
`{'jsonrpc': "2.0", 'method': "printer.objects.query", 'params':
|
|
{'objects': {'webhooks': null, 'virtual_sdcard': null,
|
|
'print_stats': null}}, id: <request id>}`
|
|
- If the request returns an error or the returned `result.status` is an empty
|
|
object printer objects are not available for query. Each queried object
|
|
should be available in `result.status`. The client should check to make
|
|
sure that all objects are received before proceeding.
|
|
- Inspect `webhooks.ready`. If the value is not "ready" the printer
|
|
is not available. `webhooks.message` contains a message pertaining
|
|
to the current state.
|
|
- If the printer is ready, inspect `print_stats.state`. It may be one
|
|
of the following values:
|
|
- "standby": No print in progress
|
|
- "printing": The printer is currently printing
|
|
- "paused": A print in progress has been paused
|
|
- "error": The print exited with an error. `print_stats.message`
|
|
contains a related error message
|
|
- "complete": The last print has completed
|
|
- If `print_stats.state` is not "standby" then `print_stats.filename`
|
|
will report the name of the currently loaded file.
|
|
- `print_stats.filename` can be used to fetch file metadata. It
|
|
is only necessary to fetch metadata once per print.\
|
|
`GET http://host/server/files/metadata?filename=<filename>`\
|
|
Or via json-rpc:\
|
|
`{jsonrpc: "2.0", method: "server.files.metadata",
|
|
params: {filename: "filename"}
|
|
, id: <request id>}`\
|
|
If metadata extraction failed then this request will return an error.
|
|
Some metadata fields are only populated for specific slicers, and
|
|
unsupported slicers will only return the size and modifed date.
|
|
- There are multiple ways to calculate the ETA, this example will use
|
|
file progress, as it is possible calculate the ETA with or without
|
|
metadata.
|
|
- If `metadata.estimated_time` is available, the eta calculation can
|
|
be done as:
|
|
```javascript
|
|
// assume "result" is the response from the status query
|
|
let vsd = result.status.virtual_sdcard;
|
|
let prog_time = vsd.progress * metadata.estimated_time;
|
|
let eta = metadata.estimated_time - prog_time
|
|
```
|
|
Alternatively, one can simply subtract the print duration from
|
|
the estimated time:
|
|
```javascript
|
|
// assume "result" is the response from the status query
|
|
let pstats = result.status.print_status;
|
|
let eta = metadata.estimated_time - pstats.print_duration;
|
|
if (eta < 0)
|
|
eta = 0;
|
|
```
|
|
- If no metadata is available, print duration and progress can be used to
|
|
calculate the ETA:
|
|
```javascript
|
|
// assume "result" is the response from the status query
|
|
let vsd = result.status.virtual_sdcard;
|
|
let pstats = result.status.print_stats;
|
|
let total_time = pstats.print_duration / vsd.progress;
|
|
let eta = total_time - pstats.print_duration;
|
|
```
|
|
- It is possible to query additional object if a client wishes to display
|
|
more information (ie: temperatures). See
|
|
[printer_objects.md](printer_objects.md) for more information.
|
|
|
|
## Bed Mesh Coordinates
|
|
The [bed_mesh](printer_objects.md#bed_mesh) printer object may be used
|
|
to generate three dimensional coordinates of a probed area (or mesh).
|
|
Below is an example (in javascript) of how to transform the data received
|
|
from a bed_mesh object query into an array of 3D coordinates.
|
|
```javascript
|
|
// assume that we have executed an object query for bed_mesh and have the
|
|
// result. This example generates 3D coordinates for the probed matrix,
|
|
// however it would work with the mesh matrix as well
|
|
function process_mesh(result) {
|
|
let bed_mesh = result.status.bed_mesh
|
|
let matrix = bed_mesh.probed_matrix;
|
|
if (!(matrix instanceof Array) || matrix.length < 3 ||
|
|
!(matrix[0] instanceof Array) || matrix[0].length < 3)
|
|
// make sure that the matrix is valid
|
|
return;
|
|
let coordinates = [];
|
|
let x_distance = (bed_mesh.mesh_max[0] - bed_mesh.mesh_min[0]) /
|
|
(matrix[0].length - 1);
|
|
let y_distance = (bed_mesh.mesh_max[1] - bed_mesh.mesh_min[1]) /
|
|
(matrix.length - 1);
|
|
let x_idx = 0;
|
|
let y_idx = 0;
|
|
for (const x_axis of matrix) {
|
|
x_idx = 0;
|
|
let y_coord = bed_mesh.mesh_min[1] + (y_idx * y_distance);
|
|
for (const z_coord of x_axis) {
|
|
let x_coord = bed_mesh.mesh_min[0] + (x_idx * x_distance);
|
|
x_idx++;
|
|
coordinates.push([x_coord, y_coord, z_coord]);
|
|
}
|
|
y_idx++;
|
|
}
|
|
}
|
|
// Use the array of coordinates visualize the probed area
|
|
// or mesh..
|
|
```
|