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

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

Автор Тема: Вопросы по скриптам в Simple-Scada 2  (Прочитано 521129 раз)

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1365
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1140 : 12 Октября 2020, 22:29:26 »
Здравствуйте.
См. описание функции GetClientName - она не работает в скриптах "Выполнен SQL запрос".

deldemo

  • Старожил
  • ****
  • Сообщений: 308
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1141 : 13 Октября 2020, 07:06:15 »
Извиняюсь. Что-то упустил этот момент.
« Изменён: 13 Октября 2020, 07:07:17 от deldemo »

msigx680

  • Новичок
  • *
  • Сообщений: 6
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1142 : 14 Октября 2020, 01:08:20 »
Здравствуйте! Подскажите пожалуйста по такому вопросу: В OPC сервер отдаю переменную "in32scada" типа DWORD.
Добавляю ее в скаду, создаю внутреннюю переменную "myvar1" типа BOOL. Создаю обьект, к нему привязываю "myvar1".
Создаю универсальный скрипт, в OPC изменения значения видны, но в скаде не работает, что не так?
Задача передать 32 значения в скаду одной переменной, и на каждое создать определенные скрипты для индикации состояний.

begin
  if Sender is TM_Image then        // сначала убедимся, что скрипт вызван объектом изображение
    with Sender as TM_Image do      // далее будем работать с объектом Sender, как с изображением
      begin
          if GetBit(in32scada.AsInt,1) = true
             then FlashColor := clGreen // включить мигание объекта зеленым цветом
    else
        Color := clBlack;
          end;
   end.     

pan2000

  • Постоялец
  • ***
  • Сообщений: 216
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1143 : 14 Октября 2020, 09:54:58 »
. . .   
в OPC изменения значения видны, но в скаде не работает, что не так?
Задача передать 32 значения в скаду одной переменной, и на каждое создать определенные скрипты для индикации состояний.
. . .


    Здравствуйте.

Скорее всего не вызывается скрипт по причине отсутствия события: либо скрипт не назначен на событие, либо отсутствует связь переменных in32scada и myvar1.

Для групп объектов с одинаковым поведением определяемым битом из in32scada, можно построить следующие схемы:
 - основная переменная объекта in32scada, номер бита упакован в свойство Tag объекта, скрипт на событие "Изменилась основная переменная":
Код: (delphi)
begin
  if Sender is TM_Image then   // сначала убедимся, что скрипт вызван объектом изображение
    with Sender as TM_Image do // далее будем работать с объектом Sender, как с изображением
      if GetBit(AsInt, Tag) then begin
        FlashColor := clGreen; // включить мигание объекта зеленым цветом
        Color := clWhite;      // второй цвет мигания
      end else begin
        FlashColor := clNone;  // выключить мигание объекта
        Color := clBlack;      // цвет объекта в этом (false) состоянии
      end;
end.
;
 
- основная переменная объекта myvar<i>, где i - номер бита, скрипт на событие "Изменилась основная переменная":
Код: (delphi)
begin
  if Sender is TM_Image then   // сначала убедимся, что скрипт вызван объектом изображение
    with Sender as TM_Image do // далее будем работать с объектом Sender, как с изображением
      if AsBool then begin
          FlashColor := clGreen; // включить мигание объекта зеленым цветом
          Color := clWhite;      // второй цвет мигания
        end
      else begin
          FlashColor := clNone;  // выключить мигание
          Color := clBlack;      // цвет объекта в этом (false) состоянии
        end;
end.
, связь переменных in32scada и набора myvar<i> осуществляет скрипт "Изменилась переменная in32scada":
Код: (delphi)
var i: integer;
    aVar: TM_Variable;
begin
  for i := 0 to 31 do begin       // в реальном проекте можно ограничить цикл или индивидуальные присвоения переменным без анализа наличия
    aVar := GetVariableByName('myvar' + IntToStr(i));
    if aVar <> nil then aVar.Value := GetBit(Variable.AsInt, i);
  end;
end.
При наличии нескольких групп объектов необходимо для каждой группы написать свой скрипт.

