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

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

Simple-Scada

ЦитироватьА так как я с саааамого начала написал нельзя? В плане передачи сразу ТМ_Variable и не плясать с бубном ?
Как в сообщении #262? Тоже нельзя, т.к. в var параметр нельзя передавать свойство переменной, как Test(BIT_0.Value) или Test(BIT_0.AsInt), нужно обязательно передать переменную соответствующего типа.

Мы бы, в данной задаче, когда нужно в подпроцедуре менять значение переменной - не использовали бы подобных конструкций которые предложены в сообщениях выше, потому что проще передавать ссылку на переменную, вот так например:

Код: pascal
procedure Test(AVariable: TM_Variable);
begin
  AVariable.Value := 1;
end;

begin
  Test(vrMy);
end.

Тогда нет необходимости создавать отдельную переменную для извлечения значения и передачи как var параметр. Кроме того становится неважно - передавать переменную как var параметр или нет, в обоих случаях будет работать, т.к. AVariable это ссылка на область памяти.

Teodor

Цитата: Simple-Scada от 31 марта 2017, 19:26:31
ЦитироватьА так как я с саааамого начала написал нельзя? В плане передачи сразу ТМ_Variable и не плясать с бубном ?
Как в сообщении #262? Тоже нельзя, т.к. в var параметр нельзя передавать свойство переменной, как Test(BIT_0.Value) или Test(BIT_0.AsInt), нужно обязательно передать переменную соответствующего типа.

Мы бы, в данной задаче, когда нужно в подпроцедуре менять значение переменной - не использовали бы подобных конструкций которые предложены в сообщениях выше, потому что проще передавать ссылку на переменную, вот так например:

Код: pascal
procedure Test(AVariable: TM_Variable);
begin
  AVariable.Value := 1;
end;

begin
  Test(vrMy);
end.
сообщение 262, первый пример :) Да, вар там лишний(с разгону не вытер, у меня в коде его нету). Но в общем смысл тот-же. :-[

ksapp

#272
Ребята, всем, конечно, спасибо. Но суть в том, что мне надо работать именно с глобальными переменными, потому что в процедуре должна изменяться глобальная переменная, переданная по ссылке. Переменную целиком тоже пробовал передавать, тоже не компилируется. Так что ваши советы не помогли. Я, конечно, нашёл решение - использовал функцию, которая возвращает значение. Но, теперь вместо одной процедуры мне приходится использовать две функции, т.к. моя подпрограмма должна изменять значения двух глобальных переменных, переданных по ссылке. А это значит, что в конструкции case мне придётся использовать begin...end, то есть

Код: pascal
case x of
1: begin
    y := func1;
    z := func2;
    end;
end;

вместо

Код: pascal
case x of
1: proc(y, z);
end;

Согласитесь, что это увеличивает размер кода и время на его написание.

Так что просьба к разработчикам решить эту проблему в будущих версиях.

P.S. Вариант из сообщения 271 попробовал, но что-то тоже не получилось. Поковыряю ещё попозже, может разберусь.
P.P.S. Вариант из сообщения 271 работает. Спасибо за подсказку.

deldemo

Доброе утро.
Уважаемые, подскажите.

Все скрипты выполняются от одной переменной. Используя биты этой переменной. 
Вариант
1) пишу скрипты привязывая их к полю OnDataChangeEx и указываю ту самую одну переменную в качестве доп.переменной для выполнения скрипта.
2) пишу все скрипты в одном месте и привязываю этот скрипт к OnDataChange другого объекта.

Как эффективней, быстрее и надежней будут выполнятся скрипты?
пример скрипта (их будет сотни)
Код: pascal
begin
{AUTO}
  if GetBit(PLC2_FIRST_PRG_status.Value, 13) then
    begin // если бит равен 1
      bt_ZKH1_auto.States[0].Color  := RGB(0,95,88);
      bt_ZKH1_auto.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH1_auto.States[0].FontStep := 0;
      bt_ZKH1_auto.States[0].Caption := 'Авто вкл.';
      img_ZKH1_manual.Visible := FALSE ;
    end
  else
    begin // если бит равен 0
      bt_ZKH1_auto.States[0].Color  := RGB(60,70,80);
      bt_ZKH1_auto.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH1_auto.States[0].FontStep := 3;
      bt_ZKH1_auto.States[0].Caption := 'Авто';
      img_ZKH1_manual.Visible := TRUE ;
    end;
end.             

Simple-Scada

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

