HSL Gateway is a high-performance, production-ready gRPC service designed to bridge industrial devices (Siemens, Mitsubishi, Omron, Allen-Bradley, Modbus and 15 more vendors) with modern IT systems. Built on .NET 10 LTS, it leverages the HslCommunication library to poll devices efficiently and exposes real-time data via a gRPC interface.
- Multi-Protocol Support: 75 device types across 20 vendors β Siemens S7/PPI/MPI/Fetch-Write, Modbus TCP/RTU/ASCII/UDP, Mitsubishi MELSEC, Omron, Allen-Bradley, Panasonic, Keyence, Delta, Fatek, Fuji, Inovance, XINJE, LSIS, Beckhoff, GE, Yokogawa, YASKAWA, Toyota, Vigor and MegMeet, over Ethernet or serial. See docs/DeviceTypes.md.
- gRPC Interface: Fast, strongly-typed API for reading tag values and device lists, with server reflection enabled.
- High Performance: In-memory caching (
TagValueCache) ensures low-latency data access. - Background Polling: Dedicated background service (
PollingWorker) handles device communication independently of API requests. - Resilient: Automatic reconnection and error handling for device communication.
- Docker Ready: Includes a multi-stage Dockerfile for easy deployment on Linux/Kubernetes.
- Simulator Included: Comes with a Modbus TCP simulator for testing and verification.
- Scalable: Supports connecting to multiple devices simultaneously with parallel polling.
- Enterprise Ready: Boots with HslCommunication enterprise licenses supplied via environment variables or certificate files.
- Framework: .NET 10 LTS (ASP.NET Core)
- Communication: gRPC (HTTP/2)
- Driver Library: HslCommunication (NuGet)
- Architecture: Clean Architecture with Dependency Injection
- .NET 10 SDK β the exact version is pinned in
global.json - Docker (optional, for containerized deployment)
If you use proto, .prototools already pins the SDK:
proto installgit clone https://github.com/yourusername/HSL-gateway.git
cd HSL-gateway
dotnet restoreStart the simulator (optional, for testing) β it serves three Modbus TCP devices on ports 50502-50504:
dotnet run --project HslSimulator/HslSimulator.csprojThen start the gateway, which listens on port 50051:
dotnet run --project HslGateway/HslGateway.csprojTo run against the simulator with devices and tags already configured, use one of the bundled environments:
ASPNETCORE_ENVIRONMENT=MultiDevice dotnet run --project HslGateway/HslGateway.csprojdotnet test HslGateway.slnHslVerifier is an end-to-end smoke test that exercises read, write, streaming, and
dynamic reconfiguration against a running gateway, and exits non-zero on failure:
HSL_GATEWAY_ADDRESS=http://localhost:50051 dotnet run --project HslVerifierConfigure devices and tags in appsettings.json, or manage them dynamically through the
ConfigManager gRPC service.
The persisted file wins. The gateway seeds from
appsettings.jsononly on first boot, then writes every change todata/gateway-config.jsonand prefers that file from then on. If edits toappsettings.jsonappear to be ignored, delete the persisted file. Its location is set byGatewayPersistence:ConfigFilePath, and the listening port byGateway:GrpcPort.
"Gateway": {
"Devices": [
{
"Id": "siemens_01",
"Type": "SiemensS7",
"Ip": "192.168.1.10",
"Port": 102,
"Rack": 0,
"Slot": 1,
"PollIntervalMs": 1000
},
{
"Id": "modbus_01",
"Type": "ModbusTcp",
"Ip": "127.0.0.1",
"Port": 50502,
"PollIntervalMs": 2000
}
],
"Tags": [
{
"DeviceId": "siemens_01",
"Name": "motor_speed",
"Address": "DB1.0",
"DataType": "double"
},
{
"DeviceId": "modbus_01",
"Name": "line_power",
"Address": "40001",
"DataType": "short"
}
]
}Type names the device family. docs/DeviceTypes.md lists all 75
supported values with their vendor, transport and default port; matching is case-insensitive.
PlcModel selects the vendor series where one applies β Siemens (S200, S200Smart, S300,
S400, S1200, S1500; defaults to S1500), Inovance, XINJE, Delta, Omron and LSIS β and
Rack/Slot apply to Siemens and the CIP drivers. Station carries the unit id β omit it to
accept the protocol's own default, which is not always 1.
Serial types use the serial fields instead of Ip/Port:
{
"Id": "rtu_01",
"Type": "ModbusRtu",
"PortName": "/dev/ttyUSB0",
"BaudRate": 9600,
"DataBits": 8,
"StopBits": 1,
"Parity": 0,
"Station": 1,
"PollIntervalMs": 1000
}DataType accepts bool, short, int, long, float, and double (the default).
The Gateway supports connecting to multiple devices simultaneously. Simply add more entries to the Devices array in appsettings.json.
- Each device runs in its own independent polling loop.
- A slow or disconnected device will not affect the performance of other devices.
- You can mix different protocols and vendors (e.g., a Siemens PLC, a MELSEC PLC and a serial Modbus device) in the same configuration.
The gRPC surface can reconfigure devices and write to PLCs, so it should not be reachable by an unauthenticated caller. Set an API key to require one on every call:
Security__ApiKey=$(openssl rand -hex 32) dotnet run --project HslGateway/HslGateway.csproj"Security": {
"ApiKey": "",
"RequireApiKey": false,
"HeaderName": "x-api-key"
}Clients send it as x-api-key: <key> or authorization: Bearer <key>; calls without a valid
key fail with UNAUTHENTICATED. / and /health stay open so orchestrator probes work.
When ApiKey is empty the gRPC surface is unauthenticated, and the gateway logs a warning
saying so at every startup. That is the default so existing deployments and the simulator
scripts keep working β set RequireApiKey: true in production to make an unauthenticated
instance fail to start instead.
Supply the key through the environment rather than committing it to appsettings.json. There
is no TLS, so put the gateway behind a trusted network or a TLS-terminating proxy; the key
alone does not protect the traffic.
Set EnterpriseLicense in HslGateway/appsettings.json (or the environment-specific file) to enable automatic activation of HslCommunication enterprise features at startup:
"EnterpriseLicense": {
"AutoLoadOnStartup": true,
"CertificateFilePath": "data/hsl-enterprise.cert",
"CertificateBase64EnvironmentVariable": "HSL_ENTERPRISE_CERT_BASE64",
"AuthorizationCodeEnvironmentVariable": "HSL_ENTERPRISE_AUTH_CODE",
"ContactInfo": "ops-team@example.com"
}On boot the gateway applies the first available artifact in this order:
HSL_ENTERPRISE_CERT_BASE64(Base64 string that represents the official HslCommunication certificate file).HSL_ENTERPRISE_AUTH_CODE(plain-text authorization code provided by HslCommunication).- The file path defined by
CertificateFilePath(defaultdata/hsl-enterprise.cert).
If both AutoLoadOnStartup is true and one of the above values exists, EnterpriseLicenseStartupService logs the successful activation and moves on with the normal startup flow. Activation is never fatal: without a license the gateway still starts in community mode. Clear or disable AutoLoadOnStartup to skip the attempt entirely.
A license can also be applied to a running gateway through ConfigManager/ActivateEnterprise,
which optionally persists the certificate to CertificateFilePath.
You can use any gRPC client (C#, Python, Go, Node.js, etc.) or tools like grpcurl. Server reflection is enabled, so no local copy of gateway.proto is needed:
grpcurl -plaintext localhost:50051 listUnknown devices and tags fail with NOT_FOUND; a configured tag that has not been polled yet
returns quality unknown.
Get Tag Value:
grpcurl -plaintext -d '{"deviceId": "modbus_01", "tagName": "line_power"}' localhost:50051 hslgateway.Gateway/GetTagValueList Devices:
grpcurl -plaintext localhost:50051 hslgateway.Gateway/ListDevicesWrite Tag Value:
grpcurl -plaintext -d '{"deviceId": "modbus_01", "tagName": "line_power", "value": 50}' localhost:50051 hslgateway.Gateway/WriteTagValueSubscribe to Tag Value (Streaming):
grpcurl -plaintext -d '{"deviceId": "modbus_01", "tagName": "line_power"}' localhost:50051 hslgateway.Gateway/SubscribeTagValueInteractive bash scripts live under scripts/tests and spin up every component you need for manual verification:
scripts/tests/multi-device.sh: launches three Modbus simulators, the gateway (using theMultiDeviceenvironment), and the multi-device test client (foreground in your terminal) so you can validate polling/subscription across devices. Pass--auto(or setHSL_TEST_AUTO=1) if you need it to run a fully automated demo scenario.scripts/tests/subscription.sh: launches a single simulator, the gateway (using theSubscriptionenvironment), and the subscriber client with a guided flow that mirrors the subscription demo and write tests.
Run them from the repo root using Git Bash, WSL, Linux, or macOS bash. Each script builds the required projects, deletes its environment's persisted config so the scenario is reproducible, starts every process in the same terminal session, and cleans up automatically when you press Ctrl+C.
Build and run the container:
docker build -t hsl-gateway .
docker run -p 50051:50051 -v hsl-data:/app/data hsl-gatewayThe image runs as a non-root user. Mount a volume at /app/data to keep the live
configuration and any persisted certificate across restarts.
The source code in this repository is licensed under the MIT License β see LICENSE.
This does not extend to HslCommunication. That package is proprietary software owned by ζε·θ‘ε·₯η©θη§ζζιε ¬εΈ, distributed under the vendor's own terms, and it supplies every device driver here β the gateway cannot run without it. Review those terms before deploying, particularly for commercial use or redistribution, and note that enterprise features require a license purchased from the vendor. See THIRD-PARTY-NOTICES.md for the full dependency breakdown.