Simple-Scada forum

Simple-Scada 2 => Ваши вопросы => Тема начата: vyacheslav от 28 Сентября 2018, 14:23:34

Название: Скрипт (прошел час)
Отправлено: vyacheslav от 28 Сентября 2018, 14:23:34
Добрый день подскажите как правильно реализовать задачу?
Есть переменная с датой, нужно что бы когда текущая дата приблизится к переменной на 2 месяца загоралась авария (переменная аварии переходила в 1)
вот скрипт:
Код: (delphi)
begin
  { если между текущим временем и vrCheckDate осталось меньше 2 месяцев }
  if MonthsBetween(Now, data_poverki_1_1.AsDateTime) < 2 then
    bahilova4_alarm_poverki_1.Value := 1
  else
    bahilova4_alarm_poverki_1.Value := 0;
end.

Проблема в том что он работает правильно и выполняет мои требования но когда проходит 2 месяца после указанной переменной авария пропадает, а мне нужно чтобы авария сохранялась постоянно, пока переменная не поменяется!

и второй вопрос этот скрипт можно использовать только для одной переменной , для другой нужно изменять название переменных.. и так постоянно, это очень неудобно так как их очень много! возможно ли сделать какой нибудь универсальный чтобы использовать для всех?
Название: Re: Скрипт (прошел час)
Отправлено: pan2000 от 28 Сентября 2018, 16:10:19
vyacheslav!
Судя по описанию, значение функции MonthsBetween это интервал между двумя значениями дат, т.е всегда неотрицательно.
Можно сравнивать заданную и текущую дату воспользовавшись определением типа TDateTime в Delphi и сравнивая "по дням":
Код
begin
  bahilova4_alarm_poverki_1.Visible := (NOW() + 60)  >= data_poverki_1_1.AsDateTime;
end.
Сравнение по дням более логично, чем сравнение по месяцам.
Пример во вложении.
Название: Re: Скрипт (прошел час)
Отправлено: Simple-Scada от 30 Сентября 2018, 09:52:28
Здравствуйте.

Цитировать
но когда проходит 2 месяца после указанной переменной авария пропадает
Как выше отметил pan2000, функция MonthsBetween всегда возвращает положительное значение, поэтому в ваше условие нужно добавить проверку
Код: (delphi)
var
  myDate: TDateTime;
begin
  myDate := data_poverki_1_1.AsDateTime;
  { если между текущим временем и vrCheckDate осталось меньше 2 месяцев }
  if (Now > myDate) and (MonthsBetween(Now, myDate) < 2) then
    bahilova4_alarm_poverki_1.Value := 1
  else
    bahilova4_alarm_poverki_1.Value := 0;
end.