Схемы различаются количеством переменных и вызовов скрипта (в первом - для всех объектов, во втором - только для объектов с изменившейся битовой переменной).   
Во вложении пример для общей и индивидуальных переменных, проект после разархивирования необходимо пересохранить.

msigx680

  • Новичок
  • *
  • Сообщений: 6
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1144 : 14 Октября 2020, 18:19:21 »
Добрый день! Спасибо большое за ответ!
Цитировать
связь переменных in32scada и набора myvar<i> осуществляет скрипт "Изменилась переменная in32scada"
Так заработало!
var i: integer;
    aVar: TM_Variable;
begin
for i := 0 to 31 do begin
   aVar := GetVariableByName('alarmstopnor48');
   if aVar <> nil then aVar.Value := GetBit(Variable.AsInt, 0);     //1

   aVar := GetVariableByName('avtomat_nor48');
   if aVar <> nil then aVar.Value := GetBit(Variable.AsInt, 1);     //2

Simple-Scada

  • Администратор
  • *****
  • Сообщений: 3197
    • Просмотр профиля
    • Simple-Scada
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1145 : 14 Октября 2020, 20:16:03 »
msigx680, это очень плохой код, половина действий просто бесполезны. Зачем выполнять цикл от 0 до 31, если в цикле выполняются одни и те же действия для одних и тех же битов. Нет смысла присваивать одно и то же значение 32 раза, достаточно сделать это один раз. Зачем искать переменную по имени, если можно обратиться к ней напрямую?
Исходя из вышеописанного код, который Вы написали можно заменить двумя строчками кода:
Код: (delphi)
begin
   alarmstopnor48.Value := GetBit(Variable.AsInt, 0);     // 1
   avtomat_nor48.Value := GetBit(Variable.AsInt, 1);      // 2
end.

Олег Печёнов

  • Новичок
  • *
  • Сообщений: 17
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1146 : 14 Октября 2020, 21:07:46 »
Добрый день,

читал, изучал - не нашел ответ.

при наступлении условия А = 1 запускается таймер. эта часть у меня работает.

как сделать, что бы при таймере в одну минуту и десять секунд  B = 1 ?

Благодарю.

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1365
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1147 : 16 Октября 2020, 09:57:02 »
Здравствуйте.

Методы для работы с таймерами описаны здесь. Методы для работы с датой/временем описаны здесь. При выполнении условия нужно запустить таймер при помощи процедуры TimerStart, например: TimerStart(MyTimer, 0); Затем создать новый скрипт с типом события "Изменились переменные", добавить переменную MyTimer в список отслеживаемых скриптом переменных и написать скрипт:
Код: (delphi)
const
  TIMEOUT = 70; // пауза в секундах
begin
  if (TimerGetState(Variable) = 1) then
    if SecondsBetween(Variable.AsDateTime, 0) >= TIMEOUT then
      begin
        TimerReset(Variable);
        MyVar.Value := 1;
      end;
end.
Если требуется постоянно через интервал времени выполнять какое-то действие, то можно использовать пример по ссылке.

lipvasko

  • Пользователь
  • **
  • Сообщений: 65
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1148 : 20 Октября 2020, 16:03:27 »
Доброго дня, сложилась  ситуация с последней версией ,  установил посл. версию, пока демо по времени , и заметил что при  вызове  сообщения  скриптом,  сервер  диагностирует ошибки и соответственно скрипт не выполняется , в предыдущей версии все было отлично  , изначально проект создав   версии демо 64 , ошибка следующая  15:55:12.368 | Ошибка в скрипте "CheckBox1_OnDataChange" в строке 5. Access violation at address 00F1F4AE in module 'Server.exe'. Read of address 00000014

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1365
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1149 : 20 Октября 2020, 16:13:31 »
Здравствуйте.

Значит в скрипте точно есть ошибка и нужно ее исправить. См. строку 5 скрипта и подумайте, в чем может быть ошибка. Если не разберетесь, пришлите нам папку с проектом для проверки на support@simple-scada.com.
« Изменён: 20 Октября 2020, 16:18:19 от Simple-Scada »

