Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Не получили письмо с кодом активации?

Официальный форум Simple-Scada.

Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Сообщения - pan2000

Страницы: 1 [2] 3 4 ... 15
16
Ваши вопросы / Re: Работа с таблицами
« : 12 Апреля 2025, 06:23:56 »
 Здравствуйте.

И есть ли возможность заполнения таблицы из БД полностью на всю форму без прокручивания (на картинке). В таблице количество строк равно 40.
Заполнить таблицу, состоящую из нескольких групп однотипных столбцов, "змейкой" можно (по крайней мере в MySQL версии 8.0) с использованием оконной функции LEAD.
Так для таблицы my_table из БД со столбцами col1, col2, col3 запрос на заполнение таблицы в Simple-Scada из двух групп не более чем в 20 строк:
SELECT *, LEAD(col1,20) OVER(),LEAD(col2,20) OVER(),LEAD(col3,20) OVER() FROM my_table LIMIT 20; 
Реальный запрос может быть усложнен за счёт замены NULL на пустую строку, форматирования данных, добавления вычисляемых столбцов. Скрин показывает результаты работы запроса по таблице из предыдущих примеров. Запрос для левой половины таблицы включает замену NULL, вычисление и форматирование столбца, правая - только вычисления.


17
Ваши вопросы / Re: Работа с таблицами
« : 10 Апреля 2025, 12:27:28 »
   Здравствуйте.
Я это воспринял как автоматическое с датчика, а если заносится ручками, то смотрите пример @pan2000.
Наличие раздельных переменных для меток заезда и выезда не обязательно указывает на "ручки" :-\, равно как и ввод значения метки в поле. Достаточно изменить события на "Изменилась основная переменная" и это будет вариант для помещения с раздельным заездом и выездом (например, туннельная печь).
Для единственного поля ввода метки (считывателя) - заезд/выезд определяется по наличию тележки в помещении. Пример во вложении.

18
Ваши вопросы / Re: Работа с таблицами
« : 09 Апреля 2025, 20:44:07 »
   Здравствуйте.

  Размер таблицы ограничен 40 строками, резонно предположить что больше тележек просто-напросто не входит в помещение или в наличии не больше 40 меток тележек.
  В примере (для БД MySQL, не более 40 меток) используется пара совмещенных таблиц: верхняя - прозрачная, содержащая собственно данные о тележках (метки событий урезаны только до времени), нижняя - с широкими колонками, перекрывающими набор колонок верхней, и полным значением времени заезда (дата-время).
Такое решение позволяет избежать нудных перекрашиваний группы ячеек из верхней таблицы и получать правильное значение времени нахождения в помещении (независимо от перезапусков сервера), как разность текущего времени и времени заезда.

Таблица содержит все последние завершенные (в том числе удачные) и все текущие переезды тележек. Можно исключить из таблицы удачно завершенные переезды, однако гарантировано увеличить количество меток (при условии что в помещении одновременно не более 40 тележек) не получится, т.к. в таблице могут присутствовать красные строки для тележек вне помещения.
При новом заезде тележки информация о предыдущем заезде удаляется из таблицы посредством смены знака у идентификатора тележки, что позволяет сохранять предысторию.
При запуске проекта и по событиям "Заезд тележки №№", "Выезд тележки №№", "Удаление из таблицы тележки №№" происходит заполнение таблицы из БД с раскладкой данных из набора данных DataSet.
Вычисление текущего времени нахождения в помещении  тележек и "раскраска" нижней таблицы осуществляются по таймеру 1 сек.

P.S. Для уменьшения скрипта раскладки данных используется более сложная форма запроса, при желании можно свести запрос к минимальному и усложнить обработку в скрипте (это по поводу смены БД).
Пример только для иллюстрации: задание интервала контроля ограничено 23:59:59, длительность нахождения в помещении ограничена ~ 800 часами, нет контроля общего числа тележек в помещении.
При условии не более 40 тележек в помещении, было бы правильно отображать в таблице состояния присутствующих в помещении тележек, а преждевременный выезд тележек перенести в отдельную таблицу.

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

По видимому, объекты формы используются только для задания части начальных значений перед работой с окном-формой, и не предполагают изменения свойств входящих в форму объектов.
Для исключения возможных ошибок/конфликтов в скрипте обработки формы следует использовать данные только из FormData. Пример ошибки подобного сорта:
- в моём предыдущем примере обнаружен КОНФЛИКТ при работе нескольких клиентов - способ передачи выбранной переменной в скрипт обработки формы посредством основной переменной поля-формы ввода значения переменной, которая не локализуется в форме и является общей для всех клиентов. При отправки формы изменялись свойства переменной из последнего открытого окна-формы.
Исправление: имя выбранной переменной передается через дополнительное невидимое поле, локализуемое в форме.