Цитировать
возможно ли сделать какой нибудь универсальный чтобы использовать для всех?
У Вас переменная даты/времени "data_poverki_1_1" привязана к какому-либо объекту? Допустим она привязана к объекту Календарь (https://simple-scada.com/help/manual/calendar.html) в качестве основной переменной. Тогда назначаем этому же календарю переменную "bahilova4_alarm_poverki_1" в качестве дополнительной (см. скрин во вложении) в меню скриптов создаём новый универсальный скрипт со следующим кодом:
Код: (delphi)
var
  aObject: TM_Object;
  myDate: TDateTime;
begin
  { прерываем скрипт, если он вызван не объектом }
  if not (Sender is TM_Object) then Exit;
  aObject := Sender as TM_Object;

  { дату/время берём из основной переменной объекта }
  myDate := aObject.AsDateTime;
  {  меняем доп. переменную в зависимости от условия }
  if (Now > myDate) and (MonthsBetween(Now, myDate) < 2) then
    aObject.VariableEx.Value := 1
  else
    aObject.VariableEx.Value := 0;
end.

Теперь этот скрипт привязываем к событию OnDataChange календаря. Далее можно создать сколько угодно объектов, назначить им основную и дополнительную переменную и привязать данный универсальный скрипт на событие OnDataChange. Напишите если что-то непонятно.
Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 01 Октября 2018, 09:24:33
Цитировать
Как выше отметил pan2000, функция MonthsBetween всегда возвращает положительное значение, поэтому в ваше условие нужно добавить проверку
var
  aObject: TM_Object;
  myDate: TDateTime;
begin
  { прерываем скрипт, если он вызван не объектом }
  if not (Sender is TM_Object) then Exit;
  aObject := Sender as TM_Object;
 
  { дату/время берём из основной переменной объекта }
  myDate := aObject.AsDateTime;
  {  меняем доп. переменную в зависимости от условия }
  if (Now > myDate) and (MonthsBetween(Now, myDate) < 2) then
    aObject.VariableEx.Value := 1
  else
    aObject.VariableEx.Value := 0;
end.
что то не пойму, этот скрипт не работает так как нужно мне. он переводит переменную bahilova4_alarm_poverki_1 в 1, только когда значение переменной data_poverki_1_1 равно текущей дате и держит ее в 1, 2 месяца и потом переводит в 0. А по моему условию перемененная bahilova4_alarm_poverki_1 должно становиться 1, когда значение переменной data_poverki_1_1 становиться меньше текущей на 2 месяца и держит ее постоянно в 1, пока я не поменяю значение переменной в дату которая больше текущей минимум на 2 месяца.
Название: Re: Скрипт (прошел час)
Отправлено: Simple-Scada от 01 Октября 2018, 09:53:19
Цитировать
А по моему условию перемененная bahilova4_alarm_poverki_1 должно становиться 1, когда значение переменной data_poverki_1_1 становиться меньше текущей на 2 месяца и держит ее постоянно в 1, пока я не поменяю значение переменной в дату которая больше текущей минимум на 2 месяца.
Тогда нужно брать условия из кода Вашего первого сообщения, без изменений и использовать их:
Код: (delphi)
var
  aObject: TM_Object;
  myDate: TDateTime;
begin
  { прерываем скрипт, если он вызван не объектом }
  if not (Sender is TM_Object) then Exit;
  aObject := Sender as TM_Object;
 
  { дату/время берём из основной переменной объекта }
  myDate := aObject.AsDateTime;
  { меняем доп. переменную в зависимости от условия }
  if (MonthsBetween(Now, myDate) < 2) then
    aObject.VariableEx.Value := 1
  else
    aObject.VariableEx.Value := 0;
end.
Учитывайте также, что данный универсальный скрипт ставится на событие OnDataChange и будет срабатывать только при изменении переменной даты (data_poverki_1_1). Соответственно переменная аварии (bahilova4_alarm_poverki_1) будет меняться только в эти моменты.
Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 01 Октября 2018, 10:09:41
ну в таком случае одна проблема ушла.. у меня появился универсальный скрипт.
но вторая проблема осталась, если значение переменной data_poverki_1_1 ставлю ниже текущей даты на 2 месяца то переменная bahilova4_alarm_poverki_1 остается в 0, а по проекту это авараия и должна быть 1
Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 01 Октября 2018, 10:18:59
Цитировать

Учитывайте также, что данный универсальный скрипт ставится на событие OnDataChange и будет срабатывать только при изменении переменной даты (data_poverki_1_1). Соответственно переменная аварии (bahilova4_alarm_poverki_1) будет меняться только в эти моменты.
то есть я правильно понял если переменная bahilova4_alarm_poverki_1 перевелась в 1, то ей и останется пока переменная data_poverki_1_1 не поменяется. в не зависимости от тога прошло 2 и более месяца с даты (data_poverki_1_1).?

но проблема в том если вносишь дату переменной data_poverki_1_1 сразу ниже текущей на 2 месяца (это аварийное событие) то она не переводит bahilova4_alarm_poverki_1 в еденицу (не считает ее аварией)
Название: Re: Скрипт (прошел час)
Отправлено: Simple-Scada от 01 Октября 2018, 10:26:49
Цитировать
то есть я правильно понял если переменная bahilova4_alarm_poverki_1 перевелась в 1, то ей и останется пока переменная data_poverki_1_1 не поменяется. в не зависимости от тога прошло 2 и более месяца с даты (data_poverki_1_1).?
Да, т.е. весь скрипт и его проверки будут выполнены только при изменении переменной даты data_poverki_1_1.

Этот код:
Код: (delphi)
if (MonthsBetween(Now, myDate) < 2) then
  aObject.VariableEx.Value := 1
else
  aObject.VariableEx.Value := 0;
работает очень примитивно. Он записывает 1 в переменную аварии всегда, когда переменная даты приблизилась к текущей дате менее чем на 2 месяца (с любой стороны, с будущего, либо с прошедшего времени) и 0 во всех иных случаях.

Цитировать
но проблема в том если вносишь дату переменной data_poverki_1_1 сразу ниже текущей на 2 месяца (это аварийное событие) то она не переводит bahilova4_alarm_poverki_1 в еденицу (не считает ее аварией)
Верно, потому что в Вашем коде, приведённом выше, в переменную аварии запишется 0, если переменная даты ушла от текущей даты на 2 и более месяца. Чтобы было наоборот, можно изменить знак в условии:
Код: (delphi)
if (MonthsBetween(Now, myDate) >= 2) then
  aObject.VariableEx.Value := 1
else
  aObject.VariableEx.Value := 0;
Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 01 Октября 2018, 13:52:10
Цитировать
Верно, потому что в Вашем коде, приведённом выше, в переменную аварии запишется 0, если переменная даты ушла от текущей даты на 2 и более месяца. Чтобы было наоборот, можно изменить знак в условии:
Код: (delphi)
if (MonthsBetween(Now, myDate) >= 2) then
  aObject.VariableEx.Value := 1
else
  aObject.VariableEx.Value := 0;
Это совсем не то..... меня полностью устраивает первый скрипт, за исключением того что через два месяца после даты , авария снимается.. можно дописать код чтобы авария работала и дальше пока переменная не поменяется на новую?
Название: Re: Скрипт (прошел час)
Отправлено: Simple-Scada от 01 Октября 2018, 14:16:36
Цитировать
за исключением того что через два месяца после даты , авария снимается
Просто добавьте нужное Вам условие перед снятием аварии, чтобы авария не снималась:
Код: (delphi)
if (MonthsBetween(Now, myDate) < 2) then
  aObject.VariableEx.Value := 1
else
  { снимаем аварию только если заданная дата находится "до" текущей даты }
  if (myDate < Now) then
    aObject.VariableEx.Value := 0;
В этом варианте переменная аварии не будет сниматься если значение даты больше (т.е. стоит после) текущей даты (не важно на сколько месяцев).
Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 01 Октября 2018, 15:12:21
Цитировать
за исключением того что через два месяца после даты , авария снимается
Просто добавьте нужное Вам условие перед снятием аварии, чтобы авария не снималась:
Код: (delphi)
if (MonthsBetween(Now, myDate) < 2) then
  aObject.VariableEx.Value := 1
else
  { снимаем аварию только если заданная дата находится "до" текущей даты }
  if (myDate < Now) then
    aObject.VariableEx.Value := 0;
В этом варианте переменная аварии не будет сниматься если значение даты больше (т.е. стоит после) текущей даты (не важно на сколько месяцев).


Точно, все верно, тоько знак нужно поменять в другую сторону! (myDate > Now) Спасибо большое.   
Название: Re: Скрипт (прошел час)
Отправлено: pan2000 от 04 Октября 2018, 00:56:56
Конструкции из вложенных if:
Код: (delphi)
if (MonthsBetween(Now, myDate) < 2) then
  aObject.VariableEx.Value := 1
else
  { снимаем аварию только если заданная дата находится "до" текущей даты }
  if (myDate > Now) then
    aObject.VariableEx.Value := 0;

определяет значение переменной aObject.VariableEx.Value следующим образом:
Код
   относительное значение Now - myDate |   -2             0              +2     
 -----------------------------------------------------------------------------------> время (месяцев)
      (MonthsBetween(NOW, myDate) < 2) |  false  |      true       |  false
 -----------------------------------------------------------------------------------------------
                       (myDate > Now)  |  true   |         х       |  false
 -----------------------------------------------------------------------------------------------
              aObject.VariableEx.Value |     0   |         1       |  сохраняет значение
 -----------------------------------------------------------------------------------------------

Значение переменной aObject.VariableEx.Value в случае "когда проходит 2 месяца после указанной переменной" (NOW - myDate) > 2
определено предисторией, т.е. при перезапуске проекта в этом временном интервале пременная будет инициализирована 0.

Доопределить значение переменной для всего временого интервала можно добавив альтернативу else с присвоением переменной 1 или
объеденив два условия:
Код: (delphi)
if (MonthsBetween(Now, myDate) < 2) or (myDate < Now) then  // интервал между датами < 2 месяцев ИЛИ дата поверки уже прошла
  aObject.VariableEx.Value := 1
else
  aObject.VariableEx.Value := 0;

Название: Re: Скрипт (прошел час)
Отправлено: vyacheslav от 04 Октября 2018, 07:09:25
Спасибо большое за помощь, вы правы!