Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?

Официальный форум Simple-Scada.

Автор Тема: Восстановление тегов при перезагрузке ПЛК с OPC UA сервером  (Прочитано 193 раз)

Lorry P

  • Новичок
  • *
  • Сообщений: 6
    • Просмотр профиля
Добрый день.
Имеем веселую конфигурацию на ПНР - Два резервированных сервера с AstraLinux , SimpleSCADA 2.7.1.0(21.04.2025) через wine (по мануалу). И резервированный ПЛК Регул R500 с OPC UA сервером без настроек безопасности и аутентификации.

Связь настроена, теги читаются. Если остановить ПЛК или загрузить в него ПО(с остановом), то теряется связь с OPC UA сервером (на мнемосхеме клиента вместо переменных желтые восклицательные знаки) и более не восстанавливается. Хотя через EDITOR или любой тестовый клиент конфигурация читается. Так же на сервере(веб форма) статус OPC UA работает. Ошибок в логах по отсутствию переменных или конфигурации нет.
Останавливаю проект на сервере, запускаю заново - все работает.

Меняли параметры в расширенных настройках(таймауты) OPC сервера в Editor, но не помогло. Что еще можно сделать? Обновить до последней версии SimpleSCADA не имеем возможности

Нашел похожую тему с ПЛК WAGO , но там ошибка по отсутствию тегов на OPC UA сервере.
https://simple-scada.com/forum/index.php?topic=1856.msg12952#msg12952

Вот эта тема тоже похожа по смыслу
https://simple-scada.com/forum/index.php?topic=2120.msg14280#msg14280
« Изменён: 27 Августа 2026, 11:52:47 от Simple Scada »

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1424
    • Просмотр профиля
Здравствуйте.

Simple-Scada работает со всеми UA-серверами и их подписками строго в соответствии со спецификацией OPC-UA. После создания подписки, ее активность постоянно контролируется. Если обмен по подписке прекратился, то скада-система автоматически выполняет пересоздание подписки. ​​

В случае Regul, разработчики UA-сервера реализовали уникальное поведение (которое не используется ни в каких других UA-серверах). После загрузки данных в ПЛК Regul, старая подписка остаётся активной, OPC-сервер отвечает сообщением поддержания активности, но при этом не передаёт данные тегов. Т.е, подписка уже по сути не используется и по ней можно было бы не отвечать (удалить ее с UA-сервера), чтобы UA-клиент увидел это и создал новую. Но вместо этого UA-сервер Regul держит подписку активной и отвечает UA-клиенту, что с подпиской всё хорошо (хотя данные не передаются).

К сожалению, со стороны скада-системы повлиять на это не получится. Возможны только следующие решения:
1. Пытаться обойти проблемы UA-сервера со стороны скада-системы. Например, создать на мнемосхеме кнопку и по событию OnClick написать скрипт принудительного пересоздания подписок на UA-сервере при помощи процедуры RecreateSubscriptions. После загрузки изменений в ПЛК, можно будет нажать кнопку и пересоздать подписки без остановки проекта.
2. Получать данные с ПЛК Regul через специализированный UA-сервер от разработчиков Regul, который работает по уникальному поведению реализованному разработчиками Regul.

Цитировать
Меняли параметры в расширенных настройках(таймауты) OPC сервера в Editor
Рекомендуем вернуть параметры по умолчанию.

Lorry P

  • Новичок
  • *
  • Сообщений: 6
    • Просмотр профиля
Да, после тестов тоже выяснил что OPC UA сервер Regul R500 оставляет подписку активной. Спасибо за подсказку про процедуру RecreateSubscriptions.  Ручной вариант пересоздания подписок добавил, но нужен был и автоматический режим, поэтому реализовал немного костыльное, но рабочее в данном случае решение.
Прилагаю скрипты, может кому-то потребуется или будет полезным.
Контроль связи берем по ссылке, контроль через пинг на AstraLinux 1.7 SE не работает в моем случае (не поддерживается системой - было упоминание в мануале SimpleSCADA в разделе линукс).

