Linux · macOS · Windows · self-hosted

One gRPC API for
every industrial protocol.

A single Rust binary that speaks Modbus, OPC UA, EtherNet/IP, Siemens S7, DNP3, BACnet/IP, and MQTT, and exposes them all behind one typed gRPC surface. Read, write, and subscribe to tags on any PLC with one client.

$49.99
One-Time
7
Protocols
Typed
Values Preserved
3 OS
Linux · macOS · Windows

Stop writing a different client for every PLC.

Every industrial protocol has its own wire format, addressing scheme, and quirks. The gateway absorbs all of that: your application talks one gRPC API and the gateway drives the device.

The same protocol logic gets re-implemented in every SCADA, HMI, and edge collector. Voltrus Gateway makes the mt-* crates (the engines powering the Voltrus explorer apps) the single canonical implementation. SCADA shrinks to SCADA concerns; protocol bugs get fixed once.

FIELD DEVICES Modbus TCPOPC UAEtherNet/IPSiemens S7DNP3BACnet/IPMQTT 7 protocols Voltrus Gateway Rust binary · stateless typed gRPC Your application SCADA · cloud · edge service one gRPC client
One gateway absorbs every protocol: your app speaks a single typed gRPC API instead of seven different clients.

One client. Any device. Any protocol.

Point the gateway at a device and talk to it over gRPC. Connect, read or write typed tag values, then subscribe for live updates. The same three calls regardless of protocol.

01 / CONNECTOpenSessionpoint at any device→ session_id02 / READ · WRITEReadTags · WriteTagtyped, type-preserving→ typed Value03 / SUBSCRIBESubscribeTagsserver-streamed batches→ stream updates session_id threads every call
Same three calls regardless of protocol: open a session, read or write typed values, then subscribe for live updates.
01 / Connect

Open a session

Point the gateway at a device: Modbus TCP, OPC UA endpoint, EtherNet/IP PLC, S7 CPU, DNP3 outstation, or BACnet controller. The gateway holds the connection and speaks the native wire protocol.

02 / Read · Write

Typed tag values

Call ReadTags or WriteTag over gRPC. Values carry bool, int, float, double, string, and bytes plus a source type. A CIP DINT or an OPC UA string round-trips intact, never flattened to a number.

03 / Subscribe

Live updates

Subscribe to tags and receive live server-streamed batches. No polling loop to maintain on the client. The gateway pushes deltas as devices change.

A single binary that replaces a stack of clients.

One canonical, cross-platform implementation of every protocol your plant uses, self-hosted, type-preserving, with native streaming subscriptions.

01

One binary, seven protocols

Modbus TCP, OPC UA, EtherNet/IP (CIP), Siemens S7, DNP3, BACnet/IP, and MQTT, all over the same API.

02

Type-preserving values

Tag values carry bool, int, float, double, string, and bytes plus a source type. A CIP DINT or an OPC UA string round-trips intact, not flattened to a number.

03

Streaming subscriptions

Subscribe to tags and receive live server-streamed batches, no polling loop to maintain on the client.

04

Self-hosted & cross-platform

A single static binary for Linux, macOS, and Windows. Run it at the edge, in a container, or beside your SCADA. No per-tag licensing.

05

One canonical implementation

The same mt-* engines that power the Voltrus explorer apps. Protocol bugs get fixed once, everywhere.

06

Discover & browse

Browse tags and discover devices over the same gRPC surface. No separate tooling to map out a PLC's tag namespace.

Read, write, and subscribe on every protocol below.

Full read, write, and subscribe on seven industrial protocols, all over the same gRPC surface.

Modbus TCPread · write · subscribe
OPC UAread · write · subscribe
EtherNet/IP (CIP)read · write · subscribe
Siemens S7read · write · subscribe
BACnet/IPread · write · subscribe
DNP3read · write · subscribe
MQTTpublish · read · subscribe
# one client, any device — the full gRPC surface
rpc OpenSession(ConnectRequest)     -> ConnectResponse
rpc ReadTags(ReadTagsRequest)       -> ReadTagsResponse
rpc WriteTag(WriteTagRequest)       -> WriteResult
rpc SubscribeTags(SubscribeRequest) -> stream TagUpdateBatch
rpc Discover(DiscoverRequest)       -> DiscoverResponse

Talk to the gateway from your own code.

