If you're integrating a label printer into a robot cell, an Allen-Bradley PLC step, or an MES workflow, REST is the wrong tool. Polling for job state burns cycles. JSON over HTTP/1.1 burns latency you can't afford on a line running at one unit per second. There is no typed contract to generate clients from. The integrator writes the same string-juggling boilerplate they wrote ten years ago, then writes it again for the next vendor.
The LabelInn Edge Server exposes a typed gRPC surface for exactly this scenario. Four services, server-streaming for live telemetry and job lifecycle events, mTLS for plant-network trust, and a single .proto definition that generates clients in Go, Python, C++, Java, .NET, Rust, and Kotlin in an afternoon.
The four services, in one paragraph each
PrintService — submit, cancel, and reprint jobs; query job state; stream job lifecycle events (queued → printing → completed/failed) to a long-lived caller so a robot controller doesn't poll. Batch submission for end-of-cycle bursts. Each call returns a typed response with a stable job id you carry back into your line's traceability database.
PrinterFleetService — enumerate the printer fleet, get health per printer (status, queue depth, ribbon and label supply levels where the hardware reports them), and stream printer status events so a SCADA HMI can light up a "Printer-A: Low Ribbon" indicator the moment the supply crosses threshold. The stream is the right primitive here: events are sparse and you want immediate fan-out without a polling tax.
VerifyService — accept barcode scan payloads from a fixed scanner or hand scanner, match them against the most recent print, and return a verification verdict. For regulated lines that require scan-to-verify, this closes the loop without a separate verification application sitting between the printer and the scanner.
SystemService — health, version, capability discovery, and a heartbeat for monitoring. The thing every integrator wires up first and forgets about.
Why typed beats stringly-typed when robots are involved
In a robot cell, errors are physical. A misrouted label means a misrouted part means a stop and a manual recovery. The cost of a stringly-typed integration where a typo in a JSON key silently does the wrong thing is measured in production hours.
gRPC's typed protobuf schema makes whole classes of error impossible:
- A field that doesn't exist on the wire is a compile error in the generated client, not a runtime
null. - An enum value the server has but the client doesn't is surfaced as an explicit "unknown" rather than silently coerced to a default.
- Required fields are required; the generated client refuses to construct an invalid request.
- Streaming methods are first-class; you don't get to forget that a job lifecycle is event-driven and accidentally poll a status endpoint in a hot loop.
For an integrator who has to defend their integration in a Quality review, "the generated client cannot construct a malformed request" is a real answer.
The integration patterns we see most often
1. PLC step calls SubmitJob from ladder logic
An Allen-Bradley CompactLogix or Siemens S7-1500 in the cell can speak gRPC through a side-car (a Linux IPC running on a Raspberry Pi or a small industrial PC, exposing a Modbus / Ethernet/IP interface to the PLC and gRPC outward). The side-car holds the typed gRPC client. The PLC step writes the order id and template id into shared memory, raises a "request print" bit, the side-car calls SubmitJob and writes the returned job id back. The PLC step waits on a "print complete" bit that the side-car raises when the server-stream emits a completed event for that job id.
Cycle time: typically 60–150 ms from PLC bit raise to PLC bit lowered, depending on printer warm-up. Compatible with one-unit-per-second lines without dropping behind.
2. MES (Wonderware, Ignition, FactoryTalk) directly
Modern MES platforms speak gRPC natively or via a generated client. Ignition's scripting environment, for example, generates Java clients from a .proto and uses them in tag-change scripts. The MES batches print submissions, watches the job stream, and reconciles the resulting label production against the work order in real time. The Quality Manager's MES dashboard sees a "labels printed: 412 / 412" green tick without any polling.
3. Robot cell controller (Fanuc, ABB, KUKA)
Robot controllers in 2026 ship with an open-platform Linux side-car (RoboDK, Fanuc PMC Plus, ABB RobotWare 7's IRC5/OmniCore extension). The side-car holds the gRPC client. The robot's TPP program calls a controller function that wraps the gRPC call. The streaming print-lifecycle event drives the robot's hand-off arbitration: don't release the part to downstream until the label is confirmed printed and verified.
Server-streaming, mTLS, backpressure
The two server-streaming methods (PrintService.StreamEvents, PrinterFleetService.StreamPrinterStatus) are the ones that justify gRPC vs. REST for this domain. Both:
- Run over long-lived HTTP/2 streams with native flow control, so a slow consumer doesn't melt the server.
- Carry typed event payloads with a discriminated union schema (printer-online, printer-error, ribbon-low, job-queued, job-completed, job-failed, etc.).
- Survive transient TCP resets via gRPC's connection-management primitives, so a brief network blip on the plant LAN does not lose events on the floor.
For trust on a plant network, the server supports mTLS: the edge node trusts only client certificates signed by the customer's chosen CA. For an environment where the plant network is already segmented and TLS termination happens at a perimeter device, API-key authentication in gRPC metadata is also supported.
How to get the .proto and a starter client
The labelinn_edge.proto definition is available to enterprise customers under a permissive integration license. After a brief discovery call we send the proto plus a starter client in your language of choice, pre-wired against an evaluation tenant. Most integrators are submitting their first job within an hour.
Generate Your Client in an Afternoon
Industrial automation engineers — request the proto, the starter client in your language, and an evaluation tenant to point it at.
Request the .proto →