ЦитироватьВсе скрипты выполняются от одной переменной. Используя биты этой переменной.
Т.е. есть одна переменная и множество объектов. Все объекты должны реагировать на изменение битов в переменной, причем каждый объект реагирует только на изменение какого-то определённого бита. Мы правильно поняли?

deldemo

Да Вы все правильно поняли.
В данный момент мой скрипт выглядит так:
Код: pascal
begin
{Скрипт меняет состояние кнопок и индикаторов PLC2}

// Marsh *************************************************************************

{SILOS 1}
  if GetBit(PLC2_FIRST_PRG_status.Value, 0) then
    begin //если бит равен 1
      bt_silos1.States[0].Color  := RGB(0,95,88);
      bt_silos1.States[0].BorderColor := RGB(0,95,88);
    end
  else
    begin //если бит равен 0
      bt_silos1.States[0].Color  := RGB(60,60,60);
      bt_silos1.States[0].BorderColor := RGB(60,60,60);
    end;

{SILOS 2}
  if GetBit(PLC2_FIRST_PRG_status.Value, 1) then
    begin //если бит равен 1
      bt_silos2.States[0].Color  := RGB(0,95,88);
      bt_silos2.States[0].BorderColor := RGB(0,95,88);
    end
  else
    begin //если бит равен 0
      bt_silos2.States[0].Color  := RGB(60,60,60);
      bt_silos2.States[0].BorderColor := RGB(60,60,60);
    end;

{on TSB}
  if GetBit(PLC2_FIRST_PRG_status.Value, 2) then
    begin //если бит равен 1
      bt_onTSB.States[0].Color  := RGB(0,95,88);
      bt_onTSB.States[0].BorderColor := RGB(0,95,88);
    end
  else
    begin //если бит равен 0
      bt_onTSB.States[0].Color  := RGB(60,60,60);
      bt_onTSB.States[0].BorderColor := RGB(60,60,60);
    end;

// TSH ***************************************************************************

{AUTO}
  if GetBit(PLC2_FIRST_PRG_status.Value, 5) then
    begin //если бит равен 1
      bt_tsh_auto.States[0].Color  := RGB(0,95,88);
      bt_tsh_auto.States[0].BorderColor := RGB(0,95,88);
      bt_tsh_auto.States[0].FontStep := 0;
      bt_tsh_auto.States[0].Caption := 'Авто вкл.';
      manual_tsh.Visible := FALSE;
    end
  else
    begin //если бит равен 0
      bt_tsh_auto.States[0].Color  := RGB(60,70,80);
      bt_tsh_auto.States[0].BorderColor := RGB(60,70,80);
      bt_tsh_auto.States[0].FontStep := 3;
      bt_tsh_auto.States[0].Caption := 'Авто';
      manual_tsh.Visible := TRUE;
    end;

{MANUAL ON}
  if GetBit(PLC2_FIRST_PRG_status.Value, 6) then
    begin //если бит равен 1 
      bt_tsh_on.States[0].Color  := RGB(0,95,88);
      bt_tsh_on.States[0].BorderColor := RGB(0,95,88);
      bt_tsh_on.States[0].Caption := 'Включено';
    end
  else
    begin //если бит равен 0
      bt_tsh_on.States[0].Color  := RGB(60,70,80);
      bt_tsh_on.States[0].BorderColor := RGB(60,70,80);
      bt_tsh_on.States[0].Caption := 'Включить';
    end;

{MANUAL OFF}
  if GetBit(PLC2_FIRST_PRG_status.Value, 7) then
    begin //если бит равен 1
      bt_tsh_off.States[0].Color  := RGB(0,95,88);
      bt_tsh_off.States[0].BorderColor := RGB(0,95,88);
      bt_tsh_off.States[0].Caption := 'Выключено';
    end
  else
    begin //если бит равен 0
      bt_tsh_off.States[0].Color  := RGB(60,70,80);
      bt_tsh_off.States[0].BorderColor := RGB(60,70,80);
      bt_tsh_off.States[0].Caption := 'Выключить';
    end;

{REVERS ON/OFF}
  if GetBit(PLC2_FIRST_PRG_status.Value, 4) then
    img_tsh_revers.Visible := true
  else
    img_tsh_revers.Visible := false;

// NORIAH ************************************************************************