Пример с исправлениями и возможностью изменения типа границ во вложении.

В настройках проекта можно включить сохранение значений и типа границ, тогда они будут сохраняться при перезапуске проекта.

20
Ваши вопросы / Re: Ввод данных типа Single
« : 26 Марта 2025, 15:15:41 »
   Здравствуйте.

  Для ограниченного набора возможных значений переменной ввода (в Вашем случае 10001 значение) можно использовать целочисленную переменную PositionTC со сдвигом запятой -1.
Код: (delphi)
begin
   case PositionTC.AsVariant of
        0..160      : wNumberPlace.Value := 1;
        161..1000   : wNumberPlace.Value := 2;
        1001..5000  : wNumberPlace.Value := 3;
        5001..7000  : wNumberPlace.Value := 4;
        7001..10000 : wNumberPlace.Value := 5;
      end;
end.

Для вещественной переменной можно использовать округление до ближайшего целого:
Код: (delphi)
...
  case Round(PositionTC_1.AsSingle * 10) of
...

21
Ваши вопросы / Re: Страница трендов
« : 18 Марта 2025, 10:31:11 »
   Здравствуйте.

Если достаточно просмотра тренда с момента клика по ячейке, то можно использовать временной тренд с одном трендом и переключением переменной.
В противном случае (поскольку данные накапливаются) необходим индивидуальный тренд для каждой переменной. В зависимости от общего количества трендов это может быть один временной тренд или несколько. Нужный тренд выбирается управлением видимостью тренда/временного тренда.
Наиболее простой вариант это единственный временной тренд (в предположении, что количество трендов не превысит максимального для временного тренда ?) и следующие правила:
- тренд выбирается по клику по строке таблицы;
- для выбора тренда используется поиск по их переменным до совпадения с дополнительной переменной ячейки;
- шкала устанавливается по минимуму-максимуму переменной;
- количество меток шкалы и линий по Y определяются шкалой переменной в свойстве "Единица измерения". Если это свойство используется в проекте, то простых решений, кроме фиксированного значения в редакторе, нет.
Пример с двумя просто переменными и одной с генератором пилы во вложении. 

При необходимости можно выбирать для одновременного просмотра и тренды нескольких переменных (определивши как отображать шкалу и т.д.), но это уже другая история...

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

  Для просмотра/редактирования одиночной переменной и её свойств можно создать обычное (или модальное) окно-форму.
При открывании окна в форму передаются переменная с набором просматриваемых/редактируемых свойств.
По заполнении данные из формы переписываются в свойства переменной.
Пример во вложении.

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

...наверное, можно как то автоматически их обнулять...

  Кнопка/кнопки изменяют состояния по действиям оператора и изменению состояния установки. Пример для некоторой модели установки во вложении.
Модель установки на основе реверсивного счетчика, по значениям переменных SCi_pusk и SCi_stop формирует временные диаграммы сигналов состояния системы в переменной SCo_Kod__Sostoyanie_:
- бит 0: 1 - система стоит, 0 - работает;
- бит 5: 32 - жалюзи открываются/закрываются, 0 - в покое;
- бит 10: 1024 - двигатель включен, 0 - выключен.

1. Кнопка имеет четыре состояния: ПУСК, ОТКР., СТОП, ЗАКР. Основная переменная связана с вспомогательной переменной состояния кнопки, дополнительная с переменной состояния системы.
В состояниях ОТКР. и ЗАКР. кнопка недоступна, а переход к следующему состоянию определяется значением переменной состояния системы.
Скрипты по изменению основной и дополнительной переменных:
Код: (delphi)
begin
  with Sender as TM_Object do
  begin
    Enabled := not GetBit(AsInt, 0);  // недоступна в нечетных состояниях кнопки (ОТКР. и ЗАКР.)
// конверсия состояний кнопки в состояние управляющих переменных
    case AsInt of
    0: begin SCi_pusk.Value := false; SCi_stop.Value := false; end;
    1: begin SCi_pusk.Value := true; SCi_stop.Value := false; end;
//    2: begin SCi_pusk.Value := true; SCi_stop.Value := false; end;
    3: begin SCi_pusk.Value := false; SCi_stop.Value := true; end;
    end;
  end;
end.
Код: (delphi)
// обратная связь от установки
begin
  with Sender as TM_Object do
  begin
    case AsInt of
    1: if GetBit(VariableEx.AsInt, 10) then value := 2;       // от включения двигателя
