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

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

Simple-Scada

ЦитироватьА как толщину линии добавить
Сейчас это невозможно, из-за некоторых особенностей отрисовки. После внедрения системы слоёв в тренды рассмотрим также возможность изменения толщины линии тренда.

mepexa

Цитата: Simple-Scada от 16 декабря 2016, 16:43:09Если так, то можно просто запоминать в начале каждого часа текущее значение и записывать измеренное за прошедший час. Для корректной работы нужно три виртуальных переменных:
  • vrInit (тип данных Boolean, можно без шкалы);
  • vrByHour (тип данных тот же, что и у переменной счетчика, шкала должна быть достаточно большой). Для хранения результата за прошедший час;
  • vrStartCount (тип данных тот же, что и у переменной счетчика, шкала должна быть достаточно большой). Хранит значение счетчика на начало часа;
Далее создаем скрипт с типом события "Прошел час" и пишем такой код:

Код: pascal
begin
  if vrInit.AsBool then
  begin
    { получаем значение, накопленное за прошедший час }
    vrByHour.Value := Int1.AsInt - vrStartCount.AsInt;
    // ... здесь можно разместить код сохранения значения за прошедший час в БД, или файл
    vrStartCount.Value := Int1.AsInt;
  end else
    begin
      vrInit.Value := True;
      vrStartCount.Value := Int1.AsInt;
    end;
end.

При этом расчеты появятся в переменной vrByHour только после того, как пройдет один полный час после старта сервера скады. И соответственно после перезапуска сервера также придется ждать один полный час, чтобы скада показала накопленное значение за этот час.

А как сделать привязку по времени не к старту скады, а к 00 час 00 мин каждого дня ?
Есть счетчики электроэнергии. показания - с постоянным накоплением.
Требуется ежесуточный отчет потребленной энергии в excel-файл (или в БД с выводом в таблицу).
Я думаю, такой пример будет востребован многими пользователями.

Simple-Scada

Как раз для таких задач мы сейчас разрабатываем взаимодействие Simple-Scada 2 с системой отчетов Stimulsoft Reports и в начале 2017 года планируем закончить. При этом вывод будет доступен не только в excel-файл, но и в html, word, pdf и т.д. Также появятся расчетные переменные, чтобы подобные расчеты велись автоматически.

garry

Использую Simple-Scada для дома, в программировании не силен и чего-то затупил: приходят 2 тега с сервера - температура подачи и температура обратки, нужно в отдельном поле вывести разницу этих температур(дельту). Не могу понять с чего начать. Использую первую бету.

Simple_Scada

#199
Имеем две температуры Temp1 и Temp2. Для решения задачи нужно создать еще одну виртуальную переменную Temp3 (не забудьте создать для нее шкалу с отрицательной нижней границей - иначе при отрицательной разнице температур будет показывать 0), и связать ее с полем для вывода "Дельты". Затем выделить поле Temp1, перейти в события -> OnDataChange и написать скрипт:
Код: pascal
begin
  Temp3.Value := Temp1.Value - Temp2.Value;
end.

Далее выделяем поле Temp2 и в событии OnDataChange также выбираем наш скрипт. В итоге при изменений Temp1 или Temp2 будет выполняться наш скрипт и в поле Temp3 всегда будет отображаться актуальная разница температур.

garry

Спасибо , все получилось! Сначала по вашему примеру не компилировалось потому-что имена переменных стояли по именам тегов по умолчанию русские Тег1, Тег2. Поменял имена переменных и все завелось. Бегаю кругами и радуюсь.

596039

#201
Здравствуйте, раскладываю переменную(Alarm_1) на биты и записываю в отдельные виртуальные переменные(Alarm_Bit_N). Объясните пожалуйста в чем разница между двумя скриптами. Первый нормально отрабатывает, второй компилируется, но не работает. Как влияет перемена строк местами на работу?

Первый:
Код: pascal
var
 Alarm_Bit : TM_Variable;
 b : byte;
Begin
 for b := 0 to 15 do
  begin
   Alarm_bit := GetVariableByName('Alarm_Bit_' + IntToStr(b));
   Alarm_bit.Value := GetBit(Alarm_1.Value , b);
  end;
End.

И второй:
Код: pascal
var
 Alarm_Bit : TM_Variable;
 b : byte;
Begin
 for b := 0 to 15 do
  begin
   Alarm_bit.Value := GetBit(Alarm_1.Value , b);
   Alarm_bit := GetVariableByName('Alarm_Bit_' + IntToStr(b));
  end;
