Вопросы по скриптам в Simple-Scada 2

Автор Simple-Scada, 29 января 2016, 15:19:20

Simple-Scada

#225
Можно оба пункта решить одним секундным скриптом. Допустим переменные тегов называются соответственно Tag1, Tag2 ... Tag32.
Тогда скрипт будет таким:
Код: pascal
var
  aGoodCount, aBadCount: Byte;
  a61447, a61493: Byte;

  procedure Check(AQuality: Boolean; var ATag: TM_Variable);
  begin
    { если нужно проверять качество }
    if AQuality = TRUE then
      if ATag.IsGoodQuality then
        Inc(aGoodCount)
      else
        Inc(aBadCount);

    { если нужно проверять значение }
    if AQuality = FALSE then
      if ATag.AsInt = 61447 then
        Inc(a61447)
      else
        if ATag.AsInt = 61493 then
          Inc(a61493);
  end;

  { проверяет восемь тегов на качество (при AQuality = TRUE)
    или на значение (при AQuality = FALSE) }
  procedure GoodOrBad(AQuality: Boolean; var T1, T2, T3, T4, T5, T6, T7, T8: TM_Variable);
  begin
    aGoodCount := 0;
    aBadCount := 0;
    a61447 := 0;
    a61493 := 0;
   
    Check(AQuality, T1);
    Check(AQuality, T2);
    Check(AQuality, T3);
    Check(AQuality, T4);
    Check(AQuality, T5);
    Check(AQuality, T6);
    Check(AQuality, T7);
    Check(AQuality, T8);
  end;

begin
  { проверяем качество 8 тегов первого устройства }
  GoodOrBad(TRUE, Tag1, Tag2, Tag3, Tag4, Tag5, Tag6, Tag7, Tag8);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
    AddMessage(Now, mkAlarm, 'Устройство 1. Нет связи!', TRUE, TRUE);

  { если все 8 тегов с хорошим качеством }
  if aGoodCount = 8 then
  begin
    { проверяем значение тегов 17..24 }
    GoodOrBad(FALSE, Tag17, Tag18, Tag19, Tag20, Tag21, Tag22, Tag23, Tag24);

    if a61447 = 8 then  // все равны 61447
      AddMessage(Now, mkAlarm, 'Устройство 1. Датчик отключен!', TRUE, TRUE);

    if a61493 = 8 then  // все равны 61493
      AddMessage(Now, mkAlarm, 'Устройство 1. Обрыв датчика!', TRUE, TRUE);
  end;


  //////   далее тот же код, но для тегов второго устройства   //////


  { проверяем качество 8 тегов второго устройства }
  GoodOrBad(TRUE, Tag9, Tag10, Tag11, Tag12, Tag13, Tag14, Tag15, Tag16);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
    AddMessage(Now, mkAlarm, 'Устройство 2. Нет связи!', TRUE, TRUE);

  { если все 8 тегов с хорошим качеством }
  if aGoodCount = 8 then
  begin
    { проверяем значение тегов 25..32 }
    GoodOrBad(FALSE, Tag25, Tag26, Tag27, Tag28, Tag29, Tag30, Tag31, Tag32);

    if a61447 = 8 then  // все равны 61447
      AddMessage(Now, mkAlarm, 'Устройство 2. Датчик отключен!', TRUE, TRUE);

    if a61493 = 8 then  // все равны 61493
      AddMessage(Now, mkAlarm, 'Устройство 2. Обрыв датчика!', TRUE, TRUE);
  end;
end.

Для сокращения кода используется две подпроцедуры:
  • Check: проверяет качество переменной (если параметр AQuality = TRUE) или значение (если AQuality = FALSE). Если тег с плохим качеством, то увеличивается счетчик aBadCount, если с хорошим, то увеличивается счетчик aGoodCount. Если идет проверка на значение, то увеличиваются счетчики a61447 и a61493 соответственно;
  • GoodOrBad: обнуляет счетчики, получает восемь тегов и передаёт их для проверки качества, либо для проверки значений.

AutoCY

#226
    Здравствуйте! Помогите разобраться.

