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

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

Вячеслав

Здравствуйте!
Существует ли полное описание команд, операторов и синтаксис для скриптов?

Simple_Scada

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

В скриптах Simple-Scada используется Object Pascal компилятор. Обо всех командах и операторах присущих языкам Pascal/Delphi можно прочесть в интернете на сайтах связанных с языками Pascal/Delphi. Например, описание типов данных и ключевые слова. Описание доступных свойств и методов скады можно найти в руководстве по скриптам. Примеры часто используемых скриптов можно найти в этом разделе.

Вячеслав

К сожалению в руководстве информация раскрыта не полностью. Например не понятно как выполняется скрипт если нет вызывающего скрипт события. Могу ли я просто написать скрипт как программу которая будет что то рассчитывать и присваивать результат внешней переменной?

Victor_P.

Цитата: Вячеслав от 20 апреля 2020, 22:44:06....как выполняется скрипт если нет вызывающего скрипт события...
Рискну предположить, что никак не выполняется.
Цитата: Вячеслав от 20 апреля 2020, 22:44:06...Могу ли я просто написать скрипт как программу которая будет что то рассчитывать и присваивать результат внешней переменной?...
А что мешает?

Simple_Scada

Цитироватьне понятно как выполняется скрипт если нет вызывающего скрипт события
Скрипты выполняются при возникновении события, к которому они привязаны, это могут быть события объектов или события, доступные при создании нового скрипта. Если скрипт не связан ни с каким событием, то он не будет выполняться.

Цитироватьнаписать скрипт как программу которая будет что то рассчитывать и присваивать результат внешней переменной
Если требуется производить расчеты на основе каких-либо переменных, то можно использовать скрипт по событию "Изменились переменные", добавив в него необходимые переменные - такой скрипт будет выполняться при изменении любой переменной из списка. Если требуется выполнять скрипт периодически через какой-то интервал времени, то можно использовать скрипт с типом события "Прошла секунда", добавив в него условие интервала, как в примере по ссылке. Для максимального быстродействия проекта следует правильно подбирать событие, по которому должен выполняться скрипт, например если требуется производить сложение нескольких переменных, то лучше использовать скрипт по событию "Изменились переменные"(а не "Прошла секунда"), тогда скрипт будет выполняться только при изменении переменных, а не каждую секунду. 

gaargot1

Цитата: Олег Печёнов от 16 августа 2018, 11:59:22Добрый день,

Как при наступлении определенных условий проиграть несколько звуковых файлов подряд?
Код: pascal
if temp100.value = 10 then
  begin
    PlayUserSound("brew",'1.ogg',false);
    PlayUserSound("brew",'2.ogg',false);
    PlayUserSound("brew",'3.ogg',false);
  end; 
 
при таком написании воспроизводится только файл 3.ogg
Тоже ломал голову, как не используя таймеры озвучивать динамические сообщения.
Решил не проигрывать аудиофайлики средствами скады, а генерировать строку в зависимости от событий и проигрывать этот текст через внешнее консольное приложение

teplocom

#1041
Добрый! У меня не работает POST-запрос из примера:
Код: pascal
var
  aHTTP: TM_HTTP;
  aPOST: TM_HTTPPost;
begin
  aPost := TM_HTTPPost.Create;        // создаем данные для отправки
  aPost.Add('username=admin');        // !!!компилятор не ругается, а в логе сервера ОШИБКА Access violation at address!!!
  aPost.Add('password=my_password');  // добавляем второй параметр
 
  aHTTP := RequestHTTP;               // создаем экземпляр запроса
  aHTTP.Post('http://mysite.com/index.html', aPost); // вызываем POST
end.

Пишет: Ошибка в скрипте "POST_API" в строке 6. Access violation at address 00C6DDDA in module 'Server.exe'. Read of address 00000000

Также не понятна нужная структура запроса серверу. "Обвязку" запроса нужно самому писать или aHTTP.Post делает это сам?
Вот такие подобные конструкции нужны?:
Код: pascal
PostData := 'log=123&pass=456';
S := 'POST /a.php HTTP/1.0'#13#10+ // тип запроса (POST) и страница, к которой обращаемся
       'Host: 127.0.0.1'#13#10+ // имя сервера
       'Connection: Close'#13#10+ // закрывать подключение после того, как сервер вернёт данные
       'Content-Type: application/x-www-form-urlencoded'#13#10+ // в каком формате передаются данные
       'Content-Length: '+IntToStr(Length(PostData))+#13#10+ // размер данных
       #13#10+PostData; // сами данные
   




