ScadaPy: добавляем протокол IEC 60870-5-104 +6


Добавление протокола iec-104 в scadapy, предоставляет дополнительные возможности для расширения системы, как в домашней автоматизации, так и для локального применения на малых предприятиях.

Данный протокол довольно сложный в освоении, но в настоящий момент в интернете можно найти достаточно документации для ознакомления.

Что дает нам использование этого протокола?

Существенный фактор – это то, что протокол является асинхронным, в отличие от modbus, и данные передаются только в случае изменения текущего состояния переменной, что в свою очередь снижает нагрузку на каналы связи. Также имеется возможность получать метку времени изменения состояния переменной на объекте, на modbus для этого используются отдельные регистры.

Подробно прочитать можно здесь.

В настоящий момент нам не удалось найти подходящую библиотеку для освоения, написанную на Python, поэтому применили уже готовую библиотеку на С с этого сайта.

Затем скомпилировали две утилиты iec104client и iec104server.

Клиент


При использовании клиента IEC 60870-5-104, утилита iec104client выполняет установление связи с подчиненным устройством, после чего происходит получение данных с объекта, при этом первоначально формируется команда (20) — общий опрос (interrogated by station interrogation) и обработка полученных данных, а затем происходит спорадический прием по изменению значения переменных.

В случае потери связи с устройством, утилита iec104client самостоятельно пытается выполнить восстановление связи. При возобновлении сессии связи, сперва отправляется команда (20) группового опроса, а затем спорадический прием.

Поддерживаемые ASDU:

Дискретные значения:

  • <36> M_SP_TB_1 — одноэлементная информация с меткой времени СР56Время2а
  • <1> M_SP_NA_1 — одноэлементная информация
Аналоговые значения:
  • <13> M_ME_NC — значение измеряемой величины, короткий формат с плавающей запятой без метки времени.
  • <36> M_ME_TF_1 — значение измеряемой величины, короткий формат с плавающей запятой с меткой времени CP56Время2а.
  • <11> M_ME_NB_1 — значение измеряемой величины, масштабированное значение

Разобраться в исходном тексте не составит труда, особое внимание следует обратить на функцию

static bool asduReceivedHandler (void* parameter, int address, CS101_ASDU asdu).

Вся обработка получаемых данных происходит именно в ней.

Можно просто оставить,

  printf("REC type: %s(%i) elements: %i\n",
            TypeID_toString(CS101_ASDU_getTypeID(asdu)),
            CS101_ASDU_getTypeID(asdu),
            CS101_ASDU_getNumberOfElements(asdu));

а затем следить за тем, какие данные были приняты.

image

На схеме выше изображен принцип работы программы.

После получения значения состояния дискретного или аналогового сигнала, происходит передача json udp пакета на сервер мониторинга или иной предусмотренный сервер (мы используем json web server).

Формат пакета не изменился: {“name”:”myvar”,”data”:[220.001]}

В настоящий момент метка времени не передается в пакете из-за отсутствия надобности, но я все же считаю, что ее надо будет добавить.

Файл настройки параметров iec104client имеет следующий вид:

Файл конфигурации клиента
[
{ "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" -- тип переменной
}
}
]


Небольшой пример файла настройки для получения значений с сервера нижнего уровня, опрашивающего устройства РЗА Сириус 3-ЛВ-03 по Modbus RTU. В данном случае нас интересуют только токи и напряжения, а остальная информация поступает в SCADA систему СДТУ.

ПС 110 кВ
[
{ "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"
}
}

]


Сервер


При использовании сервера IEC 60870-5-104, утилита iec104server работает в качестве udp сервера, выполняет поддержание связи с клиентом и при изменении состояния переменной передает данные в канал связи.

Файл настройки параметров iec104server имеет следующий вид:

Настройка сервера
[
{ "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"
}
}
]


image

Компилирование


Windows:

Для сборки утилит был использован пакет msys2-i686-20180531.

Необходимо выполнить установку данного пакета, к примеру на диск С:, получится что-то вроде C:\msys32. Заходим в эту директорию и запускаем файл msys2_shell.cmd.

Появится консольное окно, в котором теперь можно вводить команды linux.

Необходимо выполнить установку необходимых библиотек для компиляции:

pacman –S make
pacman –S gcc

Теперь надо скачать исходники для компиляции.

Заходим сюда скачиваем архив, копируем папку lib60870-C в c:\msys32.

В консольном окне msys выполняем компилирование библиотеки lib60870:

cd /lib60870-C
make clean
make

image

Теперь делаем

cd scadapy104

Запускаем сборку сервера:

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

image

Запускаем сборку клиента:

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

image

В папке C:\msys32\lib60870-C\scadapy104\bin будут находиться два файла iec104client.exe и iec104server.exe.

Для запуска этих файлов, на Windows 7,8 понадобились dll файлы
На других версиях windows не проверяли.

Теперь если запустить любую из этих утилит, то появится help подсказка.

Linux:

Необходимо установить пакеты gcc и make, если не установлены (использую Ubuntu):
$ sudo apt install build-essential
Далее компилируется все аналогично.

Конфигурационные файлы можно создавать и проверять работоспособность в “ScadaPy creator”.

Для клиента:

image

Для сервера:

image

Все библиотеки и проекты находятся здесь.




К сожалению, не доступен сервер mySQL