{AUTO}
  if GetBit(PLC2_FIRST_PRG_status.Value, 10) then
    begin //если бит равен 1
      bt_noriah_auto.States[0].Color  := RGB(0,95,88);
      bt_noriah_auto.States[0].BorderColor := RGB(0,95,88);
      bt_noriah_auto.States[0].FontStep := 0;
      bt_noriah_auto.States[0].Caption := 'Авто вкл.';
      manual_noriah.Visible := FALSE;
    end
  else
    begin //если бит равен 0
      bt_noriah_auto.States[0].Color  := RGB(60,70,80);
      bt_noriah_auto.States[0].BorderColor := RGB(60,70,80);
      bt_noriah_auto.States[0].FontStep := 3;
      bt_noriah_auto.States[0].Caption := 'Авто';
      manual_noriah.Visible := TRUE;
    end;

{MANUAL ON}
  if GetBit(PLC2_FIRST_PRG_status.Value, 11) then
    begin //если бит равен 1 
      bt_noriah_on.States[0].Color  := RGB(0,95,88);
      bt_noriah_on.States[0].BorderColor := RGB(0,95,88);
      bt_noriah_on.States[0].Caption := 'Включено';
    end
  else
    begin //если бит равен 0
      bt_noriah_on.States[0].Color  := RGB(60,70,80);
      bt_noriah_on.States[0].BorderColor := RGB(60,70,80);
      bt_noriah_on.States[0].Caption := 'Включить';
    end;

{MANUAL OFF}
  if GetBit(PLC2_FIRST_PRG_status.Value, 12) then
    begin //если бит равен 1
      bt_noriah_off.States[0].Color  := RGB(0,95,88);
      bt_noriah_off.States[0].BorderColor := RGB(0,95,88);
      bt_noriah_off.States[0].Caption := 'Выключено';
    end
  else
    begin //если бит равен 0
      bt_noriah_off.States[0].Color  := RGB(60,70,80);
      bt_noriah_off.States[0].BorderColor := RGB(60,70,80);
      bt_noriah_off.States[0].Caption := 'Выключить';
    end;


// ZKH1 ***********************************************************************

{AUTO}
  if GetBit(PLC2_FIRST_PRG_status.Value, 13) then
    begin // если бит равен 1
      bt_ZKH1_auto.States[0].Color  := RGB(0,95,88);
      bt_ZKH1_auto.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH1_auto.States[0].FontStep := 0;
      bt_ZKH1_auto.States[0].Caption := 'Авто вкл.';
      img_ZKH1_manual.Visible := FALSE ;
    end
  else    
    begin // если бит равен 0
      bt_ZKH1_auto.States[0].Color  := RGB(60,70,80);
      bt_ZKH1_auto.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH1_auto.States[0].FontStep := 3;
      bt_ZKH1_auto.States[0].Caption := 'Авто';
      img_ZKH1_manual.Visible := TRUE ;
    end;

{MANUAL OPEN}
  if GetBit(PLC2_FIRST_PRG_status.Value, 15) then
    begin // если бит равен 1
      bt_ZKH1_open.States[0].Color  := RGB(0,95,88);
      bt_ZKH1_open.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH1_open.States[0].Caption := 'Открыта';
    end
  else    
    begin // если бит равен 0
      bt_ZKH1_open.States[0].Color  := RGB(60,70,80);
      bt_ZKH1_open.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH1_open.States[0].Caption := 'Открыть';
    end;

{MANUAL CLOSE}
  if GetBit(PLC2_FIRST_PRG_status.Value, 14) then
    begin // если бит равен 1
      bt_ZKH1_close.States[0].Color  := RGB(0,95,88);
      bt_ZKH1_close.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH1_close.States[0].Caption := 'Закрыта';
    end
  else    
    begin // если бит равен 0
      bt_ZKH1_close.States[0].Color  := RGB(60,70,80);
      bt_ZKH1_close.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH1_close.States[0].Caption := 'Закрыть'
    end;

// ZKH2 ***********************************************************************

{AUTO}
  if GetBit(PLC2_FIRST_PRG_status.Value, 16) then
    begin // если бит равен 1
      bt_ZKH2_auto.States[0].Color  := RGB(0,95,88);
      bt_ZKH2_auto.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH2_auto.States[0].FontStep := 0;
      bt_ZKH2_auto.States[0].Caption := 'Авто вкл.';
      img_ZKH2_manual.Visible := FALSE ;
    end
  else    
    begin // если бит равен 0
      bt_ZKH2_auto.States[0].Color  := RGB(60,70,80);
      bt_ZKH2_auto.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH2_auto.States[0].FontStep := 3;
      bt_ZKH2_auto.States[0].Caption := 'Авто';
      img_ZKH2_manual.Visible := TRUE ;
    end;

