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

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

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

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


Сообщения - pan2000

Страницы: 1 ... 11 12 [13] 14
181
... вот я и хотел бы разделить запись точки и запуск секундной паузой что бы записи переменных не накладывались друг на друга.
Использование сдвиг-регистра для формирования временной диаграммы с периодом 1 сек.
Код: (delphi)
...
kuda_exat.Value := <очередной элемент таблицы движения>;  // запуск очередного цикла движения
sh_reg.Value := 1;                                        // внутренний тег типа integer
...
Скрипт "Прошла секунда"
Код: (delphi)
...
if GetBit(sh_reg.AsInt,2) then pusk_opc.Value := true;  // задержка от 1 до 2 сек.
sh_reg.Value := sh_reg.AsInt + sh_reg.AsInt;            // сдвиг на 1 разряд влево
...
Во вложении пример для модели загрузчика. Для просмотра трендов надо подключить БД.

182
А где поставил переменная ArduinoSerial0_D2 ?

Присвоение значений переменной ArduinoSerial0_D2:
Код
var i:integer;
begin
  iButtons.Value := Sender.Tag and iButtons.AsInt;   //  не более одной нажатой кнопки
// действия по кнопкам
  case iButtons.AsInt of
    2: i := 15;  // значения взяты из примера Button_without_scripts
    4: i := 50;
    8: i := 75;
   16: i := 200;
  else
    i := 0;
  end;
  ArduinoSerial0_D2.Value := i;
end.

183
emoxristov!
 
Возможно Вам подойдет "радиокнопка", в примере два варианта алгоритма:
- не более одной нажатой кнопки (см. этот);
- только одна нажатая кнопка.

Кнопки с фиксацией и управляются битами переменной iButtons, тег кнопки равен битовой маске.
Переменная кнопок модифицируется скриптами по событию "Пользователь кликнул объект мышью"
Код
begin
  iButtons.Value := Sender.Tag and iButtons.AsInt;   //  не более одной нажатой кнопки
// действия по кнопкам
  case iButtons.AsInt of
      . . .
  end;
end.

Код
begin
  iButtons.Value := Sender.Tag;   // только одна нажатая кнопка
// действия по кнопкам
  case iButtons.AsInt of
      . . .
  end;
end.


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

При данных условиях вполне подходит переключатель из объекта "Уровень" при условии, что его переменная доступа целого типа со шкалой [0-1].
Процесс переключения заключается в перемещении указателя мыши на движок, захвата движка и его перемещении более чем на половину шкалы, что более сложно, чем просто переместить указатель на объект и нажать ЛКМ.
"Пример" во вложении.

185
Здравствуйте!
Не подскажите как из  скрипта для кнопки получить значение Tag(дополнительной переменной) подстраницы на которой находится эта кнопка .Скрипт должен быть универсальным без явного прямого обращения   

Получить пары: <тэг текущей подстраницы> - <тэг объекта> можно следующими способами:

1. Разделить собственный тэг объекта на два поля: <тэг подстраницы><тэг объекта> с учетом количества объектов и подстраниц. 
Скрипт для десятичного представления тэга (до 100 объектов): <тэг подстраницы> * 100 + <тэг объекта>
Код: (delphi)
var
  aName: string;
  aTagPage: string;
begin
  . . .
  aName := IntToStr(Sender.Tag div 100);
  aTagPage := IntToStr(Sender.Tag mod 100);
  . . .
end.

2. Использование переменной для хранения тэга текущей подстраницы iTagPage.
   Скрипты для отслеживания перемещения по страницам/подстраницам:
   Событие "Пользователь перешел на эту страницу/подстраницу":
Код: (delphi)
begin
// для подстраницы - установить ее тэг, для страницы - восстановить тэг подстраницы, открытой последней на этой странице
  iTagPage.Value := Sender.Tag;
end.
   Событие "Пользователь покинул эту страницу":
Код: (delphi)
begin
  Sender.Tag := iTagPage.AsInt;    // запомнить тэг подстраницы, открытой последней на этой странице
    Начальные значения:
Тэг страницы равен тэгу первой подстраницы.
Начальное значение переменной iTagPage равно тэгу первой подстраницы первой страницы.

Пример для объектов типа Text (2 в 1: управление - индикация) во вложении.


P.S. На мой взгляд задавать вопрос "как сделать" следует в отдельной теме (поиск по названию темы, ответы в одном месте,
возможность продолжения).


186
Ваши вопросы / Re: Скрипт (прошел час)
« : 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;


