Adding the iec-104 protocol to scadapy provides additional opportunities for expanding the system, both in home automation and for local use in small enterprises.
This protocol is quite difficult to master, but at the moment you can find enough documentation on the Internet for review.
What gives us the use of this protocol?
A significant factor is that the protocol is asynchronous, unlike modbus, and data is transmitted only when the current state of the variable changes, which in turn reduces the load on the communication channels. It is also possible to get a timestamp of a state change of a variable on an object; on modbus, separate registers are used for this.
')
You can read in detail
here .
At the moment, we were unable to find a suitable library for development written in Python, so we used the ready-made library in C
from this site .
Then we compiled two utilities, iec104client and iec104server.
Customer
When using IEC 60870-5-104 client, the iec104client utility establishes communication with a slave device, after which data is received from the object, and a command (20) is initially formed - general interrogated by station interrogation and processing the received data, and then there is a sporadic reception on change of value of variables.
In case of loss of communication with the device, the iec104client utility independently attempts to restore communication. When a session is resumed, a group survey command (20) is sent first, and then a sporadic reception.
Supported ASDUs:Discrete values:- <36> M_SP_TB_1 - singleton information with time stamp CP56Time2a
- <1> M_SP_NA_1 - Singleton Information
Analog values:- <13> M_ME_NC - the value of the measured value, a short floating-point format without a timestamp.
- <36> M_ME_TF_1 - the value of the measured value, the short floating-point format with the timestamp CP56Time2a.
- <11> M_ME_NB_1 - measured value value, scaled value
To understand the source text is not difficult, special attention should be paid to the function
static bool asduReceivedHandler (void* parameter, int address, CS101_ASDU asdu).
All processing of the received data occurs in it.
You can just leave
printf("REC type: %s(%i) elements: %i\n", TypeID_toString(CS101_ASDU_getTypeID(asdu)), CS101_ASDU_getTypeID(asdu), CS101_ASDU_getNumberOfElements(asdu));
and then keep track of which data was taken.

The diagram above shows the principle of the program.
After receiving the value of the state of a discrete or analog signal, the json udp packet is transmitted to the monitoring server or another provided server (we use the json web server).
The package format has not changed: {“name”: "myvar", "data": [220.001]}
At the moment, the timestamp is not transmitted in the package due to the lack of need, but I still think that it will need to be added.
The configuration file for the iec104client is as follows:
Client configuration file[
{ "Client":
{ "UdpPort" :"64000", -- UDP
"UdpIp" :"127.0.0.1", -- IP UDP
"Iec104Port":"2404", -- 104 ( )
"Iec104Ip" :"192.168.0.105", -- IP 104
"Debug" :"1", -- (1 3)
"TimeSync" :"1" -- (1 0)
}
}
,
{ "MeasureValue": --
{
"VarName" : "WaterTemp", --
"IecAddress": "8001", --
"Alias" : " ", --
"VarType" : "int32" --
//int – int 2
//int32 – 4 ( float)
//float –
//
}
}
,
{ "SinglePoint": --
{
"VarName" : "EngineOnOff", --
"IecAddress": "4001", --
"Alias" : " ", --
"VarType" : "bool" --
}
}
]
A small example of a configuration file for retrieving values ​​from a lower-level server, a relay relay protection device, Sirius 3-LV-03 via Modbus RTU. In this case, we are only interested in currents and voltages, and the rest of the information goes to the SDAD SCADA system.
110 kV substation[
{ "Client":
{ "UdpPort" :"64000",
"UdpIp" :"0.0.0.0",
"Iec104Port":"2404",
"Iec104Ip" :"...",
"Debug" :"1",
"TimeSync" :"0"
}
}
,
{ "SinglePoint":
{
"VarName" : "alarm",
"IecAddress": "681",
"Alias" : "alarm",
"VarType" : "bool"
}
}
,
{ "MeasureValue":
{
"VarName" : "Ia",
"IecAddress": "372",
"Alias" : "-- Ia --",
"VarType" : "float"
}
}
,
{ "MeasureValue":
{
"VarName" : "Ib",
"IecAddress": "373",
"Alias" : "-- Ib --",
"VarType" : "float"
}
}
,
{ "MeasureValue":
{
"VarName" : "Ic",
"IecAddress": "374",
"Alias" : "-- Ic --",
"VarType" : "float"
}
}
,
{ "MeasureValue":
{
"VarName" : "Uab",
"IecAddress": "369",
"Alias" : "-- Uab --",
"VarType" : "float"
}
}
,
{ "MeasureValue":
{
"VarName" : "Ubc",
"IecAddress": "370",
"Alias" : "-- Ubc --",
"VarType" : "float"
}
}
,
{ "MeasureValue":
{
"VarName" : "Uca",
"IecAddress": "371",
"Alias" : "-- Uca --",
"VarType" : "float"
}
}
]
Server
When using the IEC 60870-5-104 server, the iec104server utility works as a udp server, maintains communication with the client and, when the state of a variable changes, transmits data to the communication channel.
The parameter settings file, iec104server, is as follows:
Server Tuning[
{ "Server":
{ "UdpPort" :"64002",
"UdpIp" :"127.0.0.1",
"Iec104Port":"2404",
"Iec104Ip" :"192.168.0.103",
"Debug" :"1"
}
}
,
{ "MeasureValue":
{
"VarName" : "WaterTemp",
"IecAddress" : "8001",
"OffSet" : "0", -- (0– ) [100,200,300,400]
"ByteCount" : "2", -- (1,2)
"ByteSequence": "12",-- (1,12,21)
"Koef" : "1", --
"VarType" : "int" –
}
}
,
{ "SinglePoint":
{
"VarName" : "EngineOnOff",
"IecAddress" : "4001",
"OffSet" : "0",
"ByteCount" : "1", --
"ByteSequence": "1", --
"VarType" : "bool"
}
}
]

Compiling
Windows:For the assembly of utilities was used package
msys2-i686-20180531 .
You need to install this package, for example on the C: drive, you get something like C: \ msys32. Go to this directory and run the file msys2_shell.cmd.
A console window will appear in which you can now enter linux commands.
You must install the necessary libraries for compilation:
pacman –S make pacman –S gcc
Now you need to download the source code for compilation.
Go
here to download the archive, copy the folder lib60870-C to c: \ msys32.
In the msys console window, compile the lib60870 library:
cd /lib60870-C make clean make

Now do
cd scadapy104
Run the server build:
gcc -g -g -o ./bin/iec104server.exe iec104server.c ./parson/parson.c -I../src/inc/api -I../src/hal/inc -I../src/tls -I./parson ../build/lib60870.a –lpthread

Run the client build:
gcc -g -g -o ./bin/iec104client.exe iec104client.c ./parson/parson.c -I../src/inc/api -I../src/hal/inc -I../src/tls -I./parson ../build/lib60870.a -lpthread

In the folder
C:\msys32\lib60870-C\scadapy104\bin
will be two files iec104client.exe and iec104server.exe.
To run these files, on Windows 7,8 you need dll
filesOn other versions of windows did not check.
Now if you run any of these utilities, a help prompt will appear.
Linux:You need to install the gcc and make packages if not installed (using Ubuntu):
$ sudo apt install build-essential
Further all is compiled similarly.
Configuration files can be created and tested for functionality in the “ScadaPy creator”.
For client:

For server:

All libraries and projects are
here.