1. Задача: если переменная var1 (byte) принимает значение больше нуля, то переменная var2 (byte) (вентилятор) принимает значение 16.
var1 - Field1, var2 - Image1.

Код: pascal
Код:
begin
if Field1.AsInt > 0 then
    Image1.AnimSpeed := 16
  else
    Image1.AnimSpeed := 0;
end.  
       
При изменении значения Field1 - ничего не происходит.

Анимация начинает срабатывать только в таком случае, при var1 - Field1, Image1:

Код: pascal
begin
if Image1.AsInt > 0 then
    Image1.AnimSpeed := 16
  else
    Image1.AnimSpeed := 0;
end.

2.   Задача: написать скрипт таймера наработки оборудования с функциями ПУСК, СТОП и ПАУЗА, работающего от системного времени.   
Как будет выглядеть код?

Спасибо.
     

Simple_Scada

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

Вы этот код:

Код: pascal
begin
if Field1.AsInt > 0 then
    Image1.AnimSpeed := 16
  else
    Image1.AnimSpeed := 0;
end. 

написали для события OnDataChange Изображения? Если да, то скрипт не будет работать, так как для изображения он будет выполняться только при изменении переменной связанной с изображением - "var2".

ЦитироватьАнимация начинает срабатывать только в таком случае, при var1 - Field1, Image1

Все верно. Если Вам нужно, чтобы запускалась/останавливалась анимация изображения при изменении переменной "var1", то ее нужно связать и с полем и с изображением и не нужно использовать две переменных.

ЦитироватьЗадача: написать скрипт таймера наработки оборудования с функциями ПУСК, СТОП и ПАУЗА, работающего от системного времени.   
Как будет выглядеть код?

Пример таймера наработки с функциями ПУСК, СТОП и ПАУЗА Вы можете найти в демо-проекте: Страница "Скрипты" -> подстраница "Простые скрипты(1)" -> пример №8 "Пример секундомера".

Guchi

#228
Код: pascal
begin
  {  обрабатываем первый таймер }
 
  if Tag11.IsGoodQuality = False then
  if Tag12.IsGoodQuality = False then
  if Tag13.IsGoodQuality = False then
  if Tag14.IsGoodQuality = False then
  if Tag15.IsGoodQuality = False then
  if Tag16.IsGoodQuality = False then
  if Tag17.IsGoodQuality = False then
  if Tag18.IsGoodQuality = False then

  begin
    vrTimer_1.Value := vrTimer_1.Value + 1;
    begin
    if vrTimer_1.AsInt = 1 then
      AddMessage(Now, mkMessage, 'Отсутсвует связь. Устройство 1!', TRUE, FALSE);
    if vrTimer_1.AsInt = 60 then
      AddMessage(Now, mkWarning, 'Отсутсвует связь. Устройство 1!', TRUE, FALSE);
    if vrTimer_1.AsInt = 180 then
      AddMessage(Now, mkAlarm, 'Нет связи. Устройство 1 !', TRUE, TRUE);
      end;
   end else
    vrTimer_1.Value := 0;




  {  обрабатываем второй таймер }
  
  if Tag21.IsGoodQuality = False then
  if Tag22.IsGoodQuality = False then
  if Tag23.IsGoodQuality = False then
  if Tag24.IsGoodQuality = False then
  if Tag25.IsGoodQuality = False then
  if Tag26.IsGoodQuality = False then
  if Tag27.IsGoodQuality = False then
  if Tag28.IsGoodQuality = False then
  begin
    vrTimer_2.Value := vrTimer_2.Value + 1;
    begin
    if vrTimer_2.AsInt = 1 then
      AddMessage(Now, mkMessage, 'Отсутсвует связь. Устройство 2!', TRUE, FALSE);
    if vrTimer_2.AsInt = 60 then
      AddMessage(Now, mkWarning, 'Отсутсвует связь. Устройство 2!', TRUE, FALSE);
    if vrTimer_2.AsInt = 180 then
      AddMessage(Now, mkAlarm, 'Нет связи. Устройство 2 !', TRUE, TRUE);
    end;
  end else
    vrTimer_2.Value := 0