187
Ваши вопросы / Re: Скрипт (прошел час)
« : 28 Сентября 2018, 16:10:19 »
vyacheslav!
Судя по описанию, значение функции MonthsBetween это интервал между двумя значениями дат, т.е всегда неотрицательно.
Можно сравнивать заданную и текущую дату воспользовавшись определением типа TDateTime в Delphi и сравнивая "по дням":
Код
begin
  bahilova4_alarm_poverki_1.Visible := (NOW() + 60)  >= data_poverki_1_1.AsDateTime;
end.
Сравнение по дням более логично, чем сравнение по месяцам.
Пример во вложении.

188
Update: начиная с версии Simple-Scada 2.3.2.0 у переменных можно включить опцию "Автоматическое восстановление". Тогда скада будет автоматически сохранять значение переменной и восстанавливать его при перезапусках проекта.

Rinat!
Виртуальные переменные можно устанавливать из файла при запуске и сохранять в файл при останове проекта. Пример для 4-х целочисленных счетчиков времени работы. Восстановление данных - скрипт по событию "Запуск проекта":
Код: (delphi)
var i: integer;
begin
  if not FileOpen('MyBinaryFile.dat', '') then exit;  // или иные действия при ошибке файла

  if FileSize = 0 then begin                 // новый файл без данных
    for i := 1 to 4 do FileWriteInteger(0);  // заполнить 0
    FileSeek(0, soBeginning);                // указатель на начало
  end;

  for i := 1 to 4 do                         // установить значения таймеров из файла
    GetVariableByName('iTimer_' + IntToStr(i)).Value := FileReadInteger;

  FileClose;
end.

Сохранение данных - скрипт по событию "Останов проекта":
Код: (delphi)
var i: integer;
begin
  if not FileRecreate('MyBinaryFile.dat', '') then exit;   // новый файл не создан
  for i := 1 to 4 do
    FileWriteInteger(GetVariableByName('iTimer_' + IntToStr(i)).Value);
  FileClose;
end.

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

vrTimer_1 ... vrTimer_8 - "массив" таймерных переменных;
iDevVector - вектор состояния устройств (для соответствующего устройству разряда: 1 = вкл, 0 = выкл.)
Код: (delphi)
var i: integer;
    tmr: TM_Variable;
begin
  for i := 1 to 8 do
    begin
      tmr := GetVariableByName('vrTimer_' + IntToStr(i));  // указатель на очередной таймер

      case (TimerGetState(tmr) * 2) + integer(GetBit(iDevVector.AsInt, i)) of
      2: TimerPause(tmr);             // остановить активный таймер
      1, 511: TimerStart(tmr, 0);     // запустить таймер из паузы или начального состояния
      end;                            // игнорировать повторные запуски и остановы
    end;
end.   

189
Ваши вопросы / Лишний символ TextFileReadLn
« : 01 Августа 2018, 08:55:53 »
Функция TextFileReadLn при первом обращении возвращает лишний первый символ.

Пример во вложении.

190
vyacheslav!

При открытии проекта виртуальные переменные иницализируются.
Хранить даты поверки можно в самой программе, файле или БД.
Каждый из вариантов имеет свои преимущества и недостатки.

В примере из вложения даты поверки хранятся в программе.

191
Серега,
символ <TAB>, используемый в Вашем файле как разделитель полей, является недопустимым для  функции StrToFloat.
Примеры некорректных последовательнстей из ровно 4-х  символов:
Код
			Temp	Hi	Low	Out	Dew	
Date Time Out Temp Temp Hum Pt.
09.07.18 14:24 23.2 23.2 23.2 [u]54 1[/u]3.3 54<TAB>1 табулятор + цифра из следующего поля
...
09.07.18 14:45 [u]1.9 [/u]22.8 1.9<TAB> табулятор

Скрипт, преобразующий строку до первого разделителя <TAB> в вещественное число:
Код: (delphi)
var
  S: UTF8string;
  i: integer;
begin
  S := aStr.AsUTF8String;

  for i := 1 to UTF8Length(S) do
    if S[i] = #9 then                          // поиск разделителя ( =табулятор)
      begin UTF8Delete(S, i, 10); break; end;  // удаление лишнего и выход из цикла

  try
    aVal.Value := StrToFloat(UTF8ToString(S)); // преобразование в вещественное
    Text1.Text := FloatToStr(aVal.Value, 2);
  except                                       // исключение: ошибка прееобразования
    Text1.Text := 'Это не число';
  end;
end.

Замечание. При вводе с клавиатуры символ <TAB> заменяется на ...
Ввод осуществляется копированием-вставкой из исходного файла, открытого в Блокноте. В поле ввода он не отображается.

Пример во вложении.