lipvasko

  • Пользователь
  • **
  • Сообщений: 65
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1150 : 20 Октября 2020, 16:24:49 »
Здравствуйте.

Значит в скрипте точно есть ошибка и нужно ее исправить. См. строку 5 скрипта и подумайте, в чем может быть ошибка. Если не разберетесь, пришлите нам папку с проектом для проверки на support@simple-scada.com.
Ошибка появляется строго на строке с вызовом сообщения, , повесил на кнопку этот скрипт    Message11.Show(1);    и снова  ошибка в сервере, 11 сообщение и его состояние 1 , существуют в проекте
« Изменён: 20 Октября 2020, 16:36:51 от lipvasko »

Simple-Scada

  • Администратор
  • *****
  • Сообщений: 3197
    • Просмотр профиля
    • Simple-Scada
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1151 : 20 Октября 2020, 16:46:56 »
Цитировать
Ошибка появляется строго на строке с вызовом сообщения, , повесил на кнопку этот скрипт    Message11.Show(1);    и снова  ошибка в сервере, 11 сообщение и его состояние 1 , существуют в проекте
Исправили. Обновление отправили Вам на e-mail.
« Изменён: 20 Октября 2020, 21:55:11 от Simple-Scada »

quarian

  • Новичок
  • *
  • Сообщений: 4
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1152 : 30 Ноября 2020, 11:32:22 »
Здравствуйте. Нужен совет.
Есть две переменных, связанных с одним устройством. Первая переменная дискретная, может принимать значения 0 или 1. Вторая переменная является счётчиком для первой типа LongWord. Есть три состояния устройства:
    1-первая переменная = 0, устройство в норме;
    2-первая переменная = 1, счётчик увеличился на 1, устройство в аварии;
    3 - первая переменная мигает, раз в секунду изменяя своё значение (0,1,0,1,0...), вторая переменная соответственно инкрементируется на 1 каждую секунду.
Задача состоит в том, чтобы разделить эти состояния и вывести соответствующее предупреждение.
С первыми двумя состояниями вопросов не возникает. Третье состояние я решил определять с помощью скорости изменения второй переменной - счётчика. Если изменяется быстрее, какого-то значения, то считаем, что третье состояние наступило. (Возможно, Вы можете предложить лучший способ).
Написал универсальный скрипт в шаблоне для фигуры, символизирующей устройство.
Код: (delphi)
var
  timeOfPreviousValue: TDateTime; //хранит время
  speedOfChanging: Double; //скорость изменения переменной (производная по времени)
  s: String; //сообщение о неисправности
begin
  if Sender is TM_Shape then
    with Sender as TM_Shape do
      speedOfChanging := 0.0;
      timeOfPreviousValue := IncSecond(Now, -interval.value); //interval - глобальная переменная времени задержки
      ArchiveValueByTime(TM_Shape(Sender).VariableEx, previousValue, timeOfPreviousValue); //запрос из архива значения, полученного на interval времени раньше
      Text2.Text := IntToStr(TM_Shape(Sender).VariableEx.AsInt64); //для отладки
      Text3.Text := IntToStr(previousValue.AsInt64); //для отладки
      if previousValue.Value <> 0 then //проверка на тот случай, когда в архиве недостаточно данных
      begin
        if (TM_Shape(Sender).VariableEx.AsInt64 - previousValue.AsInt64) > 0 then //проверка на ноль
          speedOfChanging := (TM_Shape(Sender).VariableEx.AsInt64 - previousValue.AsInt64)/interval.Value; //вычисление скорости изменения второй переменной
          Text4.Text := FloatToStr(speedOfChanging); //для отладки
        if speedOfChanging > 0.5 then //условие, при котором наступает третье состояние
          begin
            s := "Неисправность УКМ" + UTF8ToString(Sender.Hint);
            AddMessage(Now, mkAlarm, s,  true, true);
          end;
      end;