Итак, на ПЛК реализуем лайфбит Bool с частотой изменения фронта 1 секунда.
Далее создаем теги в зависимости от выбранного варианта скрипта далее(см.скриншот).
На скаде сделаем скрипт по контролю его изменения с проверкой качества обязательно:
Код: (delphi)
begin
  // обнуляем счетчик отсутствия связи если переменная лайфбита с OPC UA изменяется
if DIAG_LifeBit.IsGoodQuality then
  vrLinkTimer.Value := 0;
end.

Далее скрипт с временем выполнения 1 секунда (ниже будет 3 рабочих вариации в зависимости от задачи) :
Код: (delphi)
//Рабочий скрипт контроля двух OPC UA  и переключения клиентов серверов
const
  TIMEOUT = 10;
  RECREATE_INTERVAL = 60;
begin
  // ===== ПЛК А  =====
  vrLinkTimer.Value := vrLinkTimer.AsInt64 + 1;

  if (vrLost.AsBool = FALSE) and (vrLinkTimer.AsInt64 >= TIMEOUT) then
  begin
    vrLost.Value := True;
    AddMessage(Now, mkMessage, 'Потеряна связь с OPC UA сервером ПЛК А', TRUE, FALSE);
    UAServer1.RecreateSubscriptions;
    AddMessage(Now, mkMessage, 'Выполняется автоматическое пересоздание подписок OPC UA сервера ПЛК А.', True, False);
    vrRecreateTimer.Value := 0;
  end;

  if (vrLost.AsBool = True) then
  begin
    vrRecreateTimer.Value := vrRecreateTimer.AsInt64 + 1;
    if vrRecreateTimer.AsInt64 >= RECREATE_INTERVAL then
    begin
      UAServer1.RecreateSubscriptions;
      AddMessage(Now, mkMessage, 'Повторное пересоздание подписок OPC UA сервера ПЛК А (каждую 1 мин).', True, False);
      vrRecreateTimer.Value := 0;
    end;
  end;

  if (vrLost.AsBool = True) and (vrLinkTimer.AsInt64 < TIMEOUT) then
  begin
    vrLost.Value := False;
    AddMessage(Now, mkMessage, 'Cвязь с OPC UA сервером ПЛК А восстановлена', TRUE, FALSE);
    vrRecreateTimer.Value := 0;
  end;

  // ===== ПЛК Б  =====
  vrLinkTimer_B.Value := vrLinkTimer_B.AsInt64 + 1;

  if (vrLost_B.AsBool = FALSE) and (vrLinkTimer_B.AsInt64 >= TIMEOUT) then
  begin
    vrLost_B.Value := True;
    AddMessage(Now, mkMessage, 'Потеряна связь с OPC UA сервером ПЛК Б', TRUE, FALSE);
    UAServer2.RecreateSubscriptions;   // проверьте реальное имя объекта
    AddMessage(Now, mkMessage, 'Выполняется автоматическое пересоздание подписок OPC UA сервера ПЛК Б.', True, False);
    vrRecreateTimer_B.Value := 0;
  end;

  if (vrLost_B.AsBool = True) then
  begin
    vrRecreateTimer_B.Value := vrRecreateTimer_B.AsInt64 + 1;
    if vrRecreateTimer_B.AsInt64 >= RECREATE_INTERVAL then
    begin
      UAServer2.RecreateSubscriptions;
      AddMessage(Now, mkMessage, 'Повторное пересоздание подписок OPC UA сервера ПЛК Б (каждую 1 мин).', True, False);
      vrRecreateTimer_B.Value := 0;
    end;
  end;

  if (vrLost_B.AsBool = True) and (vrLinkTimer_B.AsInt64 < TIMEOUT) then
  begin
    vrLost_B.Value := False;
    AddMessage(Now, mkMessage, 'Cвязь с OPC UA сервером ПЛК Б восстановлена', TRUE, FALSE);
    vrRecreateTimer_B.Value := 0;
  end;

  // ===== Автопереключение серверов  =====
  //Кнопка автоматического переключения vrAutoFailoverEnabled !!
  if vrAutoFailoverEnabled.AsBool and IsMasterServer and vrLost.AsBool and (not vrLost_B.AsBool) and (not vrFailoverActive.AsBool) then
  begin
    Switch_to_Slave(nil);
    vrFailoverActive.Value := True;
    AddMessage(Now, mkAlarm, 'Автопереход на резервный сервер: потеряна связь с ПЛК А', True, False);
  end;

  if vrAutoFailoverEnabled.AsBool and IsMasterServer and vrFailoverActive.AsBool and (not vrLost.AsBool) then
  begin
    Switch_to_Master(nil);
    vrFailoverActive.Value := False;
    AddMessage(Now, mkMessage, 'Автовозврат на основной сервер: связь с ПЛК А восстановлена', True, False);
  end;
