Simple-Scada forum

Simple-Scada 2 => Ваши вопросы => Тема начата: Rolich от 04 Июля 2023, 12:13:03

Название: Запись битовой переменной по времени
Отправлено: Rolich от 04 Июля 2023, 12:13:03
Доброго времени суток, уважаемые форумчане
Может вопрос и простой, но я не нашел решения: как записать значение битовой переменной в заданное время ?
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 04 Июля 2023, 14:06:02
Добрый день. Создаете скрипт "Прошла секунда", получаете из текущей даты и времени (NOW) часы минуты и секунды, сравниваете с заданными, если равно - записать значение переменной.

Код: (delphi)
var 
DT_now : TDateTime;
samebit : Boolean;


begin
DT_now := Now();

   if (HourOf(DT_now) = 12) and (MinuteOf(DT_now)=30) and (SecondOf(DT_now) = 0) then samebit := True;   

end.

В 12:30:00 каждый день установится бит
Название: Re: Запись битовой переменной по времени
Отправлено: Simple_Scada от 04 Июля 2023, 15:34:04
Здравствуйте.

1. Если требуется включать/отключать бит по расписанию, то нужно использовать отдельную Boolean переменную вместо бита и применять компонент "Расписание (https://simple-scada.com/help/manual/schedule.html)".
2. Если нужно выполнять какие-либо действия из скрипта через заданный интервал времени(по таймеру), то пример такого скрипта см. по ссылке (https://simple-scada.com/help/script/second-passed.html).
3. Если нужно выполнять скрипт в начале заданного часа, то можно использовать скрипт с типом события "Прошел час (https://simple-scada.com/help/script/hour-passed.html)".
4. Если требуется выполнять скрипт в какое-то заданное время(например в 12-30), то можно использовать скрипт с типом события "Прошла секунда (https://simple-scada.com/help/script/event-types.html)", в котором сравнивать текущее время с заданным:
Код: (delphi)
begin
  // если сейчас 12:30
  if (HourOf(Now) = 12) and (MinuteOf(Now) = 30) and (SecondOf(Now) = 0) then
  // , то выполнить какое-то действие
end.
Методы для работы с датой/временем можно найти в руководстве по ссылке (https://simple-scada.com/help/script/datetime.html). Если требуется изменить нужный бит переменной, то используйте функцию SetBit (https://simple-scada.com/help/script/setbit.html).
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 05 Июля 2023, 07:23:26
Доброго всем времени суток
Вопрос не совсем об этом
Пример: по одному событию включается таймер на 5 минут. По истечении 5 минут, в зависимости от результата другого события, нужно записать значение битовой переменной 5 минут назад.
Как это сделать ?
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 05 Июля 2023, 08:33:32
Как вариант архивировать переменную по-изменению, потом по истечению таймера использовать функцию работы с архивом

Код: (delphi)
var
  aDate: TDateTime;
  aTimer : Integer;

begin
  aTimer := aTimer * -1;
  aDate:= IncMinute(Now, aTimer); // текущие дата и время минус количество минут в таймере
 
  { извлечь из архива значение переменной "MyVariable" в отметке времени
   "aDate" и записать результат в переменную "MyVariableRes" }
  ArchiveValueByTime(MyVariable, MyVariableRes, aDate);

end.
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 05 Июля 2023, 09:54:17
Спасибо, попробую так. А если мне нужно записать конкретное значение ? Например, такая конструкция будет работать: ArchiveValueByTime(MyVariable, false, aDate) ?
Название: Re: Запись битовой переменной по времени
Отправлено: Simple_Scada от 05 Июля 2023, 10:28:30
Здравствуйте.

Проще будет создать внутреннюю Boolean переменную и записывать в нее значение бита в момент когда "по одному событию включается таймер на 5 минут". Затем "по истечении 5 минут, в зависимости от результата другого события" использовать значение из внутренней Boolean переменной.

Цитировать
Например, такая конструкция будет работать: ArchiveValueByTime(MyVariable, false, aDate) ?
Такая конструкция не будет работать.
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 05 Июля 2023, 10:30:12
А если мне нужно записать конкретное значение ?
Например, такая конструкция будет работать: ArchiveValueByTime(MyVariable, false, aDate) ?
Эта функция принимает в качестве аргумента переменную, поэтому можно создать переменную пустышку и присваивать ей нужное значение перед выполнением функции.
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 05 Июля 2023, 10:32:01
Коллеги, спасибо за помощь !
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 05 Июля 2023, 13:39:10
И всё-таки что-то не работает :(

Имеем глобальные переменные:
1. Переменная Дата_события
2. Переменная Бит_События
3. 2 переменные Всегда_true и Всегда_false

Код
If Событие_1 then Дата_События:=Now;
If Событие_2 then ArchiveValueByTime(Всегда_true, Бит_События, Дата_события.Value) else ArchiveValueByTime(Всегда_false, Бит_События, Дата_события.Value);

Что не так ?
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 05 Июля 2023, 15:56:29
И всё-таки что-то не работает :(

Что не так ?

Не совсем пойму что нужно сделать. Если нужно конкретное значение присвоить, то просто пишем  Бит_события := True или False. Если используем функцию то из архива будет брать не смотря на то какое значение в данный момент. Если хотите присвоить значение которое было во время события 1 то обращаетесь к архивной переменной, если надо присвоить False то просто оператором присвоения :=
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 05 Июля 2023, 15:59:35
Нужно "вернуться в прошлое" в момент Событие_1 и записать либо 0, либо 1 в переменную, в зависимости от События_2
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 05 Июля 2023, 16:03:25
Напишите четко задачу с переменными или код, без абстрактных названий типо событие1 и событие 2. Так ничего непонятно
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 06 Июля 2023, 06:35:37
Доброго всем времени суток
Вообще глобально стоит задача подсчитывать количество и длительность простоя механизма, длительностью от 3 до 5 минут.
Алгоритм сейчас такой: по сигналу Var2 остановки механизма запускается таймер отсчёта простоя Timer, в переменную Vremya записывается время начала простоя
Если таймер простоя находится в интервале от 180 до 300 секунд и механизм продолжает стоять, то в переменную Var1 нужно записать true во время начала простоя
Если таймер простоя перешагнул отметку 300 секунд, в переменную Var1 нужно записать false во время начала простоя, т.е. этот простой не учитывать

Код (скрипт выполняется каждую секунду):
Код: (delphi)
Var
Vremya, Timer:TDateTime;
Var1, Var2, AlwTrue, AlwFalse: Boolean;
K:integer;

Begin
  AlwTrue.Value:=true;
  AlwFalse.Value:=false;
  K:=TimerGetState(Timer);
   if ((Var2.value=false) and (K=-1)) then
   begin
    TimerStart(Timer,0);
    Vremya:=Now;
   end;
   if ((Var2.value=true) and (K=1)) then
   begin
    TimerReset(Timer);
    Var1.Value:=false;
   end;
   if ((Var2.value=false) and ((SecondsBetween(0, Timer.AsDateTime)>180) and (SecondsBetween(0, Timer.AsDateTime)<300))) then ArchiveValueByTime(Alwtrue,Var1, Vremya);
   if ((Var2.value=false) and (SecondsBetween(0, Timer.AsDateTime)>300)) then ArchiveValueByTime(Alwfalse,Var1, Vremya);
end.
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 06 Июля 2023, 09:17:47
В таком случае если переменная Var1 у вас будет архивируемая и вы планируете по ней строить отчеты, создайте в базе данных свою таблицу для простоев с полями простой и время начала. По сигналу Var2 добавляете запросом в таблицу новую строчку INSERT простой, время. Если таймер переходит за 300 то делаете к таблице запрос DELETE запись WHERE время = Vremya. Таким образом у вас будет таблица с простоями которую можно выводить в скаду и строить отчеты.
Название: Re: Запись битовой переменной по времени
Отправлено: Nomad от 06 Июля 2023, 09:55:04
Вообще глобально стоит задача подсчитывать количество и длительность простоя механизма, длительностью от 3 до 5 минут.
У вас уже есть битовая переменная? Может её архивировать по изменению и потом ArchiveTimeOff?
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 06 Июля 2023, 10:27:40
Timothy, т.е. без создания дополнительной таблицы в БД никак не получится ?
Приведённый выше код работать не будет ?

Nomad, вы не совсем поняли, о чём речь
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 06 Июля 2023, 10:41:25
Приведённый выше код работать не будет ?
Функция ArchiveValueByTime берет значение переменной из аргумента 1 во время аргумента 3 и записывает в переменную аргумента 2. То есть в первый аргумент нужно передавать ту переменную которая у вас архивируется в скаде, а не alwaystrue или false. Если хотите сделать хорошую прослеживаемость простоев, то лучше организовывать это средствами БД а не переменных. Архивирование в стандартную таблицу тут не совсем подходит, с своей таблицей БД будет правильнее
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 06 Июля 2023, 10:50:39
Не вижу противоречий в том, что вы описали, с кодом, который приведён выше
Реализация в БД как раз таки и создаёт массу дополнительных проблем для учёта простоев при том, что этот функционал отлично реализован средствами Scada
Прошу экспертов Simple Scada поставить точку в нашей дискуссии - можно ли для решения моей задачи обойтись встроенными средствами, или необходимо писать дополнительный код для работы с БД
Спасибо
Название: Re: Запись битовой переменной по времени
Отправлено: Nomad от 06 Июля 2023, 11:19:57
4. Если требуется выполнять скрипт в какое-то заданное время(например в 12-30), то можно использовать скрипт с типом события "Прошла секунда (https://simple-scada.com/help/script/event-types.html)", в котором сравнивать текущее время с заданным:
Код: (delphi)
begin
  // если сейчас 12:30
  if (HourOf(Now) = 12) and (MinuteOf(Now) = 30) and (SecondOf(Now) = 0) then
  // , то выполнить какое-то действие
end.
Я правильно понимаю, что этот скрипт вызовется 60 раз в течение минуты с 12.30 до 12.31?
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 06 Июля 2023, 11:45:27
Скрипт будет выполняться каждую секунду, пока запущен проект
Условие выполнится только в 12:30:00 ежедневно
Название: Re: Запись битовой переменной по времени
Отправлено: Nomad от 06 Июля 2023, 11:49:49
Если есть типы событий "Прошла секунда" и "Прошёл час", как-то само собой напрашивается ещё и "Прошла минута" )
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 06 Июля 2023, 15:06:24
Я понял своё заблуждение касательно ArchiveValueByTime, оно не запишет мне значение Var1 в указанное время, а только прочитает значение AlwTRue/False
Понятно, что задачу можно решить только через БД
Но остаётся ещё вопрос: можно ли работать со значением Var1 в основной БД Simple SCADA, не создавая свои таблицы ?
Название: Re: Запись битовой переменной по времени
Отправлено: Timothy Clement от 06 Июля 2023, 15:22:25
Но остаётся ещё вопрос: можно ли работать со значением Var1 в основной БД Simple SCADA, не создавая свои таблицы ?
Можно, но делать этого не рекомендуется, хотя в версии архивации v1 у меня есть 1 проект который целиком построен на изменении таблицы trends_data.

По реализации нужного функционала без создания таблицы можно посмотреть в руководстве https://simple-scada.com/help/report/rep-time-work-idle.html (https://simple-scada.com/help/report/rep-time-work-idle.html). Может получится под свою задачу переделать
Название: Re: Запись битовой переменной по времени
Отправлено: Simple_Scada от 06 Июля 2023, 17:48:29
Здравствуйте.

Rolich, прочтите что Вы спрашивали в первом сообщении данной темы и в итоговом описании задачи в этом сообщении (https://simple-scada.com/forum/index.php?topic=1626.msg11823#msg11823). До момента полного описания задачи, в данной теме шла абсолютно бесполезная переписка. Если Вы хотите получить подробный ответ, то в вопросе сразу максимально подробно описывайте задачу целиком(а не ее отдельные фрагменты), при необходимости прилагайте дополнительную информацию(скрипты, скриншоты и т.д.). Тогда можно будет сразу дать подробный и точный ответ. Это значительно сэкономит Ваше и наше время.

Для решения задачи необходимо использовать способ описанный Timothy Clement с некоторыми изменениями. В БД нужно создать свою таблицу и использовать ее в качестве источника данных в отчетах(подробнее см. по ссылке (https://simple-scada.com/help/report/rep-user-data.html)). По сигналу Var2 записывайте время начала остановки в отдельную переменную. Если механизм простаивает нужное время (от 180 до 300 секунд), то в свою таблицу БД можно добавить новую строку с временем начала простоя(из переменной сформированной ранее), время окончания простоя и длительность простоя. По полученной таблице можно будет строить отчеты и при необходимости вывести ее в скаду (https://simple-scada.com/help/script/trunsql.html).

Возможно более простым способом будет использовать штатную систему сообщений (https://simple-scada.com/help/manual/edit-message.html), т.к. при архивации сообщений доступна информация о времени возникновения сообщения, времени завершении сообщения и его продолжительности, чего достаточно для решения описанной задачи. Для этого нужно создать отдельную группу сообщений, к примеру с именем "Простои" и создать в ней сообщения по переменным, для которых требуется отслеживать остановку механизмов. При необходимости эту группу можно скрыть от пользователей через настройку видимости групп сообщений (https://simple-scada.com/help/manual/editor-users.html). Затем в редакторе отчетов нужно создать новый отчет с типом "Сообщения", как это описано в руководстве по ссылке (https://simple-scada.com/help/report/messrep.html). При создании источника в поле "Группа сообщений" необходимо выбрать нашу группу "Простои". Далее в отчете нужно оставить требуемые колонки, например Текст сообщения, Время, Завершено и Длительность. В итоге получится таблица с простоями оборудования.

Для того, чтобы в отчет попадали только простои "в интервале от 180 до 300 секунд" нужно дважды кликнуть по бэнду данных, перейти на вкладку "Фильтры" и создать Фильтр -> Выражение:
Код
(int)Сообщения.Длительность.TotalSeconds > 180 && (int)Сообщения.Длительность.TotalSeconds < 300
, где "Сообщения" - имя источника данных.

Для подсчета общего количества простоев нужно создать бэнд "Итог данных", разместить в нем компонент "Текст", дважды кликнуть по нему и написать выражение:
Код
{Count(DataСообщения)}
, где "DataСообщения" - имя бэнда данных, в который выводятся сообщения.
Название: Re: Запись битовой переменной по времени
Отправлено: Rolich от 07 Июля 2023, 15:02:04
Доброго всем времени суток
Решил проблему чуть более элегантно, без костылей с созданием таблиц и сообщениями.
Суть идеи - в "отложенной" записи значений переменной остановки.
Это вполне решает задачу подсчёта количества остановок от 3 до 5 минут и их длительности штатными средствами Simple Scada
Привожу код, может кому-то будет полезно для решения аналогичной задачи:
Код: (delphi)
K := TimerGetState(Timer_prostoya); // проверяем статус работы таймера простоя

// если переменная механизма в false и таймер простоя не запущен - запускаем его
if ((Var1.value = false) and (K = -1)) then
  TimerStart(Timer_prostoya, 0);

// если механизм включился и таймер простоя в диапазоне 180-300 секунд
if ((Var1.value = true) and ((SecondsBetween(0, Timer_prostoya.AsDateTime) > 180) and
   (SecondsBetween(0, Timer_prostoya.AsDateTime) < 300))) then
begin
  Var2.value := true;  // взводим переменную простоя 3-5 минут
  Dlitelnost_prostoya.value := SecondsBetween(0, Timer_prostoya);  // фиксируем длительность произошедшего простоя
  TimerStart(Timer_3_5, 0);  // стартуем таймер простоя 3-5 минут
end;

// если таймер 3-5 минут достиг значения фактического простоя
if SecondsBetween(0, Timer_3_5.AsDateTime) = Dlitelnost_prostoya.value then
begin
  Dlitelnost_prostoya.value := 0;  // обнулили переменную длительности
  TimerReset(Timer_3_5);  // остановили таймер простоя 3-5 минут
  Var2.value := false;    // сбросили переменную простоя 3-5 минут
end;

if ((Var1.value = true) and (K = 1)) then
  TimerReset(Timer_prostoya); // реальный простой окончен, сбрасываем таймер
Спасибо всем за участие в дискуссии, было познавательно !