This library is under active development and NOT ready for production use.
Feature Parity: 28% complete (see ROADMAP.md)
Progress: [█████░░░░░░░░░░░░░░░] 28%
- Requires Zig 0.15.2
- See branch/tag history for previous Zig versions
- APIs are unstable and subject to change
This wrapper aims to make working with open62541 feel native to Zig by:
- Memory Safety - Proper allocator usage, clear ownership semantics, no manual memory management
- Zig Idioms - Error return types, tagged unions, comptime features instead of C conventions
- Type Safety - Strongly-typed wrappers eliminating void pointers and C-style type erasure
- Abstraction - Hide C complexities like bitfields, null-terminated strings, and manual struct initialization
This library will not reach full feature parity with open62541 for some time. If you need functionality that isn't yet wrapped, please open an issue!
Server:
- Server lifecycle (init, start, stop, iterate, runUntilInterrupt)
- Variable nodes (add with full attribute control)
- Object nodes (add with attributes)
- Namespace management (add, lookup by name/index)
- Custom server configuration (port, security mode)
Client:
- Client lifecycle (init, connect, disconnect)
- Read operations (readValueAttribute)
- Write operations (writeValueAttribute)
- Browse operations (browse, browseNext with full control)
- Custom client configuration (timeout, security mode)
Data Types:
- NodeId (numeric, string, GUID, bytestring)
- Variant (scalars and arrays for all basic types)
- QualifiedName, LocalizedText, ExpandedNodeId
- VariableAttributes, ObjectAttributes
- Browse types and masks
- Comprehensive error types
- Subscriptions & monitored items (high priority)
- Method calls (medium priority)
- Events & alarms (medium priority)
- Server-side read/write operations
- Client node management
- History access
- PubSub
- Security & certificates
- Discovery services
See ROADMAP.md for detailed progress tracking.
📚 View the full API documentation
Guides:
- Examples Guide - Complete examples for common operations
- Memory Policy - Understanding memory management
- Roadmap - Feature parity tracking
Add zopcua to your project:
zig fetch --save git+https://github.com/xentropic-dev/zopcua.gitThen in your build.zig:
const std = @import("std");
const zopcua = @import("zopcua");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "my-app",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
}),
});
// Add zopcua - automatically handles module import and platform-specific linking
zopcua.setup(exe, .{});
b.installArtifact(exe);
}That's it! The setup function automatically:
- Adds the
uamodule to your executable - Links required system libraries (ws2_32, advapi32, crypt32, bcrypt on Windows)
- Links required frameworks (Security, CoreFoundation on macOS)
- Handles all platform-specific configuration
zopcua requires mbedTLS for cryptographic operations and secure communication. By default, mbedTLS is statically linked from vendored sources - no system installation required.
If you prefer to use system-installed mbedTLS libraries instead:
zopcua.setup(exe, .{
.mbedtls = .system, // Use system mbedTLS instead of vendored
});When using system mbedTLS, ensure the libraries are installed:
- macOS:
brew install mbedtls - Ubuntu/Debian:
sudo apt install libmbedtls-dev - Other Linux: Use your distribution's package manager
const std = @import("std");
const ua = @import("ua");
pub fn main() !void {
var server = try ua.Server.init();
defer server.deinit();
try server.runUntilInterrupt(); // Blocks until Ctrl-C
}const std = @import("std");
const ua = @import("ua");
pub fn main() !void {
var server = try ua.Server.init();
defer server.deinit();
_ = try server.addVariableNode(
ua.NodeId.initString(1, "temperature"),
ua.StandardNodeId.objects_folder,
ua.ReferenceType.organizes,
ua.QualifiedName.init(1, "Temperature"),
ua.StandardNodeId.base_data_variable_type,
.{
.value = ua.Variant.scalar(f64, 23.5),
.display_name = ua.LocalizedText.init("en-US", "Temperature"),
.access_level = .{ .read = true, .write = true },
},
);
try server.runUntilInterrupt();
}const std = @import("std");
const ua = @import("ua");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var client = try ua.Client.init();
defer client.deinit();
try client.connect("opc.tcp://localhost:4840");
defer client.disconnect() catch {};
const node_id = ua.NodeId.initString(1, "temperature");
const variant = try client.readValueAttribute(allocator, node_id);
defer variant.deinit(allocator);
std.debug.print("Temperature: {d}\n", .{variant.double});
}See docs/EXAMPLES.md for more examples including writing values, browsing, arrays, objects, namespaces, and error handling.
# Build the library (uses vendored mbedTLS by default)
zig build
# Build with system mbedTLS
zig build -Dmbedtls=system
# Run tests
zig build test
# Generate documentation
zig build docsThis wrapper library is licensed under the MIT License. See LICENSE for details.
The underlying open62541 library is licensed under the Mozilla Public License 2.0. See the open62541 repository for details.
Contributions are welcome! Here's how you can help:
- Check ROADMAP.md to see what features need implementation
- Look for missing features - The library is at 28% parity with open62541, lots to do!
- Submit PRs with new features, bug fixes, or improved documentation
- Open issues for features you need or bugs you encounter
- Add tests for new functionality
- Subscriptions & monitored items
- Method calls
- Server-side read/write operations
- Client node management
- Additional attribute operations
See the roadmap for a complete breakdown of missing features.