gRPC interface for LinuxCNC machine control and HAL (Hardware Abstraction Layer).
LinuxCNC's native Python API only works locally. This project exposes it over gRPC, enabling:
- Remote monitoring - Build web dashboards, mobile apps, or desktop GUIs
- Multi-machine management - Monitor a fleet of CNC machines from one place
- Any-language integration - Use Go, Node.js, Rust, or any gRPC-supported language
- Real-time streaming - Subscribe to status updates instead of polling
The server runs on your LinuxCNC machine and exposes the gRPC interface.
pip install linuxcnc-grpc
# or with uv
uv pip install linuxcnc-grpclinuxcnc-grpc --host 0.0.0.0 --port 50051LinuxCNC must already be running before starting the server.
To start the gRPC server automatically when LinuxCNC launches, add to your machine's HAL file:
# Start gRPC server (runs until LinuxCNC exits)
loadusr linuxcnc-grpc --host 0.0.0.0 --port 50051
Or use a dedicated HAL file via your INI:
[HAL]
POSTGUI_HALFILE = grpc-server.halpip install linuxcnc-grpcimport grpc
from linuxcnc_pb import linuxcnc_pb2, linuxcnc_pb2_grpc
channel = grpc.insecure_channel("localhost:50051")
stub = linuxcnc_pb2_grpc.LinuxCNCServiceStub(channel)
status = stub.GetStatus(linuxcnc_pb2.GetStatusRequest())
print(f"Position: X={status.position.x:.3f} Y={status.position.y:.3f} Z={status.position.z:.3f}")go get github.com/dougcalobrisi/linuxcnc-grpcimport (
pb "github.com/dougcalobrisi/linuxcnc-grpc/packages/go"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
conn, _ := grpc.NewClient("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials()))
client := pb.NewLinuxCNCServiceClient(conn)
status, _ := client.GetStatus(context.Background(), &pb.GetStatusRequest{})
fmt.Printf("Position: X=%.3f Y=%.3f Z=%.3f\n", status.Position.X, status.Position.Y, status.Position.Z)npm install linuxcnc-grpcimport * as grpc from "@grpc/grpc-js";
import { LinuxCNCServiceClient, GetStatusRequest } from "linuxcnc-grpc";
const client = new LinuxCNCServiceClient("localhost:50051", grpc.credentials.createInsecure());
client.getStatus(GetStatusRequest.create(), (err, status) => {
console.log(`Position: X=${status.position.x.toFixed(3)} Y=${status.position.y.toFixed(3)}`);
});[dependencies]
linuxcnc-grpc = "1.0"
tokio = { version = "1", features = ["full"] }
tonic = "0.12"use linuxcnc_grpc::linuxcnc::linux_cnc_service_client::LinuxCncServiceClient;
use linuxcnc_grpc::linuxcnc::GetStatusRequest;
let mut client = LinuxCncServiceClient::connect("http://localhost:50051").await?;
let status = client.get_status(GetStatusRequest {}).await?.into_inner();
println!("Position: X={:.3} Y={:.3}", status.position.unwrap().x, status.position.unwrap().y);Complete examples for all supported languages:
| Example | Description | Python | Go | Node.js | Rust |
|---|---|---|---|---|---|
get_status |
Poll machine status | view | view | view | view |
stream_status |
Real-time status streaming | view | view | view | view |
jog_axis |
Jog axes with keyboard | view | view | view | view |
mdi_command |
Execute G-code via MDI | view | view | view | view |
hal_query |
Query HAL pins/signals | view | view | view | view |
upload_file |
Upload, list, delete G-code files | view | view | view | view |
See examples/README.md for setup instructions.
- LinuxCNCService - Machine control: status, jogging, MDI, program execution, file management
- HalService - HAL introspection: query pins, signals, parameters (read-only)
The server provides UploadFile, ListFiles, and DeleteFile RPCs for remote G-code file management. Files are stored in the NC files directory (default: /home/linuxcnc/linuxcnc/nc_files).
Configure the directory with --nc-files or the LINUXCNC_NC_FILES environment variable:
linuxcnc-grpc --host 0.0.0.0 --nc-files /path/to/nc_filesThis server provides remote control of CNC machinery. Ensure proper safety measures:
- Use only on trusted networks
- Implement authentication in production (gRPC supports TLS/mTLS)
- Never leave machines unattended during remote operation
- Verify E-stop and safety systems are functional
For production use, enable TLS authentication:
# Server with TLS
credentials = grpc.ssl_server_credentials([(private_key, certificate)])
server.add_secure_port('[::]:50051', credentials)# Client with TLS
credentials = grpc.ssl_channel_credentials(root_certificates)
channel = grpc.secure_channel('your-machine:50051', credentials)See Server Configuration for complete TLS setup instructions.
Requires uv for Python dependency management:
# Install dev dependencies
make setup
# Run tests
make test # Python tests
make test-all # All languages
# Generate proto code
make proto-all # Regenerate for all languagesSee CLAUDE.md for detailed development documentation.