End. 

Simple-Scada

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

Здесь дело в том, что Alarm_Bit это указатель на переменную, а не сама переменная (это почти как ссылка в интернете). В первой ситуации Вы сначала помещаете в Alarm_Bit переменную с заданным именем, а затем работаете с этой переменной. Здесь ошибок нет. Разве что нужно учитывать, что GetVariableByName может вернуть nil, если не найдет переменную и лучше этот момент предусмотреть, вот так:

Код: pascal
var
  Alarm_Bit : TM_Variable;
  b : byte;
Begin
  for b := 0 to 15 do
  begin
    Alarm_bit := GetVariableByName('Alarm_Bit_' + IntToStr(b));
    if Alarm_bit <> nil then   // если переменная найдена, то работаем с ней
      Alarm_bit.Value := GetBit(Alarm_1.Value , b);
  end;
End.

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

Код: pascal
var
  Alarm_Bit : TM_Variable;
  b : byte;
Begin
  Alarm_bit := Alarm_1;  // теперь Alarm_bit инициализирован и указывает на переменную Alarm_1
  for b := 0 to 15 do
  begin
    Alarm_bit.Value := GetBit(Alarm_1.Value , b);
    Alarm_bit := GetVariableByName('Alarm_Bit_' + IntToStr(b));
  end;
End.


596039

Спасибо за доступное объяснение

TeNQ

#204
Не силен я в SQL поэтому откладывал как мог, но сегодня пришлось заняться. И у меня появились вопросы.
Почему не работает вот такой скрипт.
Код: pascal
aQuery := 'UPDATE `program_table` ' +
            'SET `TRM1_ProgramDuration` = `2017.02.03 16:48:36`, ' +
            '`TRM2_ProgramDuration` = NOW() WHERE `ID` = 1;';
В MySQL WorkBench работает такая последовательность.
Код: pascal
update TENQ.program_table SET TRM1_ProgramDuration = '2017.02.03 17:48:36', TRM2_ProgramDuration = Now() where ID = 1;
Дело тут в формате даты/времени, потому что если я меняю `2017.02.03 16:48:36` на NOW(), то и из SS2 скрипт записывает в таблицу. Но сколько я не танцевал с бубном с различными форматами и преобразованиями, так у меня ничего и не получилось.
И еще вопрос. Это шаманство с апострофами/одинарными кавычками для названий таблиц, столбцов можно убрать?  И так новичку непонятно ничего, так еще и разберись где их ставить, а где нет. В идеале я хотел бы через ctl+c/v скопировать из WorkBench рабочую последовательность и вставить ее в скрипт SS2 и чтобы заработало).
Все, разобрался.Вот так работает.
Код: pascal
aTRM1_ProgramDuration := QuotedStr('2017.02.03 16:48:36');
  aQuery := 'UPDATE `program_table` ' +
            'SET `TRM1_ProgramDuration` = ' + aTRM1_ProgramDuration + ', ' +
            '`TRM2_ProgramDuration` = NOW() WHERE `ID` = 1;';  
Т.е. таки оказалось, что вся проблема в этих кавычках/апострофах. Причем только обходным путем, используя дополнительную функцию ее удалось решить. Но это же и не очевидно и не удобно.
Я сейчас столкнулся с вещью, которая мне убила мне час времени. Я никак не мог понять, почему у меня не работает последовательность
Код: pascal
aTRM1_ProgramDuration := QuotedStr(DateTimeToStr(vrTRM1_ProgramDuration.AsDateTime));
aTRM2_ProgramDuration := QuotedStr(DateTimeToStr(vrTRM2_ProgramDuration.AsDateTime));   
aQuery := 'UPDATE `program_table` ' +
            'SET `TRM1_ProgramDuration` = ' + aTRM1_ProgramDuration + ', ' +
            '`TRM2_ProgramDuration` = ' + aTRM2_ProgramDuration + ' WHERE `ID` = 1;';
Ведь все же работает, если я дату беру из текста. Но из переменной ни в какую. А дело было вот в чем. Я инициализировал переменные vrTRM1_ProgramDuration через функцию StrToTime. При этом переменной присваивается год 1899. А MySQL считает  что в дате ошибка, если год ниже 1970 (проверено экспериментально).

Simple-Scada

