Чаще всего в SCADA системах используются платные лицензии, в которых прописано ограниченное количество тегов, с которыми можно работать - если хочешь больше тегов (чтобы получать больше сигналов из PLC), то нужно больше платить. Естественно может появиться желание немного сэкономить и выйти из положения ограничившись меньшим количеством тегов, для этого придется немного схитрить, о чем я и хотел бы написать.

Самый простой вариант, который я тоже применял в наших проектах, это использовать вместо дискретных тегов аналоговые - 16 дискретных сигналов можно заменить на одно слово. А вот из слова достать нужный бит средствами самой СКАДА - это уже довольно простая задача. На Intouch, например, при программировании реакция на нажатие кнопки, скрипт который обнуляет 4 бит может выглядеть вот так:

А если нужно, наоборот записать туда 1, то формула будет такая: EMG_DO_W = EMG_DO_W | 0x0010 Функция смены цвета элемента визуализации в зависимости от бита состояния выглядит похожим образом (для примера показал сравнение с десятеричным числом):

Таким нехитрым способом можно без проблем сэкономить 15 тегов (1 тег вместо 16), но все-равно даже так занимается 1 тег. А ведь можно пойти дальше и в некоторых случаях обойтись вообще без тега. Например, есть стандартный блок, так называемый Ready16 - блок показывающий готовность механизма, состоящий из 16 условий (так же 16 бит преобразуются в одно слово) - если любое из условий не соблюдается, то запуск механизма не возможен и поэтому для проверки почему это может быть, нужно подсветить оператору нужные эти условия. Вот так это может выглядеть:

И как же можно сэкономить теги в таком случае? А так что в СКАДА системах обычно бывает встроенная возможность с помощью скриптов запускать внешние программы. Идея простая: запускать программу с нарисованным заранее интерфейсом блока Реди16, которая сама будет подключаться к контроллеру, забирать из него нужный сигнал и рисовать состояние блока в данный момент. Скрипт при клике на кнопку, в котором прописывается адрес сигнала, который программа должна получить, для универсальности можно передать текст ошибок, заголовок окна и т.п. Вот такой скрипт я сделал для запуска внешней программы на Intouch:

FileDelete ("c:\Ready16\text.txt");
DIM f AS MESSAGE;
f =" f:"+StringChar(34)+ "\Ready16\text.txt"+StringChar(34);
FileWriteMessage("c:\Ready16\text.txt",-1,"Готов к работе/в работе",1);
FileWriteMessage("c:\Ready16\text.txt",-1,"Ошибка Привода",1);
FileWriteMessage("c:\Ready16\text.txt",-1,"Связь с Приводом ОК",1);
FileWriteMessage("c:\Ready16\text.txt",-1,"Привод отвечает на команды ",1);
FileWriteMessage("c:\Ready16\text.txt",-1,"Ошибка Тормоза",1);
FileWriteMessage("c:\Ready16\text.txt",-1,"Разъединитель силовой цепи",1);
DIM h AS MESSAGE;
h =" h:"+StringChar(34)+ "40 - Станция Натяжения №2 Ролик №1"+StringChar(34);

StartApp "C:\Ready16\Ready16.exe "+h+f+" s:D800"+" l:D801"+" a:D802.1";

Удаляем старый текст, добавлем в текстовый файл, новый текст, добавляем адреса и заголовки и передаем все это нашей программе. Первоначально хотелось передать и тексты ошибок аргументами, но в Windows существует ограничение на длину аргументов (у меня получилось 260 символов, о чем сказано и тут в комментариях). Также в Интаче длина сообщения типа message тоже имеет свое ограничение в 160 символов. В общем наиболее простой способ это обмен сообщениями через файл.

Сама программа написана на базе бесплатной библиотеки на C# HslCommunication-Community. Очень странно, что при скачивании с GitHub готовой программы, Windows Defender ругался на вирусы в ней, хотя проверка через virustotal ничего не показала. Исходный код моей программы тут: Ready 16.

Еще был эксперимент с отображением статуса блоков Ready16 при открытии соответствующего окна на HMI. Можно повесить скрипт, который будет запускаться до того как прорисуется интерфейс окна HMI. Скрипт запросит адрес статуса блоков, и уже можно подсвечивать блоки соответствующими цветами:

DIM res AS MESSAGE;
OLE_CreateObject(%WS,"Wscript.Shell");
%WS.RegWrite("HKEY_CURRENT_USER\Software\ready16\value",0,"REG_DWORD");

res = %WS.Run("C:\Ready16\ReadWord.exe s:D800",2,1);
result = %WS.RegRead("HKEY_CURRENT_USER\Software\ready16\value");

В этом примере обмен между программами организован при помощи реестра Windows, хотя можно был�� бы сделать также через промежуточный файл. Мне просто показалось что реестр работает быстрее, поправьте если ошибаюсь. При запуске функции %WS.Run можно при помощи параметров запускать окно в скрытом режиме, но главное включить последний параметр WaitOnReturn , где 1 - он означает что скрипт запустивший программу дождется ее выполнения и только потом продолжит свой сценарий. В данном случае он запишет состояние реестра (в который наша программа запишет состояние слова по адресу D800 из контроллера) в глобальный тег result

PS эти хаки не от разработчиков и не для них, это больше для эксплуатирущих уже готовые системы, у которых в проекте появились ограничения в тегах