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

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

Andrey1883


Почему-то
sunriseMinutes:=Int((sunrise*60) div 60);
даёт ошибку incopatible types "SINGLE" and "INTRGER"

я так понимаю, потому что операция деления нацело определена в Паскале только для случая, когда по обе стороны от div указаны
целочисленные значения. а у вас  переменная sunrise имеет тип SINGLE


ARV


B.B

#1607
Цитата: Andrey1883 от 10 декабря 2024, 12:45:01Почему-то
sunriseMinutes:=Int((sunrise*60) div 60);
даёт ошибку incopatible types "SINGLE" and "INTRGER"

я так понимаю, потому что операция деления нацело определена в Паскале только для случая, когда по обе стороны от div указаны
целочисленные значения. а у вас  переменная sunrise имеет тип SINGLE
Немного не так Int((sunrise*60) - целое, 60 - целое.
Поэтому "по обе стороны от div указаны целочисленные значения"

UPD Прошу прощения. Скобки! Порядок неправильный!! Действительно SINGLE получится, а выглядит как целое  :D

B.B

Цитата: ARV от 10 декабря 2024, 15:56:02Есть же round()...
Нам надо именно целую часть, а Round() Возвращает число X округленное до ближайшего целого..
Поэтому INT

Иначе из 7,55 (это 7 часов 33 минуты) получим 8 часов и 33 минуты. Что неверно.

ZWolol

#1609
Int дает EXTENDED, и преобразовывать нужно оператор деления, а не результат.

sunriseMinutes:=integer(sunrise*60) div 60;

P.S.
Только Div не любит преобразование типа (это зависит от оптимизации компилятора).
Например, на Lazarus ругается, что первый элемент не может быть Double.

Лучше используй i:= integer(sunrise*60); и её подставляй для Div.

P.S.S.
А чем тебя это не устраивает?: sunriseMinutes:=integer(sunrise);

ARV

Цитата: B.B от 12 декабря 2024, 21:22:53Round() Возвращает число X округленное до ближайшего целого
Ну, тогда есть Trunc()

Принудительное преобразование типов по-настоящему требуется достаточно редко, и чаще всего свидетельствует о недопонимании чего-то важного...

AndreyA

#1611
Здравствуйте!
Задача в следующем: необходимо подсчитывать время наработки механизмов и выводить часы наработки оператору (не рапорта) как переменные процесса.
сделал скрипт раз в секунду:
Код: pascal
const
  TIMEHOUR = 3600;
begin
  if (conv1.Value = 20) and (worksec_conv1.Value < TIMEHOUR) then
    worksec_conv1.Value := worksec_conv1.AsInt + 1;

  if (conv1.Value = 20) and (worksec_conv1.Value >= TIMEHOUR) then
  begin
    workhours_conv1.Value := workhours_conv1.AsInt + 1;
    worksec_conv1.Value := 0;
  end;
end.
Вопрос : как этот скрипт подвязать к 70 обьектам? В этом скрипте сделать копии или можно оптимизировать как шаблон?
conv1.Value = 20 - состояние конвейера (в работе)
Спасибо за внимание         

Simple Scada

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

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

Для вычисления времени наработки по архивным данным рекомендуем использовать Boolean переменные состояния механизма (включен/выключен) вместо целочисленных переменных отвечающих за несколько состояний механизма. Если таких переменных нет на ПЛК, то нужно создать внутренние Boolean переменные с однотипными именами (например conv1_Status, conv2_Status и т.д.) и в скрипте по изменению переменных (conv1, conv2 и т.д.) записывать в соответствующие внутренние переменные значение 1, когда "conv1.AsInt = 20" и записывать 0 в ином случае. Пример универсального скрипта по событию "Изменились переменные":
Код: pascal
var
  aVarStatus: TM_Variable;
begin
  aVarStatus := GetVariableByName(Variable.Name + '_Status');
  if aVarStatus <> nil then       // если переменная существует
    if Variable.AsInt = 20 then   // если переменная вызвавшая скрипт = 20, то
      aVarStatus.Value := True    // записываем True в переменную состояния механизма
    else                          // иначе
      aVarStatus.Value := False;  // записываем False в переменную состояния механизма
end.
Таким образом, в переменных conv1_Status, conv2_Status и т.д. будет сохраняться информация о работе механизмов (1 - включен, 0 - выключен). Далее, как уже было описано выше, для получения суммарного времени наработки можно использовать процедуру ArchiveTimeOn.

AndreyA

#1613
Благодарю за ответ! Но получается что надо знать текущую дату и начальную чтобы вычислить разницу, и как я понял процедура будет запускаться 1 раз в час и вычислять время наработки. В моем случае подсчет может осуществляться несколько лет и наверно постоянный опрос 1 раз в час всего интервала у каждого механизма будет возможно замедлять работу скады. 

Simple_Scada

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

ЦитироватьНо получается что надо знать текущую дату и начальную чтобы вычислить разницу
Текущую дату/время можно получить с помощью функции "Now", а начальную дату если она будет постоянной можно сохранить как константу или задавать ее через переменную (если требуется периодически корректировать начальную дату). Если нужно получать наработку за фиксированный интервал времени (например за последний год), то при помощи методов для работы с датой/временем можно отнимать нужный интервал от текущей даты, например отнять 1 год:
Код: pascal
DateStart := IncYear(Now, -1); // вычисляем начальную дату

Цитироватьи как я понял процедура будет запускаться 1 раз в час и вычислять время наработки. В моем случае подсчет может осуществляться несколько лет и наверно постоянный опрос 1 раз в час всего интервала у каждого механизма будет возможно замедлять работу скады.
Можно обновлять данные реже чем раз в час, например раз в сутки. Для этого можно использовать скрипт "Начало часа" и добавить дополнительную проверку:
Код: pascal
var
  DateStart, DateEnd : TDateTime;
begin
  // запускаем скрипт раз в сутки в 00 часов
  if HourOf(Now) = 0 then
  begin
      DateEnd := Now;                 // текущие дата и время
      DateStart := IncYear(Now, -1);  // вычисляем начальную дату
      // вычислить время включенного состояния переменной "MyVariable" за период
      // от "DateStart" до "DateEnd" и записать результат в переменную "MyVariableRes"
      ArchiveTimeOn(MyVariable, MyVariableRes, DateStart, DateEnd);
   end;
end.

Также, чтобы снизить нагрузку на проект и БД при выборке данных за большие промежутки времени, можно:
1. Выполнять вычисления из прореженного слоя;
2. Вызывать процедуру ArchiveTimeOn порциями, например по 20 переменных.

rogalsky83

#1615
Добрый день!
Есть таблица MySql, которую SCADA заполняет переменными. Эта таблица отображается в SCADA через метод RunSQL компонента таблица. Необходимо корректировать значения некоторых полей вручную из скады.
Пробовал подвязать такой скрипт на событие oncelldatachange таблицы
Код: pascal
var aID, aValue, aField, aQuery:string;
AisString:boolean;
begin
aID:=Table17.GetCell(0, Cell.Row).Text;
aValue:= Table17.GetCell(Cell.Col, Cell.Row).Text;
AisString:= false;
case Cell.Col of
0: exit;
1: aField:='cam';   //
2: aField:='poc';
3: aField:='vol';
4: begin aField:='sta'; AisString:= true; end;
5: begin aField:='end'; AisString:= true; end;
6: begin aField:='ope'; AisString:= true; end;
7: aField:='drd';
8: aField:='drh';
9: aField:='drs';
10: aField:='tck';
11: begin aField:='wid'; AisString:= true; end;
12: begin aField:='por'; AisString:= true; end;
13: begin aField:='typ'; AisString:= true; end;
14: aField:='wms';
15: aField:='wmf';
16: aField:='ene';
17: aField:='qen';
18: aField:='war';
19: aField:='qwa';
20: aField:='zag';
21: aField:='pro';
end;
if AisString then aQuery:= 'UPDATE `test` SET `'+aField+'`='+Quotedstr(aValue) +' WHERE `id`=' +aID+';'
else aQuery:= 'UPDATE `test` SET `'+aField+'`='+aValue +' WHERE `id`=' +aID+';';
RunSQL(aQuery, nil, 134);
end.
, но скрипт не выполняется вероятно из-за того, что не изменялись переменные, связанные с таблицей. Есть ли какая-нибудь возможность выполнить UPDATE поля таблицы БД при изменении соответствующего поля таблицы в SCADA?

Simple_Scada

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

ЦитироватьПробовал подвязать такой скрипт на событие oncelldatachange таблицы, но скрипт не выполняется вероятно из-за того, что не изменялись переменные, связанные с таблицей.
См. описание события "OnCellDatachange". Данное событие выполнится, только если изменится значение переменной, связанной с ячейкой таблицы. Но у Вас, скорее всего, ячейки не связаны с переменными, соответственно, скрипт выполняться не будет.

Посмотрите пример создания таблицы рецептов в БД. В нем реализовано изменение данных в выделенной пользователем строке таблицы и последующее обновление строки в БД – см. описание для кнопки "Изменить".

Alexey Golubev

Как отключить компьютер с сервером simple-scada с использованием скрипта и команды shutdown.exe ?
OPC сервер по модбас опрашивает ПЛК. ПЛК имеет функцию контроля питания компьютера с установленной скадой. Если питание пропало, то есть резервный источник на 5 минут и ПЛК выдает битовый сигнал отключения. OPC опрашивает данный бит раз в секунду. Если бит установлен в 1 то корректно отключаем скаду. Нужно чтобы скада выполнила скрипт отключения . Как это можно сделать?

Simple Scada

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

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

Если на ПК-сервере запущен десктоп-клиент, то в настройках (Options.exe -> Simple-Client -> "Имя этого клиента") необходимо задать уникальное имя (например "Client_Server") для данного клиента и перед выключением ПК завершать его работу, используя процедуру "CloseApplicationClient". Далее, используя процедуру "RunApplication", можно завершить работу ПК-сервера. Пример скрипта на событие "Изменились переменные":
Код: pascal
begin
  if Variable.AsBool then  // если значение переменной вызвавшей скрипт = True(1), то
  begin
    CloseApplicationClient('Client_Server'); // закрыть десктоп-клиент с именем 'Client_Server'
    RunApplication(SS_SERVER_NAME, 'shutdown.exe', '/s /t 30'); // выключить ПК-сервер через 30 секунд
  end;
end.
Если используется битовая переменная, то для получения значения нужного бита используйте функцию "GetBit".

B.B

Использовании в скриптах функции сдвига, например на определённое число минут IncMinute,
в качестве параметра сдвига можно задать только константу.

Возможно ли работать с переменной типа DateTime или TDateTime?

Пока применяются возможности СУБД для работы со временем.