192
Счетчик вызовов показывает число прохождений этого участка программы с момента запуска проекта.
В данном примере - иллюстрация парных вызовов при изменении одной переменной, включая два вызова при инициализации переменных.

По поводу локальных переменных - нельзя, но если очень хочется (не в рабочем проекте)...
Цитата: « Сообщение от Simple-Scada  21 Июль 2017, 15:02:58 »
Локальные переменные в Pascal, Delphi, C, C++, C# и т.п. языках не инициализируются компилятором и это забота программиста. При каждом очередном вызове скрипта переменной выделяется область памяти и её структура может быть любой (зависит от того, что в ней хранилось ранее), соответственно и значение переменных после выделения памяти может быть каким угодно. Компилятор в Simple-Scada работает аналогично, но при первой инициализации все-таки обнуляет переменную, а при последующих выделяет ту же самую область памяти, что и в первый раз. Поэтому в переменной значение сохраняется (не касается динамических типов данных, например строк). При этом мы рекомендовали бы работать с локальными переменными как и в других языках, т.е. сначала инициализировать, а затем использовать, чтобы значение переменной всегда было очевидным.

193
Sergey_Em,
Цитировать
1 вариант я сам уже пробовал, но меняются значения только в одну сторону.

Вариант 1 аналогичен задаче обмена значениями двух переменных, т.е. необходима промежуточная переменная.

Скрипт по событию "Изменилось значение переменной связанной ..." для переменных PLCtemp и HMItemp:
Код
var i, j: integer;
begin
  with Sender as TM_Field do j := Value;  // запомнить изменившуюся переменную
  PLCtemp.Value := j;                             // изменить переменные
  HMItemp.Value := j;

  i := i + 1;          // счетчик вызовов этого скрипта
  Text1.Text := 'Событий = ' + IntToStr(i);
end.

Пример во вложении.

194
Событие "Выполнен SQL запрос" это действительно признак завершения выполнения запроса и для его обработки требуется скрипт соответствующего типа.

В Вашем примере создается очередь из 10000 запросов без ожидания завершения выполнения предыдущего запроса и ошибки, предположительно, возникают из-за ограничений системы (максимальное допустимое время выполнения скрипта, превышение допустимой длины очереди запросов и т.д.).

Для выполнения запросов "поодиночке" Ваш пример можно изменить так:

1. Начало процесса:
Код: (delphi)
var
  aQuery: string;
begin
  aQuery := 'CREATE TABLE IF NOT EXISTS '+ 'Test_Data' +' (' +
            '`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT,' +
            '`Test_string` CHAR(32),'+
            'PRIMARY KEY (`ID`)' +
            ') ENGINE = InnoDB DEFAULT CHARACTER SET = cp1251;';
  RunSQL(aQuery, nil, 1);
end.

2. Выполняемый в цикле скрипт типа "Выполнен SQL запрос":
Код: (delphi)
var
  aQuery, text: string;
  i: integer;
begin
  i := DataSet.Tag;
  if i >= 10000 then exit;       // выход из цикла
  text := QuotedStr('Цикл => '+inttostr(i));
  aQuery := 'INSERT INTO `Test_Data` ' +
            '(`Test_string`) VALUES ' +
            '('+ text +');';
  RunSQL(aQuery, nil, i + 1);
  Text1.Text := text; // индикация хода процесса
end.
Пример во вложении.

P.S. В Вашей задаче разумно использовать на одну операцию один SQL запрос и записывать по 22 параметра.


195
Цитировать
Подскажите плз, можно ли обратиться с SQL-запросом к чужой (не своей) базе данных?
Для БД MySQL (при наличии прав доступа) удаётся обратиться с запросом к системной (чужой?) БД при условии,
что имя таблицы полное и не заключено в кавычки ``.

Кавычки ``, судя по сообщению об ошибке запроса, добавляют имя выбранной БД к имени таблицы.
Как и для всякой недокументированной возможности, применение остается на свой страх и риск.

Скрипт типа "Полностью запущен" заполняет таблицу информацией о всех таблицах БД, выбранной в проекте.
Код: (delphi)
begin
  Table1.Title := 'Таблицы БД    ' + GetDatabaseName;
  Table1.RunSQL('SELECT `TABLE_NAME`, `TABLE_ROWS`, `TABLE_COMMENT` FROM '
    + 'INFORMATION_SCHEMA.TABLES'              // полное имя таблицы не заключено в кавычки  ` `
    + ' WHERE `TABLE_SCHEMA` = ''' + GetDatabaseName + ''';', tsAll);
end.

Полностью пример (с отключенной БД) в приложении.

Страницы: 1 ... 11 12 [13] 14