end.

секундный скрипт проверяет 8 переменных на качество и если все 8 плохого качества то по таймеру выдает сообщение...скрипт мой (выстраданный с Вашей помощью...за что я Вам очень благодарен) вроде бы  работает...как его можно упростить ? потому как переменных может быть и не 8 8))) возможно применить процедуру Check...
Идет просто проверка на связь с Устройством...по всем переменным...возможно и по одному (любому)

Код: pascal
var
  aGoodCount, aBadCount: Byte;
  a61447, a61493: Byte;

  procedure Check(AQuality: Boolean; var ATag: TM_Variable);
  begin
    { если нужно проверять качество }
    if AQuality = TRUE then
      if ATag.IsGoodQuality then
        Inc(aGoodCount)
      else
        Inc(aBadCount);

    { если нужно проверять значение }
    if AQuality = FALSE then
      if ATag.AsInt = 61447 then
        Inc(a61447)
      else
        if ATag.AsInt = 61493 then
          Inc(a61493);
  end;

  { проверяет восемь тегов на качество (при AQuality = TRUE)
    или на значение (при AQuality = FALSE) }
  procedure GoodOrBad(AQuality: Boolean; var T1, T2, T3, T4, T5, T6, T7, T8: TM_Variable);
  begin
    aGoodCount := 0;
    aBadCount := 0;
    a61447 := 0;
    a61493 := 0;
   
    Check(AQuality, T1);
    Check(AQuality, T2);
    Check(AQuality, T3);
    Check(AQuality, T4);
    Check(AQuality, T5);
    Check(AQuality, T6);
    Check(AQuality, T7);
    Check(AQuality, T8);
  end;

begin
  { проверяем качество 8 тегов первого устройства }
  GoodOrBad(TRUE, Tag1, Tag2, Tag3, Tag4, Tag5, Tag6, Tag7, Tag8);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
    AddMessage(Now, mkAlarm, 'Устройство 1. Нет связи!', TRUE, TRUE);

  { если все 8 тегов с хорошим качеством }
  if aGoodCount = 8 then
  begin
    { проверяем значение тегов 17..24 }
    GoodOrBad(FALSE, Tag17, Tag18, Tag19, Tag20, Tag21, Tag22, Tag23, Tag24);

    if a61447 = 8 then  // все равны 61447
      AddMessage(Now, mkAlarm, 'Устройство 1. Датчик отключен!', TRUE, TRUE);

    if a61493 = 8 then  // все равны 61493
      AddMessage(Now, mkAlarm, 'Устройство 1. Обрыв датчика!', TRUE, TRUE);
  end;


  //////   далее тот же код, но для тегов второго устройства   //////


  { проверяем качество 8 тегов второго устройства }
  GoodOrBad(TRUE, Tag9, Tag10, Tag11, Tag12, Tag13, Tag14, Tag15, Tag16);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
    AddMessage(Now, mkAlarm, 'Устройство 2. Нет связи!', TRUE, TRUE);

  { если все 8 тегов с хорошим качеством }
  if aGoodCount = 8 then
  begin
    { проверяем значение тегов 25..32 }
    GoodOrBad(FALSE, Tag25, Tag26, Tag27, Tag28, Tag29, Tag30, Tag31, Tag32);

    if a61447 = 8 then  // все равны 61447
      AddMessage(Now, mkAlarm, 'Устройство 2. Датчик отключен!', TRUE, TRUE);

    if a61493 = 8 then  // все равны 61493
      AddMessage(Now, mkAlarm, 'Устройство 2. Обрыв датчика!', TRUE, TRUE);
  end;
end.
вышеописанный скрипт с Check процедурой выдавал каждую секунду что "Нет связи с Устройством 1", "Нет связи с Устройством 2".
Насчет проверки по значению- эту часть скрипта можно убрать...только по качеству

AutoCY

#229
ЦитироватьПример таймера наработки с функциями ПУСК, СТОП и ПАУЗА Вы можете найти в демо-проекте: Страница "Скрипты" -> подстраница "Простые скрипты(1)" -> пример №8 "Пример секундомера".