end.



(*
//Рабочий скрипт для одного сервера OPC UA. Функционал попытки переподключения через 1 минуту. Без переключения клиентов между серверами .
const
  TIMEOUT = 10;
  RECREATE_INTERVAL = 60;
begin
  vrLinkTimer.Value := vrLinkTimer.AsInt64 + 1;

  if (vrLost.AsBool = FALSE) and (vrLinkTimer.AsInt64 >= TIMEOUT) then
  begin
    vrLost.Value := True;
    AddMessage(Now, mkMessage, 'Потеряна связь с OPC UA сервером', TRUE, FALSE);
    UAServer1.RecreateSubscriptions;
    AddMessage(Now, mkMessage, 'Выполняется автоматическое пересоздание подписок OPC UA сервера.', True, False);
    vrRecreateTimer.Value := 0;
  end;

  if (vrLost.AsBool = True) then
  begin
    vrRecreateTimer.Value := vrRecreateTimer.AsInt64 + 1;
    if vrRecreateTimer.AsInt64 >= RECREATE_INTERVAL then
    begin
      UAServer1.RecreateSubscriptions;
      AddMessage(Now, mkMessage, 'Повторное пересоздание подписок OPC UA сервера (каждую 1 мин).', True, False);
      vrRecreateTimer.Value := 0;
    end;
  end;

  if (vrLost.AsBool = True) and (vrLinkTimer.AsInt64 < TIMEOUT) then
  begin
    vrLost.Value := False;
    AddMessage(Now, mkMessage, 'Cвязь с OPC UA сервером восстановлена', TRUE, FALSE);
    vrRecreateTimer.Value := 0;
  end;
end.

 *)

(*
//Рабочий скрипт попытки пересоздания подписок. Без повторных попыток
begin
  vrLinkTimer.Value := vrLinkTimer.AsInt64 + 1;
  // проверка на отсутствие связи
  if (vrLost.AsBool = FALSE) and (vrLinkTimer.AsInt64 >= TIMEOUT) then
  begin
    vrLost.Value := True;
    AddMessage(Now, mkMessage, 'Потеряна связь с OPC UA сервером', TRUE, FALSE);
    UAServer1.RecreateSubscriptions;    //Пересоздание подписок для регула (у них не стандартный сервер, подписка держится активной даже если данных нет)
    AddMessage(Now, mkMessage, 'Выполняется автоматическое пересоздание подписок OPC UA сервера.', True, False);
  end;

  // проверка на восстановление связи
  if (vrLost.AsBool) and (vrLinkTimer.AsInt64 < TIMEOUT) then
  begin
    vrLost.Value := False;
    AddMessage(Now, mkMessage, 'Cвязь с OPC UA сервером восстановлена', TRUE, FALSE);
  end;
end.
*)
« Изменён: 29 Августа 2026, 15:23:20 от Simple-Scada »