{MANUAL OPEN}
  if GetBit(PLC2_FIRST_PRG_status.Value, 18) then
    begin // если бит равен 1
      bt_ZKH2_open.States[0].Color  := RGB(0,95,88);
      bt_ZKH2_open.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH2_open.States[0].Caption := 'Открыта';
    end
  else    
    begin // если бит равен 0
      bt_ZKH2_open.States[0].Color  := RGB(60,70,80);
      bt_ZKH2_open.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH2_open.States[0].Caption := 'Открыть';
    end;

{MANUAL CLOSE}
  if GetBit(PLC2_FIRST_PRG_status.Value, 17) then
    begin // если бит равен 1
      bt_ZKH2_close.States[0].Color  := RGB(0,95,88);
      bt_ZKH2_close.States[0].BorderColor := RGB(0,95,88);
      bt_ZKH2_close.States[0].Caption := 'Закрыта';
    end
  else
    begin // если бит равен 0
      bt_ZKH2_close.States[0].Color  := RGB(60,70,80);
      bt_ZKH2_close.States[0].BorderColor := RGB(60,70,80);
      bt_ZKH2_close.States[0].Caption := 'Закрыть'
    end;
end.                                                        

этот скрипт привязан к  инструменту "поле" и событию он  OnDataChange
Как видно из текста скрипта ,он меняет визуальное отображение совершенно разных кнопок.

В связи с внедрением новой возможности в S-S .OnDataChangeEx хотел раскидать скрипты непосредственно на кнопки.
Из этого следует вопрос. Не будит ли новый вариант медленней?
Ведь каждая кнопка будет одновременно вызывать свой скрипт.(так как переменная по которой срабатывает OnDataChangeEx одна)

Simple-Scada

Жаль что для разных кнопок выполняются уникальные изменения (для одних смена цвета, для других цвет + надпись и т.д.), а не типовые., тогда можно было бы все сделать одним универсальным скриптом.
Вы писали что таких скриптов будут сотни. Т.е. нужно будет выполнять тот же длинный скрипт но извлекая биты из другой переменной и применимо к другим кнопкам? Если так, то можно рассмотреть вариант создания нескольких универсальных скриптов из данного длинного скрипта.

Например взять следующую часть кода:
Код: pascal
begin
  {SILOS 1}
  if GetBit(PLC2_FIRST_PRG_status.Value, 0) then
    begin //если бит равен 1
      bt_silos1.States[0].Color  := RGB(0,95,88);
      bt_silos1.States[0].BorderColor := RGB(0,95,88);
    end else
      begin //если бит равен 0
        bt_silos1.States[0].Color  := RGB(60,60,60);
        bt_silos1.States[0].BorderColor := RGB(60,60,60);
      end;

  {SILOS 2}
  if GetBit(PLC2_FIRST_PRG_status.Value, 1) then
    begin //если бит равен 1
      bt_silos2.States[0].Color  := RGB(0,95,88);
      bt_silos2.States[0].BorderColor := RGB(0,95,88);
    end else
      begin //если бит равен 0
        bt_silos2.States[0].Color  := RGB(60,60,60);
        bt_silos2.States[0].BorderColor := RGB(60,60,60);
      end;
end.

Его можно заменить универсальным. Назовем его "uniButtonState" и напишем такой код:
Код: pascal
begin
  if not (Sender is TM_Button) then Exit;
  
  with Sender as TM_Button do
    if GetBit(AsInt, Tag) then
    begin
      States[0].Color  := RGB(0,95,88);
      States[0].BorderColor := RGB(0,95,88);
    end else
      begin
        States[0].Color  := RGB(60,60,60);
        States[0].BorderColor := RGB(60,60,60);
      end;
end.

В этом коде номер бита с которым нужно работать мы берём из свойства "Тег" кнопки. Теперь у кнопки bt_silos1 можно изменить свойство тег на 0, а кнопке bt_silos2 тег изменить на 1. В качестве доп. переменной выбрать PLC2_FIRST_PRG_status и на событие OnDataChangeEx выбрать наш универсальный скрипт "uniButtonState". Причем если в будущем нужно будет добавить в проект ещё несколько подобных кнопок, то можно будет использовать этот же универсальный скрипт, а не писать новый.