Попробовал повторить таймер представленный в demo в своем проекте - пока ничего не получается.
Последовательность действий следующая:
1. Создал виртуальные переменные:
vrTimerState (состояние таймера), тип Byte;
vrIntervalInSec (интервал в сек), тип Int64, шкала - время;
vrTime (хранение отмеренного времени), тип DataTime, шкала - время.
2. Создал кнопку ПУСК. Присвоил переменную - vrTimerState. В событиях OnClick установил скрипт:
Код: pascal
begin
      if vrTimerState.AsInt = 0 then
         vrTime.Value := IncSecond(Now, -vrIntervalInSec.AsInt)
      else
         vrIntervalInSec.Value := SecondsBetween(Now, vrTime.Value);
end. 

3. Создал кнопку СТОП. В событиях OnClick установил скрипт:
Код: pascal
begin
  vrTimerState.Value := 0;
  vrIntervalInSec.Value := 0;
  txtTimer.Text := '0 дней 00:00:00';
end. 
4. Создал тект. В свойствах текста указал - 0 дней 00:00:00
5. Написал скрипт
Код: pascal
begin
  { Код для таймера. Если таймер запущен выводим накопленное время }
     if vrTimerState.AsInt = 1 then
        txtTimer.Text := IntToStr(DaysBetween(Now, vrTime.Value))  + ' дней ' + TimeToStr(Now -       vrTime.Value);
end.   
   
Подскажите, пожалуйста, где я что не учел?

Teodor

5. Написал срипт
А когда этот скрипт и чем вызывается?

AutoCY

#231
Цитата: Teodor от 15 марта 2017, 12:11:535. Написал скрипт
А когда этот скрипт и чем вызывается?
Да я ввел этот скрипт, в надежде, что он как-то выведет информацию о текущем времени, но к чему его "прикрутить" не знаю  ???

Teodor

#232
Цитата: AutoCY от 15 марта 2017, 13:06:53Да я ввел этот скрипт, в надежде, что он как-то выведет информацию о текущем времени, но к чему его "прикрутить" незнаю  ???
Например сделать его секундным, или часовым, или по событию (по кнопке). Я ж не знаю как вам надо :)
Но если скрипт не вызывать, он точно не исполнится.

AutoCY

#233
ЦитироватьНапример сделать его секундным, или часовым, или по событию (по кнопке). Я ж не знаю как вам надо :) Но если скрипт не вызывать, он точно не исполнится.

При условии, когда две переменных становятся больше нуля, включается таймер, если в процессе условие не соблюдается - таймер переходит в режим ПАУЗЫ.

В общем, поставил скрипт пятого пункта на кнопку ПУСК. Теперь таймер отображает значения, но пока обновляет данные только при условии нажатия кнопки.

AutoCY

ЦитироватьНапример сделать его секундным, или часовым, или по событию (по кнопке). Я ж не знаю как вам надо :) Но если скрипт не вызывать, он точно не исполнится.

Получилось. При создании скрипта выбрал событие: прошла секунда.

AutoCY


ЦитироватьПри условии, когда две переменных становятся больше нуля, включается таймер, если в процессе условие не соблюдается - таймер переходит в режим ПАУЗЫ.

На строке  else программа не хочет компилироваться.

Код: pascal
begin
      if vr_4.Value >  0 and vr_5.Value > 0  then
      begin
         { если выполнено условие, то включается таймер }
         vrIntervalInSec_2.Value := SecondsBetween(Now, vrTime_2.Value);
         { При включении таймера выводим накопленное время }
         txtTimer_2.Text := IntToStr(DaysBetween(Now, vrTime_2.Value))  + ' дней ' + TimeToStr(Now - vrTime_2.Value);
      end;
      else
         { если таймер ещё не включен }
         vrTime_2.Value := IncSecond(Now, -vrIntervalInSec_2.AsInt);
  end.
            

Simple-Scada

AutoCY, лишняя точка с запятой после end, должно быть:

Код: pascal
...
      txtTimer_2.Text := IntToStr(DaysBetween(Now, vrTime_2.Value))  + ' дней ' + TimeToStr(Now - vrTime_2.Value);
    end else
      { если таймер ещё не включен }