#205
ЦитироватьВ MySQL WorkBench работает такая последовательность.
Дело в том, что в редакторе скриптов текст заключается в одинарные кавычки (апострофы), например: 'текст'. В SQL текст также заключается в одинарные кавычки. И если мы выполним запрос: RunSQL('my_text');, то в СУБД придет текст без кавычек, т.е. my_text. И если мы хотим передать текст с кавычками, то мы можем использовать функцию QuotedStr, которая заключает строку в одинарные кавычки, например: RunSQL(QuotedStr('my_text'));. Можно также обойтись без QuotedStr и чтобы добавить в строку одинарную кавычку её в строке нужно удвоить. Т.е. без QuotedStr наш скрипт будет таким: RunSQL('''my_text'''); и в СУБД придет 'my_text'. Или ещё пример:  RunSQL('''hello'' my ''friend''');, в этом случае в СУБД будет передана строка 'hello' my 'friend'.

ЦитироватьИ еще вопрос. Это шаманство с апострофами/одинарными кавычками для названий таблиц, столбцов можно убрать?
Имена таблиц и столбцов в MySQL часто заключают в другие одинарные кавычки, которые находятся на клавише "ё" и выглядят так: ``. Их основное предназначение в том, чтобы избежать  путаницы между зарезервированными ключевыми словами и названиями переменных, столбцов или таблиц. Например в SQL есть ключевое слово SELECT и мы хотим назвать столбец также. Для этого мы пишем так: SELECT * FROM `select` WHERE ...;

Поэтому, если Вы не используете ключевые слова при именовании таблиц и т.д., то эти кавычки можно убрать и записывать так: RunSQL('SELECT * FROM my_table.my_column WHERE id = 10');

ЦитироватьЯ инициализировал переменные vrTRM1_ProgramDuration через функцию StrToTime.
StrToTime запишет в переменную только время, без даты и дата останется 30 декабря 1899. Поэтому нужно инициализировать используя StrToDateTime (дата + время), например:

Код: pascal
var
  D: TDateTime;
begin
  D := StrToDateTime('03.02.2017 16:48:36'); 
end.

В результате вышеописанного можем заменить такую запись:
Код: pascal
aQuery := 'UPDATE `program_table` ' +
          'SET `TRM1_ProgramDuration` = `2017.02.03 16:48:36`, ' +
          '`TRM2_ProgramDuration` = NOW() WHERE `ID` = 1;';

на такую:
Код: pascal
aQuery := 'UPDATE program_table ' + 
          'SET TRM1_ProgramDuration = ''2017.02.03 16:48:36'', ' + 
          'TRM2_ProgramDuration = NOW() WHERE id = 1;';

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

TeNQ

Спасибо за разъяснения. Думаю дальше легче пойдет)

toreto

Здравствуйте!!! Такой вопрос: есть несколько полей со значениями и нужно вывести наибольшее из них в отдельное поле. И еще использую процедуру "Button_OnClick" со скриптом  MinimizeApplicationClient(GetClientName) на сворачивание клиента, и если запущено несколько клиентов то сворачивание происходит на всех клиентах, то же самое и с закрытием. Использую версию Simple-Scada 2.1.2.0.   

Simple-Scada

#208
ЦитироватьТакой вопрос: есть несколько полей со значениями и нужно вывести наибольшее из них в отдельное поле.
Пусть это поля fldA, fldB, fldC, а поле с максимумом fldMax. Каждое поле должно быть связано со своей переменной, а поле fldMax связано с виртуальной переменной. Тогда переходим к скрипту OnDataChange для поля fldA и пишем такой код:

Код: pascal
var
  aMax: Double;
begin
  aMax := fldA.AsFloat;
  if fldB.AsFloat > aMax then aMax := fldB.AsFloat;
  if fldC.AsFloat > aMax then aMax := fldC.AsFloat;

  fldMax.Value := aMax;
end.

Готово. Теперь у полей fldB и fldC выставляем этот скрипт на событие OnDataChange.

ЦитироватьИ еще использую процедуру "Button_OnClick" со скриптом  MinimizeApplicationClient(GetClientName) на сворачивание клиента, и если запущено несколько клиентов то сворачивание происходит на всех клиентах, то же самое и с закрытием. Использую версию Simple-Scada 2.1.2.0.
Значит на всех клиентских компьютерах используется одинаковое имя (или оно не задано). Изменить имя клиента Вы можете через Options.exe (раздел Simple-Client, поле "Имя этого клиента").

toreto