Этот вариант подойдет Вам? Если да, то мы можем написать как переделать на универсальные скрипты оставшуюся часть кода.

deldemo

ЦитироватьЖаль что для разных кнопок выполняются уникальные изменения.....
Да действительно жаль. Но как не крути в этом то и загвоздка :'(. Причем я предполагаю что со временем они("уникальные изменения") будут изменятся в зависимости от смены конфигурации маршрутов.
ЦитироватьЭтот вариант подойдет Вам? Если да, то мы можем написать как переделать на универсальные скрипты оставшуюся часть кода.
Спасибо большое за помощь !!!!!!
Я примерно понял как писать универсальные скрипты. Думаю что справлюсь сам. У Вас и без меня огромное кол-во работы.
Еще раз большое спасибо!

deldemo

#278
ЦитироватьЕго можно заменить универсальным. Назовем его "uniButtonState" и напишем
Я не знаю по какой причине, но данный способ вообще отказывается работать с кнопкой(по крайней мере у меня).
С изображением все работает, а с кнопкой нет.

Скрипт вроде как выполняется но не полностью
Первая часть до ELSE не реагирует на изменение бита.

Вообщем провел несколько тестов.
Оказалось что именно OnDataChangeEx не работает нормально.
Так как если закинуть скрипт в OnDataChange то все выполняется полностью.

Simple-Scada

deldemo, всё работает, мы случайно в примере указали основную переменную, а работать ведь надо с дополнительной. Т.е. вот так:

Код: pascal
begin
  if not (Sender is TM_Button) then Exit;
  
  with Sender as TM_Button do       // далее работаем с Sender'ом как с кнопкой
    if Assigned(VariableEx) then    // если кнопка связана с до. переменной
      if GetBit(VariableEx.AsInt, Tag) then   // достаем из доп. переменной бит равный номеру тега кнопки
      begin
        States[0].Color  := RGB(0,95,88);
        States[0].BorderColor := RGB(0,95,88);
      end else
        begin
          States[0].Color  := RGB(60,60,60);
          States[0].BorderColor := RGB(60,60,60);
        end;
end.

deldemo

Спасибо!!!!!. Теперь все понятно. Нужно всегда указывать доп.переменную.

AutoCY

Цитата: Simple-Scada от 20 марта 2017, 09:44:50
Цитата: AutoCY от 17 марта 2017, 13:13:30необходимо сделать таймер наработки оборудования с тремя интервалами во времени. Например, таймер формирует отдельные отрезки времени с 8.00 до 12.00, далее с 12.00 до 16.00 и т.д. При этом компонент таблица регистрирует эти данные в соответствующие ячейки. В результате, чтобы можно было проследить сколько работало оборудование в трех сменах в течении суток, скажем, за месяц.
Но ведь в этом случае все накопленные в таблице записи будут потеряны при первом перезапуске сервера скады или проекта. К тому же, чтобы они добавлялись в таблицу придется на каждый интервал времени выделить переменные и связать ячейки таблицы с этими переменными. Причем если планируется выводить наработку за месяц добавляя по 3 новых строки в день, то получается что нужно создать 90 строк в таблице и заполнить все строки переменными. Плюс остается проблема с потерей данных при перезапусках. Такая система совсем не подходит для нормальной работы.

Правильнее было бы выводить наработки получая их из архива. Т.е. включить у нужных тегов архивацию а затем выполнять выборку из БД за нужный интервал времени и подсчитывать время наработки. Тогда даже после перезапуска сервера все наработки сохранятся. Только сейчас все это нужно делать в запросе и готовых функций для вычисления наработок средствами скады нет. Постараемся их добавить в ближайших обновлениях.

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

Simple_Scada

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

Система отчетов сейчас находится на стадии бета-тестирования. После доработки и добавления в нее некоторого функционала, добавления необходимых примеров по работе с системой отчетов, можно будет вернуться к Вашему вопросу.

ksapp

Здравствуйте.
Поле ввода (TM_Field) не обрабатывает события мыши (двойной щелчок - остальные пока не проверял).
Пытаюсь вызвать скрипт по этому событию - ничего не происходит. Сам скрипт рабочий. Например, при двойному щелчку по TM_Text этот же скрипт работает.
Это баг или всё-таки я что-то делаю не так?

Simple-Scada

ЦитироватьЭто баг или всё-таки я что-то делаю не так?
Здравствуйте. Вы всё делаете правильно. Событие двойного клика перекрывается обработкой ввода. Исправим в будущих обновлениях.