//    3: if not GetBit(VariableEx.AsInt, 5) then value := 0;    // от закрытых жалюзи
    3: if GetBit(VariableEx.AsInt, 0) then value := 0;        // от состояния системы
    end;
  end;
end.

2. Пара двоичных кнопок с общим вектором состояния, Однако в этом случае скрипты становятся сложнее, а информативность ниже, т.к. допустимы только три состояния вектора (запрещено - доступны одновременно ПУСК и СТОП). 

24
   Здравствуйте.
Условие:
по сути, притенять кнопку нужно от момента нажатия, до значения переменной 1024. после этого она должная стать активной и перейти в состояние 2
предполагает наличие трёх состояний и, соответственно трех графических образов, причем собственно нажатие кнопки переведет её в следующее состояние.
Возможные варианты создания третьего притемненного состояние:
- при нажатии кнопка становится невидимой, графический объект (Текст, Кнопка или ...) размещенный непосредственно под кнопкой изображает притемненное состояние. По достижении условия кнопка вновь становится видимой;
- добавление третьего (притемненного) состояния к кнопке. в котором кнопка становится "Недоступной". По достижении условия кнопка переходит в состояние "Стоп" и вновь становится доступной;
- аналогично предыдущему варианту, но с использованием автомата состояний. Кнопка прикрыта сверху прозрачным объектом, управляющим автоматом с переходами по нажатию: "Пуск"->"Притемнение", "Притемнение"->"Притемнение", "Стоп"->"Пуск". По достижении условия автомат переходит в состояние "Стоп".
Притемненное состояние кнопки может использоваться для индикации промежуточных состояний (разумеется если они могут быть выделены):
ПУСК -> двигатель запускается -> жалюзи открывается -> что-то ещё случается -> СТОП
Примеры вариантов во вложении.

25
  Здравствуйте.
Последовательность действий для кнопки с инвертированием состояния:
- проверить что выбранная по клику ЛКМ ячейка это именно кнопка (варианты: переключение точно по кнопке или по строке);
- инвертировать бит переменной определяющий состояние кнопки (переменная привязана к дополнительной переменной ячейки);
- изменить индикацию кнопки-ячейки по состоянию бита.
Скрипт по событию OnCellClick:
Код: (delphi)
begin
  with Cell do
  begin
    if (Col <> 3) or (Row <> 1) then exit;                // клик ЛКМ не на кнопке - выход
    VariableEx.Value := InverseBit(VariableEx.Value, 0);  // инвертировать бит
    if GetBit(VariableEx.AsInt, 0) then                   // изменить индикацию кнопки-ячейки
    begin                                                 //  по текущему состоянию бита
      Text := 'Выкл';
      Color := clGreen;
    end
    else
    begin
      Text := 'Вкл';
      Color := clRed;
    end;
  end;
end.
В редакторе должны быть установлены цвет и текст ячейки в соответствии с начальным состоянием бита переменной.

При большом количестве кнопок проверка принадлежности ячейки к множеству кнопок становится весьма громоздкой. Для упрощения можно использовать определенные соглашения:
- дополнительная переменная есть только у кнопок;
- оператор case по выражению (Col * 10000 + Row) с возможностью выбора номера бита переменной (пример во вложении), и т.д.


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

 Можно получить выборку последовательным выполнением трёх запросов для временных общих табличных выражений с использованием оконных функций выбора предыдущего/последующего значений LAG и LEAD:
- выделение переходов значений value с фильтрацией по идентификатору переменной id и, возможно, по интервалу времени для timestamp. Поиск начинается с перехода 0->1, для первой строки в качестве предыдущего значения выбирается 0:

SELECT id,timestamp AS time1,value AS value1,LAG(value,1,0) OVER() AS value2 FROM trends_data WHERE id=1;

- формирование временных интервалов для значений value=1 и value=0:

WITH ttemp1 AS (SELECT id,timestamp AS time1,value AS value1,LAG(value,1,0) OVER() AS value2 FROM trends_data WHERE id=1) SELECT id,time1,LEAD(time1,1,' ещё не завершен') OVER() AS time2,value1,value2 FROM ttemp1 WHERE value1<>value2;

- прореживание интервалов только для значений value=1:

WITH ttemp2 AS (WITH ttemp1 AS (SELECT id,timestamp AS time1,value AS value1,LAG(value,1,0) OVER() AS value2 FROM trends_data WHERE id=1) SELECT id,time1,LEAD(time1,1,' ещё не завершен') OVER() AS time2,value1,value2 FROM ttemp1 WHERE value1<>value2) SELECT * FROM ttemp2 WHERE value1=1;


27
Ошибки / Артефакты функции ArchiveValueByTime
« : 02 Декабря 2024, 01:57:47 »
     Здравствуйте.

