In theory, it all sounds easy: there’s a PLC, there are signals, we read them and analyze. In practice, you’re faced with hundreds and thousands of addresses, some clearly labeled, some as if meant for people with telepathy, and some live somewhere inside the logic.
And that’s where diagnostics begin.

A Signal is Not Just 0 or 1
The first thing I had to accept: the same value 1 for different signals can mean completely different things.
Conditionally:
X— PLC inputs. Often these are sensors, buttons, emergency circuits, limit switches.Y— PLC outputs. This is not a sensor, but the state of the output command.M— internal bits, including alarms and events.D,W,GD— registers and words, where parameters, states, analog values, and other "non-bit" stories can be found.L/Mwithin ladder logic — a separate pain, because this may not be a physical signal, but an intermediate condition.
The most dangerous mistake is to look at the address and immediately draw a conclusion. For example, if Y320 = 1, it doesn’t mean we turned something on. It only means: the PLC keeps the output command on. We read it. We don’t write, we don’t force, we don’t control.
This is an important boundary, especially on real equipment.
First, I Built a Map of the World
There was a lot of data: dumps, Excel files, signal maps, traces from interfaces, fragments of logic. I didn’t try to immediately turn all this into a production collector. First, I did something more boring but useful: I organized the signals into directories and preserved the connection to the original lines.
One of the raw indexes ended up with 4710 records:
X: 372Y: 287M: 450D: 3393W: 188GD: 20
But reading everything indiscriminately is a bad idea. Such an index is needed more as an audit: where the address came from, what the original line was, what the confidence was, what the priority was. If later two books argue with each other, you can return to the source instead of guessing from memory.
After additional documents, the directories were refined. For example, one additional X remained for the inputs, which came from the electrical diagram. For alarms, M, a new bit appeared outside the main range — M6475, as a hypothesis from active tracing. A few error registers were added to the analog layer.
So, the final summary map didn’t provide new physical inputs/outputs, but it helped verify that the current directories were not falling apart.
The Most Useful Layer — Alarms
A separate large part of the work was around M bits of alarms and events.
At first, these were just addresses. For example:
M6001 = 1
How to diagnose this? No way, if there’s no context. At most, you can say: “some M-bit turned on.” For a person at the machine, this is almost useless.
So, I enhanced the alarm directory:
- added human-readable texts for alarms;
- categorized the alarms;
- added an interface screen where this can be displayed;
- added connections with devices, if they were in the sources;
- added active traces;
- added fields like “what to check” and “which process is affected.”
As a result, the alarm book grew to 451 M-bits:
M6001–M6450
+ M6475
= 451
Plus, 58 lines of active alarm trace were added. Some of them with high confidence, some with low. And that’s okay. It’s better to honestly store confidence than to pretend that everything is known for sure.

Important Note: An Alarm is Not Always Directly Related to a Sensor
The naive scheme looks like this:
sensor X triggered
→ alarm M activated
→ the cause was identified
Sometimes it is indeed the case. For example, some alarms are directly related to X.
But some alarms come through internal logic: servo bits, L/M conditions, D/W registers, or even without a clear physical source.
So, proper diagnostics look more like this:
if M = 1
→ retrieve the alarm text
→ retrieve the category
→ find the relevant interface screen
→ review related X/D/W signals, if available
→ review the internal conditions
→ determine what must be inspected manually
This is no longer just data collection. It’s translation from PLC language to human language.
Y-Outputs: Readable but Not Touchable
The next important layer is Y.
I wanted to check if it’s safe to read the states of PLC output commands. To do this, I conducted a smoke test on the Y directory: 287 outputs, read-only.
The rule was strict:
read Y
do not write to Y
do not force Y
do not use Y as a control channel
The code must not contain write, force, reset, remote control, and other dangerous things. Only reading.
The test went through MC/SLMP 3E Binary, with the command 0401 batch read, in bit mode.
The result of the smoke test:
Y signals planned: 287
read_ok: 287 / 287
all_cycles_ok: 287 / 287
batch reads ok: 40 / 40
batch reads failed: 0
errors: 0
Over 5 reading cycles:
- in the last cycle, 61 Y-addresses were active;
- 4 outputs changed during the test:
Y081,Y084,Y1A0,Y32B.
For diagnostics, this is useful: it means the Y layer is not just formally read, but reflects the live state of the PLC output commands.
But once again: this is not control. This is context.
A good diagnostic chain might look like this:
PLC command Y
→ feedback X
→ alarm M
For example, the PLC gave a command, then we check if feedback came, and if not — what alarm was raised.
A Bit About Read Commands
I won’t delve into protocols, but I’ll note one thought.
Different tasks require different commands:
0401— read large sequential ranges ofX/Y/M/L/D;0406— read several dispersed blocks in one request;0403— read rare single addresses;0801 + 0802— monitor registration/execution for a stable set, but with limitations;0601— read buffer memory intelligent modules, for example for the analog layer, if standard device memory is not confirmed;0613— buffer memory of the Ethernet module, more for diagnosing communication.
And always nearby lies a red sign: there are write commands and remote-control. They can easily be confused if you’re not careful. In a factory, such carelessness can be too costly.
What I Took Away
The main takeaway: diagnostics don’t start with a model or a dashboard. They start with a proper dictionary of signals.
In short, the practical order is as follows:
- Gather a raw index of all addresses and don’t lose the link to the source.
- Separate signals by meaning: inputs, outputs, alarms, registers, internal conditions.
- Don’t read everything indiscriminately — first understand what can be read and why.
- For alarms, store human context: text, category, screen, connections, what to check.
- For Y, establish a read-only rule at the data and code level.
- Store confidence. If the connection is hypothetical, let it be noted as such.
- Check reading with smoke tests, rather than taking Excel files/instructions/notes from production at face value.
- Don’t confuse observation and control.
For an ML engineer, this might not be the most glamorous part of the job. There’s no neural network that beautifully predicts an alarm an hour in advance. But without this foundation, any model will be learning from a mess of incomprehensible bits.
And when a signal transforms from M6001 = 1 into a comprehensible event with a category, screen, connections, and a list of checks — diagnostics have a chance to be useful before the situation turns into an emergency.
And that already looks like proper engineering work: not just collecting data, but making it possible to make the right decision based on it.