Simple-Scada

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

Подтверждаем ошибку. В текущей сборке неправильно зарегистрирован конструктор класса TM_HTTPPost. В ближайшем обновлении исправим. Многие серверы поддерживают GET вместо POST, например можно попробовать так:
Код: pascal
var
  aHTTP: TM_HTTP;
  aQuery: string;
begin
  // формируем текст HTTP запроса
  aQuery := 'http://127.0.0.1/a.php?log=123&pass=456';
 
  aHTTP := RequestHTTP;   // создаём экземпляр запроса
  aHTTP.Get(aQuery, 0);     // вызываем GET с запросом aQuery
end.
Если Ваш сервер работает только с POST, то нужно дождаться обновления.

ЦитироватьТакже не понятна нужная структура запроса серверу. "Обвязку" запроса нужно самому писать или aHTTP.Post делает это сам?
Вот такие подобные конструкции нужны?
Стандартные заголовки запроса, как Host, Connection, Content-Type, Content-Length формируются автоматически и обычно их не нужно прописывать. Но при желании можно задать свои заголовки, например:
Код: pascal
aHTTP := RequestHTTP;
aHTTP.SetHeader('Host', '127.0.0.1');
aHTTP.SetHeader('Connection', 'Close');
aHTTP.SetHeader('ContentType', 'application/x-www-form-urlencoded');
Если Вы работаете с каким-то общедоступным сервером, то назовите его, мы можем перед обновлением проверить скаду с ним и опубликовать примеры запросов для этого сервера.


UPD: исправление с конструктором класса TM_HTTPPost добавили в обновление 2.3.6.12;

Simple-Scada

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

Не нужно брать значение в виде строки, а затем переводить его в Integer. Берите значение сразу как Integer:
Код: pascal
DataSet.Fields[0].AsInt
Все свойства полей данных описаны в этой статье руководства.

lipvasko

спасибо , да не подумал , об других свойствах этой функции

teplocom

#1045
ЦитироватьUPD: исправление с конструктором класса TM_HTTPPost добавили в обновление 2.3.6.12;

Спасибо, теперь вижу ответы от сервера по запросам POST.
Однако получаются только запросы, где отсутствуют параметры запроса.
По API мне после заголовка нужно отправлять ПАРАМЕТРЫ ЗАПРОСА в таком виде:
{
   "login":"user@cloud.by",
   "password":"123456"
}

Если добавляю любые символы, в aPost.Add('login":user@cloud.by'); -не важно что внутри Add, даже хотя бы один символ , то получаю ответ в Response: HTTP/1.1 400 Bad request
Если делаю зарос без строчки aPost.Add(' '); то получаю ответ в Response: HTTP/1.1 401 Unauthorized

Если делать просто GET запрос типа 'http://127.0.0.1/a.php?log=user@cloud.by&pass=123456';, то ответ от сервера такой:
{"name":"Exception","message":"Неверный email или пароль.","code":0,"status":401,"type":"customException","error_status":1}

Вообще, как-нибудь возможно "подсмотреть" что отправляется в запросе aHTTP.Post и в каком виде?

Simple-Scada

ЦитироватьЕсли добавляю любые символы, в aPost.Add('login":user@cloud.by'); -не важно что внутри Add, даже хотя бы один символ , то получаю ответ в Response: HTTP/1.1 400 Bad request
Конечно, ведь если отправлять какие-то произвольные значения серверу, то сервер их не поймёт и выдаст сообщение о том, что запрос неправильный, что и происходит в Вашем случае (400 Bad request). Запрос нужно посылать строго в том формате, который требует сервер, никаких лишних символов в нём быть не должно.

ЦитироватьЕсли делаю зарос без строчки aPost.Add(' '); то получаю ответ в Response: HTTP/1.1 401 Unauthorized
Тоже верно, ведь теперь Вы не посылали никаких непонятных серверу данных и ошибки "Bad request" не произошло. Но при этом Вы и не авторизовались, о чём и говорит сервер сообщением "401 Unauthorized".

ЦитироватьaPost.Add('login":user@cloud.by');
В этом запросе пропущена двойная кавычка в самом начале, очевидно что он не будет правильно распознан сервером. Возможно правильный формат такой: aPost.Add('"login":user@cloud.by');
, это если сервер требует именно такой формат, сначала имя параметра в кавычках, затем двоеточие, затем значение параметра.

