Driver SDK Reference
Build device drivers for Muxit as standalone .NET class libraries (Tier 3) or as JavaScript modules (Tier 1). C# drivers implement IConnectorDriver from the shared SDK. JS drivers export a default object with meta, init, get, set, execute, and shutdown methods.
Driver Tiers
| Tier | Type | Location | Status |
|---|---|---|---|
| 0 | Built-in (C#) | Compiled into MuxitServer | Always available |
| 1 | JavaScript | workspace/drivers/*.driver.js | Active (sandboxed V8) |
| 2 | SCPI | workspace/drivers/*.scpi | Disabled |
| 3 | DLL Extension (C#) | workspace/drivers/free/ or premium/ | Active |
JS Drivers (Tier 1)
Structure
export default {
meta: {
name: "MyDriver",
version: "1.0.0",
description: "Short description of what this driver does.",
group: "instruments", // DriverGroup: "instruments", "motion", "communication", "utilities"
properties: { voltage: { type: "number", access: "rw", unit: "V", description: "Output voltage" } },
actions: { reset: { description: "Reset device" } },
streams: ["output"],
},
async init(config) { /* set up transport, initialize device */ },
async get(property) { /* return property value */ },
async set(property, value) { /* set property value */ },
async execute(action, args) { /* execute action, return result */ },
async shutdown() { /* clean up */ },
};Available APIs
| API | Description |
|---|---|
createTcpTransport(host, port, opts) | Create TCP transport ({ delimiter, timeout }) |
createSerialTransport(path, opts) | Create serial transport ({ baudRate, delimiter, timeout }) |
__emitStream(stream, data) | Emit streaming data |
log.debug/info/warn/error(...) | Logging |
timestamp() | ISO timestamp string |
Security Sandbox
JS drivers run in an isolated ClearScript V8 engine with these restrictions:
require(),import()— blockedprocess,global— deleted fromglobalThis- No access to
fs,net,child_process, or any Node.js APIs - Path traversal —
.driver.jsfiles must reside withinworkspace/drivers/ - Name collision — JS drivers cannot shadow built-in (Tier 0) driver names
Built-in Drivers (Tier 0)
| Driver | Name | Description |
|---|---|---|
WebcamDriver | Webcam | USB webcam capture via OpenCV |
OnvifDriver | Onvif | ONVIF IP camera discovery, streaming, PTZ |
TestDriver | TestDevice | Test/example driver exercising all features |
FileAccessDriver | FileAccess | Sandboxed file I/O restricted to a base directory |
MqttBridgeDriver | MqttBridge | MQTT broker bridge (ESP32, Arduino, Home Assistant, Node-RED) |
VisionDriver | Vision | Computer vision (OpenCV detection, color/contour tracking) — license-gated |
FileAccess Driver
Provides read/write/list/delete operations sandboxed to a single directory (typically workspace/data/).
Config:
| Key | Type | Default | Description |
|---|---|---|---|
basePath | string | (required) | Root directory for file operations |
maxFileSizeMB | int | 10 | Max file size for read/write in MB |
createIfMissing | bool | true | Create base directory if missing |
Actions:
| Action | Args | Returns | Description |
|---|---|---|---|
listFiles | path? | string[] | List files (relative paths) |
readText | path | string | Read text file |
writeText | path, content | "OK" | Write text file |
appendText | path, content | "OK" | Append to text file |
deleteFile | path | "OK" | Delete a file |
rename | from, to | "OK" | Rename/move within sandbox |
fileInfo | path | object | File metadata |
C# Drivers (Tier 3)
Quick Start
- Copy
drivers/Muxit.Driver.Template/todrivers/Muxit.Driver.YourDevice/ - Rename in
.csproj:<AssemblyName>YourDevice</AssemblyName> - Implement your driver logic
- Build:
dotnet build drivers/Muxit.Driver.YourDevice -c Release - Copy
YourDevice.dlltoworkspace/drivers/free/ - Test:
node start.js cli, thenscanandinit YourDevice
IConnectorDriver Interface
public interface IConnectorDriver
{
string Name { get; }
string? Version => null;
string? Description => null; // Human-readable driver description
Task InitAsync(Dictionary<string, object?>? config);
Task ShutdownAsync();
IEnumerable<PropertyDescriptor> GetProperties();
IEnumerable<ActionDescriptor> GetActions();
Task<object?> GetAsync(string property);
Task SetAsync(string property, object? value);
Task<object?> ExecuteAsync(string action, object? args);
bool SupportsStreaming => false;
IEnumerable<string> GetStreams() => [];
Action<string, string>? StreamEmitter { get; set; }
}DriverGroup Enum
Every driver should declare a group for UI categorization using the [DriverGroup] attribute:
using Muxit.Driver.Sdk;
[DriverGroup(DriverGroup.Instruments)]
public sealed class MyDriver : IConnectorDriver { ... }| Value | Description |
|---|---|
DriverGroup.Instruments | Measurement devices (oscilloscopes, multimeters, spectrometers) |
DriverGroup.Motion | Robots, CNC, stages, actuators |
DriverGroup.Communication | Serial monitors, MQTT bridges, protocol adapters |
DriverGroup.Utilities | Test devices, file access, vision, general-purpose |
For JS drivers, set meta.group to the lowercase enum name (e.g., "instruments", "motion").
Lifecycle
- Constructor — must be parameterless and public. Do NOT open connections here.
- InitAsync(config) — open connections, start background tasks
- GetAsync / SetAsync / ExecuteAsync — normal operation
- ShutdownAsync — release all resources
Property Types
| Type string | C# type (Get) | C# type (Set) |
|---|---|---|
"string" | string | string |
"int" | int | int |
"double" | double | double |
"bool" | bool | bool |
"double[]" | double[] | object?[] |
"object" | Dictionary<string, object?> | Dictionary<string, object?> |
Automatic type conversion: All driver return values are automatically converted to native JavaScript types when accessed from connector configs or scripts. C# double[] becomes a JS array you can .map(), .filter(), or spread (...). C# Dictionary<string, object?> becomes a plain JS object. No manual conversion is needed in connector or script code.
Access Modes
| Access | Meaning |
|---|---|
"R" | Read-only |
"R/W" | Read-write |
"W" | Write-only |
Config Helpers
using static Muxit.Driver.Sdk.DriverConfig;
public Task InitAsync(Dictionary<string, object?>? config)
{
var host = GetString(config, "ip", "192.168.1.100");
var port = GetInt(config, "port", 5000);
var timeout = GetDouble(config, "timeout", 30.0);
var verbose = GetBool(config, "verbose", false);
}Actions & Arguments
Actions are declared with ActionDescriptor. Each argument is described with ArgDescriptor(name, type, description):
public IEnumerable<ActionDescriptor> GetActions() => new[]
{
new ActionDescriptor("reset", "Reset to factory defaults"),
new ActionDescriptor("moveTo", "Move to position", [
new ArgDescriptor("x", "double", "X coordinate in mm"),
new ArgDescriptor("y", "double", "Y coordinate in mm"),
new ArgDescriptor("z", "double", "Z coordinate in mm"),
]),
};Descriptors:
// Property: name, type, access, unit, description
public record PropertyDescriptor(string Name, string Type, string Access,
string Unit = "", string Description = "");
// Action argument: name, type, description
public record ArgDescriptor(string Name, string Type, string Description = "");
// Action: name, description, args
public record ActionDescriptor(string Name, string Description = "",
List<ArgDescriptor>? Args = null);Streaming
public bool SupportsStreaming => true;
public IEnumerable<string> GetStreams() => new[] { "data", "video" };
public Action<string, string>? StreamEmitter { get; set; }
// Emit from background thread:
StreamEmitter?.Invoke("data", jsonString);Minimal Driver Example
using Muxit.Driver.Sdk;
using static Muxit.Driver.Sdk.DriverConfig;
namespace Muxit.Driver.YourDevice;
public sealed class YourDeviceDriver : IConnectorDriver
{
public string Name => "YourDevice";
public string? Version => "1.0.0";
public string? Description => "Your device description for documentation and AI.";
public Action<string, string>? StreamEmitter { get; set; }
public Task InitAsync(Dictionary<string, object?>? config)
{
var host = GetString(config, "host", "localhost");
return Task.CompletedTask;
}
public Task ShutdownAsync() => Task.CompletedTask;
public IEnumerable<PropertyDescriptor> GetProperties() => new[]
{
new PropertyDescriptor("value", "double", "R", "", "Current reading"),
};
public IEnumerable<ActionDescriptor> GetActions() => Array.Empty<ActionDescriptor>();
public Task<object?> GetAsync(string property) => property switch
{
"value" => Task.FromResult<object?>(42.0),
_ => throw new ArgumentException($"Unknown property: {property}"),
};
public Task SetAsync(string property, object? value) =>
throw new ArgumentException($"Property '{property}' is read-only");
public Task<object?> ExecuteAsync(string action, object? args) =>
throw new ArgumentException($"Unknown action: {action}");
}Building & Testing
# Build all drivers
node build.js drivers
# Build specific driver
dotnet build drivers/Muxit.Driver.YourDevice -c Release
# Test with CLI
node start.js cli
# Then: scan, init, get, set, exec, meta, shutdownProject Structure
drivers/
├── Muxit.Driver.Sdk/ # Shared SDK
├── Muxit.Driver.Template/ # Reference implementation
├── Muxit.Driver.Fairino/ # Robot driver
├── Muxit.Driver.Avantes/ # Spectrometer driver
├── Muxit.Driver.Scpi/ # Generic SCPI instrument driver
└── Muxit.Driver.YourDevice/
├── Muxit.Driver.YourDevice.csproj
└── YourDeviceDriver.csFree vs Premium Drivers
| Type | Signed? | License? | Who builds? |
|---|---|---|---|
| Official (free) | Yes | No | Muxit team |
| Official (premium) | Yes | Yes | Muxit team |
| Third-party (free) | No | Never | Anyone |
Free drivers are always free. Build the DLL, drop it in workspace/drivers/free/, done.