end.
Возникли следующие вопросы.
1. При попытке обращения к локальной переменной типа TM_Variable, в которую я передал результат функции ArchiveByTime в логе сервера появилась ошибка access violation. Поэтому создал глобальную переменную previousValue. Правильно ли я понимаю, что нет способа возвращать значение в локальную переменную? Не хотелось бы создавать отдельную переменную для каждого устройства.
2. Если создавать отдельную переменную для каждого устройства, то для работы в универсальном скрипте нужно будет использовать поиск по имени, а в имя протаскивать подстановку какого-нибудь поля? (hint, name).
« Изменён: 13 Декабря 2020, 21:50:34 от Simple_Scada »

Simple_Scada

  • Администратор
  • *****
  • Сообщений: 1365
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1153 : 30 Ноября 2020, 22:17:01 »
Здравствуйте.

Опишите подробно, какую именно задачу Вы пытаетесь решить при помощи этих двух переменных? Если они нужны для контроля связи, то можно использовать способ описанный здесь. Также, не понятно для чего требуется две переменных, если все описанные состояния можно получить из первой переменной и для чего определять скорость изменения переменной если и так известно, что она изменяется раз в секунду?

В приведенном скрипте используются вычисления на основе архивных функций - это плохой способ. Также, следует учитывать, что функция ArchiveValueByTime является асинхронной, т.е. она создает запрос к БД и ожидает пока он выполнится. Не гарантируется, что он всегда будет выполняться моментально. Например, если СУБД нагружена какими-то другими запросами, то ей может потребоваться какое-то время на их выполнение и результат ArchiveValueByTime будет выдан с какой-то задержкой. Поэтому, вызывать архивные функции и в том же скрипте производить вычисления с результатом данных функций неправильно, т.к. на момент выполнения вычислений результата может не быть. Правильный вариант - это вызвать архивную функцию, а затем по изменению переменной-результата(т.е. когда архивная функция гарантированно выполнится) производить вычисления.

По вопросам:
1. Правильно.
2. Да, такой вариант возможен.
« Изменён: 01 Декабря 2020, 11:32:51 от Simple-Scada »

quarian

  • Новичок
  • *
  • Сообщений: 4
    • Просмотр профиля
Re: Вопросы по скриптам в Simple-Scada 2
« Ответ #1154 : 01 Декабря 2020, 10:39:36 »
Здравствуйте. Спасибо за быстрый ответ.
Попробую более подробно описать задачу.

Переменные один и два, это, на самом деле, переменные OPC-сервера, связанные с одним дискретным входом модуля ввода (первая отвечает за состояние этого входа, а вторая за встроенный в модуль ввода счётчик). Один вход модуля ввода контролирует состояние одного устройства. Как я уже говорил, состояний у устройства три: в первом состоянии (99 процентов времени) логический ноль; второе состояние это авария, когда на входе появляется единица и горит до тех пор, пока обслуживающий персонал не предпримет некоторые физические действия; третье же состояние, когда на входе 0 и 1 сменяют друг друга с периодом в 1 секунду, говорит о неисправности самого устройства, его измерительной схемы.
Задача состоит только в том, чтобы различать состояния этих устройств (контроль связи будет осуществляться при помощи другого механизма). Задержка с распознаванием третьего состояния не сильно важна (до 5-10 секунд норм).
Устройств будет достаточно большое количество (около 1000), и 99 процентов времени они будут находится в первом состоянии, поэтому выполнения скриптов по времени я стараюсь избегать.
Использование второй переменной (счётчика модуля ввода) обусловлено моим страхом того, что изменение состояния первой может в какой-то момент синхронизироваться с частотой опроса и в этом случае скада будет считать, что устройство в первом или втором состоянии, в то время как оно уже минуту в третьем. При этом не хочется жёстко фиксировать время опроса, потому что для меня непонятно как поведёт себя OPC и скада при увеличении количества устройств и чем придётся пожертвовать для нормальной работы.

Вы правы насчёт архивной функции - я перемудрил. Гораздо проще и надёжнее держать две глобальные переменные: одну с предыдущим значением, а вторую с меткой времени, когда это значение было получено. И уже на основе этих двух переменных производить вычисления.

Ещё раз спасибо за помощь.
« Изменён: 01 Декабря 2020, 10:51:47 от quarian »