Official Python and TypeScript gRPC clients live in the source repository under gateway/sdks/, not on PyPI or npm yet. They wrap the typed API the gateway exposes: server-side sessions, reads and writes of type-preserving tag values, tag browsing, and streaming subscriptions. Where the SCADA SDKs speak REST to the SCADA server, these speak gRPC to the lightweight 24/7 protocol layer.

Subscribe once and the gateway pushes an initial batch, then sends a new one only when a value or its quality changes. Polls that fail while a device is down arrive as per-tag errors and quality stamps instead of killing the stream, and values return when the device recovers. Both SDKs ship a subscribe_24x7 example with reconnect and backoff for unattended use.

Python SDK

A thin wrapper over the generated gRPC stubs, committed so no protoc is needed. Dicts in, proto values out; only grpcio and protobuf as dependencies.

git clone https://github.com/dzulfikar08/MacTools.git
cd MacTools/gateway/sdks/python && pip install -e .
from voltrus_gateway import VoltrusGateway

with VoltrusGateway("http://127.0.0.1:50061") as gw:
    session = gw.connect("modbus", ip="192.168.1.10", unit_id=1, endianness="big")

    tags = [{"name": "temperature", "address": 0, "reg_type": "float32",
             "register_area": "holding"}]
    for tv in gw.read_tags(session, tags):
        print(tv.tag.modbus.name, tv.value.double_val, tv.quality)

    gw.write_tag(session, tags[0], 72.5)   # -> WriteResult(success, error, latency_ms)
    gw.disconnect(session)

Source: gateway/sdks/python in github.com/dzulfikar08/MacTools

TypeScript SDK

The same gRPC surface with plain objects in and typed messages out. Only @grpc/grpc-js and @bufbuild/protobuf as runtime dependencies, and connect configs are compile-time checked per protocol.

git clone https://github.com/dzulfikar08/MacTools.git
cd MacTools/gateway/sdks/typescript && npm install
import { VoltrusGateway, valueOf } from "voltrus-gateway";

const gw = new VoltrusGateway("http://127.0.0.1:50061");
const session = await gw.connect("modbus", { ip: "192.168.1.10", unitId: 1, endianness: "big" });

const tags = [{ name: "temperature", address: 0, regType: "float32", registerArea: "holding" }];
for (const tv of await gw.readTags(session, tags)) {
  console.log(tv.tag.modbus?.name, valueOf(tv.value), tv.quality);
}

await gw.writeTag(session, tags[0], 72.5);   // -> WriteResult { success, error, latencyMs }
await gw.disconnect(session);
gw.close();

Source: gateway/sdks/typescript in github.com/dzulfikar08/MacTools

Driving the SCADA server instead? See its SDKs.

Perpetual license

Stop writing a client
for every protocol.

$49.99
One-time · one license = one host

A commercial product: not open source, not a subscription. Buy it once and run it forever. Each license covers a single host: a workstation, a server, an edge box, or a VM.

Buy a license: $49.99 → Read the docs

Questions engineers ask.

A single Rust binary that unifies industrial protocols (Modbus, OPC UA, EtherNet/IP, Siemens S7, DNP3, BACnet/IP, and MQTT) behind one typed gRPC API. Instead of writing a different client for every protocol, you talk to the gateway once and read, write, and subscribe to tags on any PLC.
No. Voltrus Gateway is a commercial product. It is a one-time purchase of $49.99. No subscription, no per-tag licensing, no recurring fees.
One license covers one host: a PC, a server, or any single machine that runs the gateway binary. Buy a license per host you deploy on. A license is perpetual: buy once, run forever.
Modbus TCP, OPC UA, EtherNet/IP (CIP), Siemens S7, DNP3, BACnet/IP, and MQTT all ship with full read, write, and subscribe support over the same gRPC surface.
Kepware is a Windows-only, licensed OPC server. Voltrus Gateway is a cross-platform, self-hosted binary exposing a modern typed gRPC API with native streaming subscriptions. No per-tag licensing and no Windows requirement.
Yes. Tag values are carried as a rich oneof (bool, int32, int64, uint32, float, double, string, and bytes) plus a source_type string, so a CIP DINT or an OPC UA string round-trips without being flattened to a number.

Stay Updated

Get notified about gateway updates & new protocols

MQTT broker support, new protocols, and API updates land regularly. No spam, only product news.