API Overview - Duet3D/DuetSoftwareFramework GitHub Wiki

DSF provides a powerful API aimed at expandability and flexibility. The easiest way to get started with it is to obtain the .NET package called DuetAPIClient. Both the API and the API client are available as NuGet packages (see here and here). A Python API client are available.

To get a basic idea how the .NET-based DuetAPIClient works, check out the source code of the CodeConsole utility and the code documentation.

The .NET-based API libraries are - unlike the other DSF components - licensed under the terms of the LGPL 3.0 or later. If you wish to build your own API client, it is strongly recommended to follow the DuetAPIClient implementation because it properly documents and handles possible exceptions of every command.

Note that DSF 3.2 requires permissions for third-party plugins that are installed from the web interface. Please see the plugins documentation for further details.

Inter-Process Communication

To make use of the API, inter-process communication has to be performed. For this purpose UNIX sockets are used. By default, DSF provides a UNIX socket at /var/run/dsf/dcs.sock which other applications can connect to.

A third-party application may connect to this socket in stream mode. Once a connection has been established, DCS sends a welcome message in JSON format like

{
    "id": 12,
    "version": 11
}

where id represents a connection identifier and version the version number of the API provided. Once this object has been received, the client is supposed to either close the connection (e.g. because the API level is incompatible) or to send back an init message with the desired mode of operation:

{
    "mode": "Command",
    "version": 11
}

where mode can be either Command, Intercept, or Subscribe (see docs). This is then acknowledged by the server:

{
    "success": true
}

If anything went wrong during the mode selection, the server may respond with

{
    "success": false,
    "errorType": "ArgumentException",
    "errorMessage": "Invalid connection mode"
}

If you are using the DuetAPIClient, there is no need to deal with plain JSON objects yourself. The API libraries already provide wrappers for every supported object type. To see how JSON objects are exchanged in detail, you can start DuetControlServer with the --log-level trace option.

Command Mode

A command connection is a universal connection mode in which various commands can be performed. Check out the code documentation for a list of supported commands.

To put the new connection into Command mode, a client can respond to the first init message with

{
    "mode": "Command"
}

Once this mode has been selected and the success response as described above has been processed by the client, the client may issue supported commands. For example:

{
    "command": "SimpleCode",
    "code": "G4 S3"
}

As soon as G4 S3 completes, a response like

{
    "success": true,
    "result": ""
}

is sent back to the client. Here the result field holds the final code result. Note that the connection will be blocked as long as a command is being processed.

Interception Mode

Duet Software Framework allows you to intercept codes as they are being processed. At present, the following interception modes are supported:

  • pre: Code is being started but it has not been processed internally yet
  • post: Code has been executed internally but it has not been resolved. It is about to be sent to RepRapFirmware for further processing
  • executed: Code has been executed and a result is about to be returned

Once the server's initialization message has been received, a client may choose to intercept codes by sending

{
    "mode": "Intercept",
    "interceptionMode": "Pre"
}

As in the example above, this is acknowledged by the server:

{
    "success": true
}

After this the client has to listen for incoming codes until the connection has been closed. When a code is being executed, something like this is sent to the client:

{
    "type": 'G',
    "parameters": [
        "letter": 'S',
        "value": "4",
        "isString": "false"
    ],
    ...
}

See the documentation for further information about the transmitted fields.

After receipt, the code can be either:

  • ignored which lets the code continue as expected,
  • canceled which cancels the code and throws an OperationCanceledException on its task,
  • resolved which resolves the code using a given result

Apart from that, you can run any commands like in the command mode while a code is being intercepted. Note that it is mandatory to send one of the three commands above to avoid deadlocks. If the connection is interrupted while a code is being intercepted, this happens automatically in the background.

So if a client wants to ignore the received code, it can send

{
    "command": "Ignore"
}

After that, DuetControlServer will send the next code in the queue to the client.

Subscription Mode

In many use-cases a third-party application wishes to receive updates about the machine model, which contains information like axis positions and other useful information. For this purpose Duet Software Framework provides a mode in which machine model updates can be received whenever the machine model has been updated.

In this mode, only a single command is supported: Acknowledge Send this command whenever the latest machine model update has been processed. Any other command will create an ArgumentException. Note that the Acknowledge command does NOT send back a standard response; instead the next model update is transferred as soon as it is available.

This mode provides two types of operation:

  1. Full mode. Every time the machine model has been updated and parsed, the whole machine model is serialized and send to the API client
  2. Patch mode. In this mode, only the changed object model fields are transferred when an update occurs. In addition, you can specify a filter in case you are only interested in a certain namespace.

Regardless of the chosen mode, the first thing the client will receive is the full serialized machine model. In case a client wants to connect, an init message like this has to be sent first:

{
    "mode": "Subscribe",
    "subscriptionMode": "Patch"
}

Like in the examples before the server responds with a success message:

{
    "success": true
}

Which is followed by the full serialized machine model:

{
    "channels:" { ... },
    "electronics": { ... },
    ...
}

In order to flag the readiness for processing more data, the client sends back

{
    "command: "Acknowledge"
}

After that, the (partial) machine model is sent back to the client when needed.

Custom HTTP endpoints

For custom applications, it can be handy to register custom HTTP endpoints. For this purpose, there is a command that lets you create one. However, these endpoints only support plain text and no binary data. Consider this when designing your own API endpoints.

Custom RESTful HTTP endpoints

To create a new HTTP REST endpoint, one may send

{
    "command": "AddHttpEndpoint",
    "endpointType": "GET",
    "namespace": "third-party-app",
    "path", "test",
    "uploadRequest": false
}

which creates a response from DuetControlServer like

{
    "success": true,
    "result": "/var/run/dsf/third-party-app/test-GET.sock"
}

where the result represents the path to the UNIX socket that DWS will use. As a consequence, the third-pary application has to start listening on the specified UNIX socket path in SOCK_STREAM mode. Whenever a new HTTP request is made, DuetWebServer will attempt to connect to the given UNIX socket path. After that, a serialized ReceivedHttpRequest JSON object is sent. The endpoint server may then send back a serialized SendHttpResponse JSON object that specifies what result needs to be returned to the client.

Custom WebSockets

If you want to create your own custom WebSocket provider, replace GET with WebSocket above. When a new WebSocket is connected, DuetWebServer will attempt to connect to the same UNIX socket. However, a client may not have sent any information yet and in this case no ReceivedHttpRequest response is sent to the UNIX socket provider. To send a message to the WebSocket, send the same SendHttpResponse over the UNIX socket connection.

For further information, check the documentation or have a look at the CustomHttpEndpoint source code.