KlipperRestApiSharp
A C# based library to communicate with a klipper using MainsailOS.
Moonrakers Documentation
This C# library wraps the available Web API functions listed in the
Moonraker's documentation below.
https://moonraker.readthedocs.io/en/latest/web_api/
You can see the current migration progress in the following table.
WebAPI migration status
Following you'll find the list of migrated functions from the WebAPI.
Printer Administration
| Function |
Added? |
Tested? |
| Get Klippy host information |
✅ |
✅ |
| Emergency Stop |
✅ |
✅ |
| Host Restart |
✅ |
✅ |
| Firmware Restart |
✅ |
✅ |
Printer Status
| Function |
Added? |
Tested? |
| List available printer objects |
✅ |
✅ |
| Query printer object status |
✅ |
✅ |
| Subscribe to printer object status |
✅ |
✅ |
| Query Endstops |
✅ |
✅ |
| Query Server Info |
✅ |
✅ |
| Get Server Configuration |
✅ |
✅ |
| Request Cached Temperature Data |
✅ |
✅ |
| Request Cached GCode Responses |
✅ |
✅ |
| Restart Server |
✅ |
✅ |
| Get Websocket ID |
✅ |
✅ |
GCode APIs
| Function |
Added? |
Tested? |
| Run a gcode |
✅ |
✅ |
| Get GCode Help |
✅ |
✅ |
Print Management
| Function |
Added? |
Tested? |
| Print a file |
✅ |
✅ |
| Pause a print |
✅ |
✅ |
| Resume a print |
✅ |
No |
| Cancel a print |
✅ |
No |
Machine Commands
| Function |
Added? |
Tested? |
| Get System Info |
✅ |
✅ |
| Shutdown the Operating System |
✅ |
✅ |
| Reboot the Operating System |
✅ |
✅ |
| Restart a system service |
✅ |
No |
| Stop a system service |
✅ |
No |
| Start a system service |
✅ |
No |
| Get Moonraker Process Stats |
✅ |
✅ |
File Operations
| Function |
Added? |
Tested? |
| List available files |
✅ |
✅ |
| Get gcode metadata |
✅ |
✅ |
| Get directory information |
✅ |
✅ |
| Create directory |
✅ |
✅ |
| Delete directory |
✅ |
✅ |
| Move a file or directory |
✅ |
✅ |
| Copy a file or directory |
✅ |
✅ |
| File download |
✅ |
No |
| File upload |
✅ |
✅ |
| File delete |
✅ |
✅ |
| Download klippy.log |
✅ |
✅ |
| Download moonraker.log |
✅ |
✅ |
Authorization
| Function |
Added? |
Tested? |
| Login User |
✅ |
✅ |
| Logout Current User |
✅ |
✅ |
| Get Current User |
✅ |
✅ |
| Create User |
✅ |
✅ |
| Delete User |
✅ |
✅ |
| List Available Users |
✅ |
✅ |
| Reset User Password |
✅ |
✅ |
| Refresh JSON Web Token |
✅ |
✅ |
| Generate a Oneshot Token |
✅ |
✅ |
| Get the Current API Key |
✅ |
✅ |
| Generate a New API Key |
✅ |
✅ |
Database APIs
| Function |
Added? |
Tested? |
| List namespaces |
✅ |
✅ |
| Get Database Item |
✅ |
✅ |
| Add Database Item |
✅ |
✅ |
| Delete Database Item |
✅ |
✅ |
Job Queue APIs
| Function |
Added? |
Tested? |
| Retrieve the job queue status |
✅ |
✅ |
| Enqueue a job |
✅ |
✅ |
| Remove a Job |
✅ |
✅ |
| Pause the job queue |
✅ |
✅ |
| Start the job queue |
✅ |
✅ |
Update Manager APIs
| Function |
Added? |
Tested? |
| Get update status |
✅ |
No |
| Perform a full update |
✅ |
No |
| Update Moonraker |
✅ |
No |
| Update Klipper |
✅ |
No |
| Update Client |
✅ |
No |
| Update System Packages |
✅ |
No |
| Recover a corrupt repo |
✅ |
No |
Power APIs
| Function |
Added? |
Tested? |
| Get Device List |
✅ |
✅ |
| Get Device Status |
✅ |
✅ |
| Set Device State |
✅ |
✅ |
| Get Batch Device Status |
✅ |
✅ |
| Batch Power On Devices |
✅ |
✅ |
| Batch Power Off Devices |
✅ |
✅ |
Octoprint API emulation
| Function |
Added? |
Tested? |
| Version information |
✅ |
✅ |
| Server status |
✅ |
✅ |
| Login verification & User information |
✅ |
No |
| Get settings |
✅ |
✅ |
| Octoprint File Upload |
✅ |
✅ |
| Get Job status |
✅ |
✅ |
| Get Printer status |
✅ |
✅ |
| Send GCode command |
✅ |
✅ |
| List Printer profiles |
✅ |
✅ |
History APIs
| Function |
Added? |
Tested? |
| Get job list |
✅ |
✅ |
| Get job totals |
✅ |
✅ |
| Reset totals |
✅ |
✅ |
| Get a single job |
✅ |
✅ |
| Delete job |
✅ |
✅ |
MQTT APIs
| Function |
Added? |
Tested? |
| Publish a topic |
No |
No |
| Subscribe to a topic |
No |
No |
Websocket notifications
Not implemented yet.
Usage
You can check the Test project for more code examples.
Initialize the client
This initialize a new KlipperClient object. Always check if the
client is reachable before using it.
private readonly string _host = "192.168.10.113";
private readonly int _port = 80;
private readonly string _api = "";
private readonly bool _ssl = false;
// Note, the api key is not mandatory
KlipperClient _server = new(_host, _port, _ssl);
await _server.CheckOnlineAsync();
if (_server.IsOnline)
{
await _server.RefreshAllAsync();
Assert.IsTrue(_server.InitialDataFetched);
//var token = await _server.GetOneshotTokenAsync();
KlipperAccessTokenResult token2 = await _server.GetApiKeyAsync();
Assert.IsTrue(!string.IsNullOrEmpty(token2.Result));
}
WebSocket
It's recommended to StartListening() to the WebSocket of your Klipper server.
An example is shown below.
Dictionary<DateTime, string> websocketMessages = new();
KlipperClient _server = new(_host, _api, _port, _ssl);
await _server.CheckOnlineAsync();
Assert.IsTrue(_server.IsOnline);
_server.StartListening();
// Once the Id has been received, subscribe to the printer status objects
_server.WebSocketConnectionIdChanged += (o, args) =>
{
Assert.IsNotNull(args.ConnectionId);
Assert.IsTrue(args.ConnectionId > 0);
Task.Run(async () =>
{
string subResult = await _server.SubscribeAllPrinterObjectStatusAsync(args.ConnectionId);
});
};
_server.Error += (o, args) =>
{
Assert.Fail(args.ToString());
};
_server.ServerWentOffline += (o, args) =>
{
Assert.Fail(args.ToString());
};
_server.WebSocketDataReceived += (o, args) =>
{
if (!string.IsNullOrEmpty(args.Message))
{
websocketMessages.Add(DateTime.Now, args.Message);
Debug.WriteLine($"WebSocket Data: {args.Message} (Total: {websocketMessages.Count})");
}
};
_server.WebSocketError += (o, args) =>
{
Assert.Fail($"Websocket closed due to an error: {args}");
};
// Wait 10 minutes
CancellationTokenSource cts = new(new TimeSpan(0, 10, 0));
_server.WebSocketDisconnected += (o, args) =>
{
if (!cts.IsCancellationRequested)
Assert.Fail($"Websocket unexpectly closed: {args}");
};
do
{
await Task.Delay(10000);
await _server.CheckOnlineAsync();
} while (_server.IsOnline && !cts.IsCancellationRequested);
_server.StopListening();
Assert.IsTrue(cts.IsCancellationRequested);
User auth
If your Klipper server is protected with a login, please call the LoginUserAsync method first.
Alternatively you can provide the API key instead.
string username = "TestUser";
string password = "TestPassword";
KlipperUserActionResult userCreated = await _server.CreateUserAsync(username, password);
Assert.IsNotNull(userCreated);
List<KlipperUser> users = await _server.ListAvailableUsersAsync();
Assert.IsTrue(users?.Count > 0);
KlipperUserActionResult login = await _server.LoginUserAsync(username, password);
Assert.IsNotNull(login);
Assert.IsTrue(login.Username == username);
KlipperUser currentUser = await _server.GetCurrentUserAsync();
Assert.IsNotNull(currentUser);
KlipperUserActionResult newTokenResult = await _server.RefreshJSONWebTokenAsync();
Assert.IsNotNull(newTokenResult);
Assert.IsTrue(_server.UserToken == newTokenResult.Token);
string newPassword = "TestPasswordChanged";
KlipperUserActionResult refreshPassword = await _server.ResetUserPasswordAsync(password, newPassword);
Assert.IsNotNull(refreshPassword);
KlipperUserActionResult logout = await _server.LogoutCurrentUserAsync();
Assert.IsNotNull(logout);
login = await _server.LoginUserAsync(username, newPassword);
Assert.IsNotNull(login);
Assert.IsTrue(login.Username == username);
logout = await _server.LogoutCurrentUserAsync();
Assert.IsNotNull(logout);
KlipperUserActionResult userDeleted = await _server.DeleteUserAsync(username);
Assert.IsNotNull(userDeleted);