ЦитироватьЕсли делать просто GET запрос типа 'http://127.0.0.1/a.php?log=user@cloud.by&pass=123456';, то ответ от сервера такой:
{"name":"Exception","message":"Неверный email или пароль.","code":0,"status":401,"type":"customException","error_status":1}
Это уже больше похоже на рабочую версию запроса, т.к. сервер дал понятный ответ "Неверный email или пароль". Вы точно уверены в том что указали верный e-mail и пароль? Также обратите внимание, что в этом GET запросе Вы передаёте логин как параметр с именем "log", но в других местах Вы пишете "login", а также "pas" и "password". Ваш сервер допускает оба варианта "log" / "login", "pas" / "password"? Или всё таки какой-то один вариант. Если сервер требует имя параметра "login", то указывайте именно так, т.е.:
http://127.0.0.1/a.php?login=user@cloud.by&password=123456

ЦитироватьВообще, как-нибудь возможно "подсмотреть" что отправляется в запросе aHTTP.Post и в каком виде?
Можно попробовать снимать трафик через Wireshark или подобное ПО, но зачем, если ответы сервера дают нужную информацию, как описано выше.

Цитировать{
   "login":"user@cloud.by",
   "password":"123456"
}
Это JSON-формат запроса, его обычно передают через TStringStream, который мы не выносили в скрипты, но можем добавить в будущем (обычно для JSON также указывают ContentType как json). Сейчас можно попробовать и напрямую:
Код: pascal
var
  aHTTP: TM_HTTP;
  aPOST: TM_HTTPPost;
begin
  aPost := TM_HTTPPost.Create;        // создаем данные для отправки
  aPost.Add('{"login":"user@cloud.by","password":"123456"}'); // добавляем данные

  aHTTP := RequestHTTP;               // создаем экземпляр запроса
  aHTTP.SetHeader('ContentType', 'application/json');   
  aHTTP.Post('http://127.0.0.1/a.php', aPost); // вызываем POST
end.

ЦитироватьПо API мне после заголовка нужно отправлять...
Если у Вас есть описание API, то дайте нам ссылку на него (можно выслать на support@simple-scada.com), тогда было бы понятно какие запросы требует сервер и вышеописанные вопросы решатся сами собой.

torchinsky

#1047
Есть переменная с контроллера типа Word.
Первые 3 бита показывают в каком режиме работает установка.
0 - Режим 1
1 - Режим 2
2 - Режим 3

На экране рисую отображение всего этого дела. Оч удобно и красиво получилось сделать с помощью button с enabled = false. По факту это не кнопка уже, красивая такая метка. НО! Нужно отобразить 4ю кнопку "Неактивное"....
Решил попробовать через второстепенную переменную и событие на ее изменение. Написал скрипт и не нашел способа программно изменить текущий state кнопки.
Я понимаю, что можно создать локальную переменную, ее привязать как основную и в скрипте менять значение...но я не хочу так, ибо их придется делать 36 ибо 36 установок...
Можно не рисовать вообще или по другому выводить сообщение, о том что установка неактивна....
Еще можно оставить у кнопки 1 state и просто менять ей цвет...Но хотелось бы большей однотипности в поведении этих кнопок...

Просто хочется без таких решений сказать кнопке "измени состояние"...Такое как нить возможно?

Пример скрипта

Код: pascal
begin
  if Sender is TM_Button then
      with Sender as TM_Button do
        if GetBit(VariableEx.Value , 0) = false and GetBit(VariableEx.Value , 1) = false and GetBit(VariableEx.Value , 2) = false then
           setState(1);   // это фантазии
        else
           setState(0);   // это фантазии
end.

torchinsky

И еще один вопрос...не совсем по скриптам: никто не пробовал проекты делать и синхронизировать работу через git или другие системы контроля версий? Есть какие либо рекомендации или не вариант совсем?


pan2000

#1049
Цитата: torchinsky от 29 июня 2020, 00:45:16Нужно отобразить 4ю кнопку "Неактивное"....
Здравствуйте!
Это кнопка с восьмью состояниями. Бонусом - индикация запрещенных комбинаций. При отсутствии оных - можно обойтись кнопкой с пятью состояниями. См. пример во вложении.