Bypass vendor lock-in for PLC dashboards with 120 lines of code


Say you’ve got a legacy app that’s used at your large enterprise that shows you a few values on an old wrinkly dashboard — with no other option than just seeing that value or exporting a PDF report of historical data.

Just as well let’s say the vendor of the solution is now charging you an arm and a leg to update that dashboard, add new PLCs and add basic functionalities like graphing, you could plan ahead — prepare your budget and go with the vendor that locked you in, or you could use tools used by giants to avoid that, get rid of vendor lock-in and own your data.

Let’s talk about the second option, because I have no experience with the first one.

What’s a PLC? A glorified, hardened and fast controller with a variety of inputs/outputs that you can program to do operations (the name stands for Programmable Logic Controller), in a very simple manner of saying. They’re often used to control industrial equipment ranging from water flow sensors, chlorination stations or even nuclear plants.

Usually very proprietary software controls and programs such devices with a possibility of quite a few protection layers including at the hardware level for anything from hacking to reverse engineering.

Enough about that, let’s get to the data retrieval part.

First of all you need to know where your PLC is — specifically the RACK and SLOT, you can find this in both the PLC programming software, or you can dig around the legacy app and find the information.

After you’ve isolated that, you need to figure out where your data is — specifically the DB Number, the Address at which the information starts, and the Size of the information.

Your data could lie in DB2234, at an offset of 10 bits and have a size of 4 bits, for example. All of this could be found in the said proprietary software suite or the legacy software config files.

type PLC struct {
 Name    string `json:"name"`
 Desc    string `json:"desc"`
 IP      string `json:"ip"`
 Rack    int    `json:"rack"`
 Slot    int    `json:"slot"`
 Address int    `json:"address"` // This is the DB Number
 Start   int    `json:"start"` // This is the Address
 Size    int    `json:"size"` // This is the length of the data
// This is all you need to get data.

I chose to use Golang and this very useful library to scrape the data from a number of PLCs, then followed the Prometheus instrumenting documentation to expose those metrics and scrape them into Prometheus, less than 120 lines of code later — the metrics were being exported.

Finally we ended up with a nice dashboard in Grafana that allows us fine grained control over the data and enables us to do visualization of historical data, comparisons, and generally doesn’t lock us in to a specific vendor or exorbitant pricing for modifications.

That part is the easy one, the tips that’ll save you a lot of time are as follows:

  • look for the program blocks, those will show you how the data is getting composed and outputted — sometimes you’ll need a scaling factor to get the real value (since the PLC reads analog voltages, not actual human values)
  • data types are sneaky, sometimes it’s a float32, sometimes it’s a float64

This is by no means something new or amazing, and there’s a great talk by Toby Varland of Varland Plating (whose image I stole above) about using Grafana and InfluxDB for the same purpose, possibly in a better way than I did.

In an ideal world I would’ve made use of Grafana Live and a datasource plugin to have actual real-time data, but this checkmarks the 80/20 rule and is better than nothing, for now. The art of making high priority into low priority into tech debt.

I wish you the best of luck in trying to save your company a ton of money by using this “simple trick.”