Fraunhofer-FIT-DIEN / iec104-python

A Python module to simulate SCADA and RTU communication over protocol 60870-5-104 to research ICT behavior in power grids.
https://iec104-python.readthedocs.io/latest/python/index.html
GNU General Public License v3.0
50 stars 9 forks source link

Add option to use Select or Execute in Qualifier of Command #2

Closed FernandoMK closed 9 months ago

FernandoMK commented 10 months ago

When trying to send a Single Command (C_SC_NA_1) from an IEC104 client to a slave device, an error occurs because the command has the QOC's S/E field set to "execute" (value 0).

Therefore, it is necessary to send the command with the QOC's S/E field set to "select" (value 1), and then send the same command with "execute".

Below are images collected through Wireshark.

The first images displays the packets for the execution of a Single Command (C_SC_NA_1) using the TestHarness software from Triangle Microworks. In it, you can observe the sending of an ASDU of type C_SC_NA_1 with COT = ACT and S/E = Select. Subsequently, the slave responds with ACTCON. wireshark - iec104 - testharness - 1

After the Select, the same command is sent again with COT = ACT and S/E = Execute. The slave responds with ACTCON as expected. wireshark - iec104 - testharness - 2

Following that, you can verify the correct writing of the value to the slave device.

The next images show the same command being sent through the IEC104 Python client built with this library. It can be seen that when sending a command, only the command with the S/E = Execute field is sent, missing the Select part before. Therefore, the slave responds with ACTCON_NEGA, and the sent value is not updated on the slave device. wireshark - iec104 - python client

Because of this, the value sent by the client is never updated on the slave device.

m-unkel commented 10 months ago

Thank you for the detailed report.

I can confirm that iec104-python is not sending commands with the select flag. I will prepare a fix.

lennart-bader commented 10 months ago

From my understanding, this should be an optional feature depending in the desired operation mode (direct vs. select and execute). Is this correct?

FernandoMK commented 10 months ago

From my understanding, this should be an optional feature depending in the desired operation mode (direct vs. select and execute). Is this correct?

Hello Lennart Bader, thank you for the comment.

Based on my knowledge of the protocol, IEC60870-5-104, commands (whether Single or Double Commands) and set-points always have the field for Select/Execute. There is no such thing as "Directly."

lennart-bader commented 10 months ago

For command transmission, IEC104 specifies two standard procedures according to this technical report (page 22):

So just sending the "execute" flag is still according to standard, and I guess the "select & execute" mode is missing.

FernandoMK commented 10 months ago

For command transmission, IEC104 specifies two standard procedures according to this technical report (page 22):

  • "Direct command": Control operations are immediately executed (The "execute" flag is set for the first command, as currently implemented)
  • "Select and execute command": Two step command, where first the "select" flag is set, the operation is checked by remote station (but not yet executed) and then acknowledged (or not acknowledged) to the client. The client can then send the same command with the "execute" flag to actually instruct the remote station to execute the command

So just sending the "execute" flag is still according to standard, and I guess the "select & execute" mode is missing.

You are correct. Based on this document and the IEC60870-5-101 standard (chapter 7.4.7), there is indeed a direct command mode that simply sends the execute flag. I apologize for my earlier misconception.

FernandoMK commented 10 months ago

I'm working on a fix from a fork as well. I noticed that when running the test.py file located in "tests," the following exception occurs.

------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\...\iec104-python\tests\test.py", line 345, in <module>
    if sv_step_point.read():
ValueError: Cannot send read commands as server

Is the test suite broken, or is this an expected behavior?

m-unkel commented 10 months ago

There is a typo, yes, please see branch fix-test, I will merge it soon.

Here is a suggestion for the command mode feature: https://github.com/Fraunhofer-FIT-DIEN/iec104-python/pull/3

# new property: point.command_mode
# new enum: c104.CommandMode

single_command = station.add_point(io_address=16, type=c104.Type.C_SC_NA_1, command_mode=c104.CommandMode.SELECT_AND_EXECUTE)
m-unkel commented 10 months ago

Can you verify that this will fix the issue? pip install git+https://github.com/Fraunhofer-FIT-DIEN/iec104-python.git@feature-command-mode

FernandoMK commented 10 months ago

Can you verify that this will fix the issue? pip install git+https://github.com/Fraunhofer-FIT-DIEN/iec104-python.git@feature-command-mode

I tested this new version using the SELECT_EXECUTE flag. I tested it for the following commands: C_SC_NA_1, C_DC_NA_1, C_SE_NB_1, and C_SE_NC_1. All of them worked correctly.

However, the read command point.read() stopped working and is always returning False. In Wireshark, I noticed that the read command (C_RD_NA_1) was sent, and a valid response from my slave device was also sent, but the point.read() command still returns False.

Below is the Wireshark screenshot showing the C_RD_NA_1 command sent and the M_ME_NB_1 response being sent by the slave to the client.

wireshark - iec104 - python client - 2

There is a typo, yes, please see branch fix-test, I will merge it soon.

About this, the branch fix-test is up to date with main. Are there any commits left to push in your local repository?

m-unkel commented 10 months ago

However, the read command point.read() stopped working and is always returning False. In Wireshark, I noticed that the read command (C_RD_NA_1) was sent, and a valid response from my slave device was also sent, but the point.read() command still returns False.

A pushed a fix into the feature branch.

About this, the branch fix-test is up to date with main. Are there any commits left to push in your local repository?

Oh sorry, i pushed the missing commit.

FernandoMK commented 10 months ago

It seems everything is fine now. I tested the write commands using the SELECT_EXECUTE flag and the read commands for M_SP_NA_1, M_DP_NA_1, M_ME_NB_1, and M_ME_NC_1. Everything I tested worked correctly.

I will be waiting for the merge and a formal release in PyPI. Thank you very much for your assistance.

coop-open-source commented 10 months ago

The update was released to PyPI

FernandoMK commented 10 months ago

Just letting you know, it seems that the automatic documentation from Sphinx has stopped working. The C++ Core section is okay, but the c104 Python module has no documentation on classes, methods, properties, and enums.

This is the C++ Core section: iec104 c++ docs

This is the c104 python module section (everthing is like that): iec104 python module docs

Is everything ok with the documentation?

FernandoMK commented 10 months ago

I also noted that the C_SE_NA_1 commands were not fixed with the SELECT_AND_EXECUTE command mode. I opened a pull request with the correction. Just a simple fix :)

coop-open-source commented 10 months ago

thanks I merged your contribution! I will create a 1.17.1 once the documentation generation is fixed..

m-unkel commented 9 months ago

release 1.17.1 is there