Значение функции ArchiveValueByTime отличается от значения из архива при одинаковой временной метке.

Тест:
- генерация возрастающей последовательности с периодом 1 секунда;
- запись в таблицу до 32 последних пар значений-времени последовательности по команде (т.е. последних реально записанных в БД);
- по клику на строке таблицы вызывается функция с параметром времени из этой строки, результат записывается в последний столбец этой строки, теперь можно сравнить значения из архива и функции.

Управление:
- кнопка "ОСТАНОВИТЬ ЗАПИСЬ"/"ПРОДОЛЖИТЬ" - останов/продолжение счета последовательности (запись в архив по изменению переменной);
- кнопка "ЗАПОЛНИТЬ ТАБЛИЦУ" - запись в таблицу;
- кнопка "ВЫЧИСЛИТЬ ФУНКЦИЮ" - вычислить функцию по всем строкам;
- параметр "Сдвиг, сек" [-20..20] - сдвиг значения параметра функции.

Собственно тестирование:
- предварительно желательно очистить таблицы проекта и контролировать таблицу трендов средствами БД.
- запустить проект и подождать пока значение последовательности достигнет значения больше 32 (ожидаемая запись буферов), заполнить таблицу;
- вычислить функцию и/или одиночное вычисление/перевычисление функции по ЛКМ на строке;
- изменяя значение параметра "Сдвиг" можно добиться совпадения значений функции со значениями из таблицы. (магическое значение параметра равно -9). Магическое значение сохраняется и для последовательности с периодом 2 секунды.

Ещё есть предположение, что последнее значение (уже архивированное или в буфере) не требует сдвига.

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

Во вложении проект исправленный для чтения из CSV-файла, имена параметров обезличены от физического смысла и называются "Параметр для верхней строки" и "Параметр для первого столбца". 

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

  Двумерная калибровка включает следующие действия:
- чтение таблицы калибровки из файла в динамический массив при запуске проекта. Значений параметров температуры и давления хранятся столбце и строке с нулевым индексом;
- поиск для давления и температуры пары индексов интервала значений параметров, включающих давление и температуру;
- вычисление интерполированного значения из таблицы: совпадение индексов в обоих парах - выборка из таблицы, при одной совпадающей паре индексов - линейная интерполяция, индексы в обоих парах различны - двумерная интерполяция. Значения температуры и/или давления вне таблицы считаютcя соответствующими граничными значениями. 

Пример таблицы калибровки, комментарии строк показаны исключительно для описания структуры, в файле комментарии не допускаются:                                                           
фрагмент таблицы из  https://studfile.net/html/2706/401/html_WtevgQQelM.i4K9/img-S7y52D.png    // заголовок, игнорируется при загрузке файла
000   1.0   1.1   1.5   2.0   5.0  15.0          // 000 - исключительно для сохранения числа переменных в строке, переменные это значения давления для соответствующего столбца
 60 219.1 213.9 218.6 218.5 216.6 208.0     // первое число - значение температуры, далее значения энтальпии для соответствующих значений температуры и давления
 70 223.5 223.3 223.0 222.9 221.1 213.3     // разделитель чисел - пробел, пробелы перед числом игнорируются, для всех строк обязательно одинаковое количество чисел

Пример во вложении. Вывод отладочной информации позволяет изучить алгоритм проекта.

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

  Можно превратить шаблон в подобие объекта пользователя (или "сгруппированный объект"), характеризующегося поведением шаблона как единого целого. Условно можно разделить общие свойства шаблона на две части - не изменяющие геометрию составляющих объектов: перемещение, управление цветом, доступом и видимостью, так и изменяющие: масштабирование, поворот. Последних следует избегать, так как есть возможность (особенно для WEB-клиента) появление артефактов на картинке.
  Для начала нужно при инициализации шаблона связать объекты посредством последовательных ссылок в UserData, что позволит изменять объект без использования его переменных. Такая последовательность обезличена, можно использовать один универсальный скрипт. Аналогичную последовательность ссылок можно создать при запуске проекта и для группы обычных объектов.
  Управления свойствами шаблона осуществляется по изменению переменных, связанных с первым объектом последовательности (т.е. последовательность нужно начинать с объекта не использующего переменные проекта или с дополнительного объекта, предназначенного исключительно для управления свойствами шаблона).
  Во вложении пример циклического перемещения шаблона по Х-координате в пределах экрана. Для иллюстрации экзотических возможностей в пример добавлена простейшая операция зеркального отражения шаблона по Х (изменение знака ширины объекта). Однако, как и следовало ожидать, простота оборачивается артефактами картинки, особенно для WEB-клиента.



Страницы: 1 [2] 3 4 ... 15