...

Simple-Scada

Цитироватьвышеописанный скрипт с Check процедурой выдавал каждую секунду что "Нет связи с Устройством 1", "Нет связи с Устройством 2".
Насчет проверки по значению- эту часть скрипта можно убрать...только по качеству
Да, забыли учесть таймеры. Если добавить таймер и убрать проверку на значение, то скрипт будет таким:

Код: pascal
var
  aGoodCount, aBadCount: Byte;

  procedure Check(var ATag: TM_Variable);
  begin
    if ATag.IsGoodQuality then
      Inc(aGoodCount)
    else
      Inc(aBadCount);
  end;

  procedure GoodOrBad(var T1, T2, T3, T4, T5, T6, T7, T8: TM_Variable);
  begin
    aGoodCount := 0;
    aBadCount := 0;
   
    Check(T1);  Check(T2);
    Check(T3);  Check(T4);
    Check(T5);  Check(T6);
    Check(T7);  Check(T8);
  end;

begin
  { проверяем качество 8 тегов первого устройства }
  GoodOrBad(Tag1, Tag2, Tag3, Tag4, Tag5, Tag6, Tag7, Tag8);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
  begin
    vrTimer_1.Value := vrTimer_1.Value + 1;
    case vrTimer_1.AsInt of
        1: AddMessage(Now, mkMessage, 'Отсутствует связь. Устройство 1!', TRUE, FALSE);
       60: AddMessage(Now, mkWarning, 'Отсутствует связь. Устройство 1!', TRUE, FALSE);
      180: AddMessage(Now, mkAlarm, 'Нет связи. Устройство 1!', TRUE, TRUE);
    end;
  end else
    vrTimer_1.Value := 0;


  //////   далее тот же код, но для тегов второго устройства   //////

  { проверяем качество 8 тегов второго устройства }
  GoodOrBad(Tag9, Tag10, Tag11, Tag12, Tag13, Tag14, Tag15, Tag16);

  { если все 8 тегов с плохим качеством }
  if aBadCount = 8 then
  begin
    vrTimer_2.Value := vrTimer_2.Value + 1;
    case vrTimer_2.AsInt of
        1: AddMessage(Now, mkMessage, 'Отсутствует связь. Устройство 2!', TRUE, FALSE);
       60: AddMessage(Now, mkWarning, 'Отсутствует связь. Устройство 2!', TRUE, FALSE);
      180: AddMessage(Now, mkAlarm, 'Нет связи. Устройство 2!', TRUE, TRUE);
    end;
  end else
    vrTimer_2.Value := 0;
end.

pan-nn

Новый затык со скриптами.
Как из переменной TDateTime вытащить только время?   Нужно сравнивать две переменных только  с учетом времени.
В Делфи есть AsTime и TimeToStr, а как тут сделать?

Simple-Scada

ЦитироватьВ Делфи есть AsTime и TimeToStr, а как тут сделать?
Можно так же как в Delphi перевести в строку только время используя TimeToStr и затем сделать сравнение строк. TimeToStr вытащит из TDateTime только время, без даты. Например:

Код: pascal
var
  dt1, dt2: TDateTime;
  Time1, Time2: string;
begin
  dt1 := Now;
  dt2 := Now;

  Time1 := TimeToStr(dt1);
  Time2 := TimeToStr(dt2);

  if Time1 = Time2 then 
  begin
    // время в dt1 равно времени dt2!
  end;
end.

Этот способ работает. Но так так TimeToStr зависит от формата времени, то правильнее сравнивать время извлекая часы, минуты и секунды. Вот так:

Код: pascal
var
  dt1, dt2: TDateTime;
begin
  dt1 := Now;
  dt2 := Now;

  { если часы, минуты и секунды у dt1 и dt2 равны }
  if (HourOf(dt1) = HourOf(dt2)) and
     (MinuteOf(dt1) = MinuteOf(dt2)) and
     (SecondOf(dt1) = SecondOf(dt2)) then
  begin
    // время в dt1 равно времени dt2!
  end;
end.