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

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

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

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


Сообщения - PavelSh

Страницы: [1]
1
Если требуется выполнять скрипт в какое-то заданное время(например в 12-30), то можно использовать скрипт с типом события "Прошла секунда", в котором сравнивать текущее время с заданным:
Я верно понимаю, что он успеет выполниться 60 раз, пока время не будет 12-31?

2
Ваши вопросы / Re: Simple-Scada 2, HTTP GET POS, ZONT API
« : 25 Сентября 2022, 11:00:21 »
Добрый день, техподдержка Simple Scada уже выложили в онлайн-справку пример работы с Zont. Я тоже выложу наш вариант.

1. Логин и пароль к личному кабинету храним в локальных переменных с выводом на "техническую" страницу проекта, к которой есть доступ только у разработчика. Это необходимо для оперативной смены логин пароля без внесения изменений в проект с перезапуском.
2. Работает скрипт, который следит за "корректностью токена". Если несколько раз запрос с Токеном не срабатывает, то автоматически идет запрос нового Токена.
3. Необходимо учесть, что время жизни Токенов сейчас бесконечно. Раздавать всем их не стоит. Отменить можно, если в личном кабинете изменить пароль. В этом случае все ранее выданные Токены аннулируются.

Вот скрипт, который следит запрашивает Токен (событие раз в секунду)

Код: (delphi)
var
  aHTTP: TM_HTTP;
  aPost: TM_HTTPPost;

const
Interval = 60;


begin
  Timer_Zapros_API_Key.Value := Timer_Zapros_API_Key.Value + 1; //накапливаем секунды в таймер

      if Timer_Zapros_API_Key.Value = 1 then  //если таймер досчитал до 1
        begin
        //если (нет токена или ошибка запроса) и менее 5 запросов
        if ((APIkeyZont_Token_eee.Value = '') OR (Err_HTTP.AsBool = true)) AND (Count_ZaprosApi.Value < 5) Then
          //Производим запрос токена
          Begin
          Count_ZaprosApi.Value := Count_ZaprosApi.Value + 1; //Подсчет кол-ва запросов токена

          aPost := TM_HTTPPost.Create(hptJSON);
          aPost.Add('{"client_name": "Любое название вашего приложения"}');
          aHTTP := RequestHTTP;
          aHTTP.SetSSL(stSSLv23);
          aHTTP.SetHeader('Authorization','Basic ' + Base64Encode(combobox1.Text + ':' + Password.AsStr)); // в combobox1 лежит логин
          aHTTP.SetHeader('ContentType', 'application/json');
          aHTTP.SetHeader('X-ZONT-Client', 'ваша почта для связи со стороны разработчика API Zont');
          aHTTP.Post('https://zont-online.ru/api/get_authtoken', aPost, 70); // отмечаем запрос тегом = 70
          end;
        end;

  if Timer_Zapros_API_Key.Value >= Interval Then //если таймер досчитал до интервала
  Timer_Zapros_API_Key.Value := 0; //обнуляем таймер   

  //сброс счетчика неудачных запросов токена
  if (Err_HTTP.AsBool = false) OR (Sbros_Count.AsBool = true) then
    Count_ZaprosApi.Value := 0;

end.

4. Обрабатываем ответ на запрос Токена (тип - выполнен запрос API)

Код: (delphi)
var
ApiKey: string;

begin

if Response.Tag = 70 then
   begin
    ApiKey := (Response['token'].AsStr);
    Text10.Text := ApiKey; // выводим на экран Токен для визуального контроля его получения
    APIkeyZont_Token_eee.Value := ApiKey;
   end;
end.

5. Делаем запрос данных устройств с ранее полученных Токеном. (раз в секунду)

Код: (delphi)
var
  aHTTP: TM_HTTP;
  aPost: TM_HTTPPost;

begin
  Timer_Zapros_Devices.Value := Timer_Zapros_Devices.Value + 1; //Накапливаем секунды в таймер

  if Timer_Zapros_Devices.Value = 7 then  //если таймер досчитал до 7
        begin
          //производим запрос, если есть токен и нет ошибки запроса
          if (APIkeyZont_Token_eee.Value <> '') AND (Err_HTTP.AsBool = false)  then
            begin
            // формируем POST данные
            aPost := TM_HTTPPost.Create(hptJSON);
            //aPost.Add('"load_io": False');

            // отправляем данные с авторизацией токеном
            aHTTP := RequestHTTP;
            aHTTP.SetSSL(stSSLv23);
            aHTTP.SetHeader('ContentType', 'application/json');
            aHTTP.SetHeader('X-ZONT-Client', 'Ваша почта');
            aHTTP.SetHeader('X-ZONT-Token', APIkeyZont_Token_eee.AsStr);
            aHTTP.Post('https://zont-online.ru/api/devices', aPost, 81); // отмечаем запрос тегом = 80
            end;

        end;

  if Timer_Zapros_Devices.Value >= Interval_zaprosa_devices.Value Then //если таймер досчитал до интервала
  Timer_Zapros_Devices.Value := 0; //обнуляем таймер


end.

6. Обрабатываем ответ на полученный запрос (выполнен запрос API). Часть переменных придется создать вручную.

Код: (delphi)
var
  I,J: Integer;
  Disconnect1, Disconnect2, Disconnect3, Disconnect4: boolean;
  aTemp1, aTemp2, aTemp3, aTemp4, aTemp5, aTemp6, aTemp7, aTemp8, aTemp9, aTemp10, aTemp11, aTemp12: double; //температура датчиков
  aStatus1, aStatus2, aStatus3, aStatus4, aStatus5, aStatus6, aStatus7, aStatus8, aStatus9, aStatus10, aStatus11, aStatus12: string;  //состояние датчиков
  aResult, aResultTerm: string;
  aSimInDevice, aForeignMsisdn: TM_JSONNode;
  aDeviceArray, aThermArray, aTherm, aDevice, aNode: TM_JSONNode;
  aVar1: array [0..3] of byte;  //массив пропуска датчика

begin


  // если код ответа сервера не равен 200 (ОК), то выдаём ошибку
  if Response.Code <> 200 then
    begin
    //AddMessage(Now, mkAlarm, 'Ошибка выполнения HTTP-запроса, tag = ' + Response.Text , TRUE, FALSE);
    Err_HTTP.Value := true;
    Exit;  // прерываем выполнение
    end
  else
    Err_HTTP.Value := false;

 
  // прерываем выполнение, если тег не равен 81
  if Response.Tag <> 81 then
     Exit;

  aResult := '';
  aResultTerm := '';
  aDeviceArray := Response['devices'];      // получаем массив devices
  for I := 0 to aDeviceArray.Count - 1 do
  begin
    aDevice := aDeviceArray.Nodes[I];       // извлекаем очередное устройство из массива aDeviceArray


          //Сброс битов массива пропуска и извлечение IP
          case aDevice['id'].AsInt of
          //Объект_1
          12345: // ID вашего объекта (смотреть в ответе, лучше в Postman)
            begin
            aVar1[0]:= 0;
            Объект_1_ipDevice.Value:= aDevice['ip'].AsStr;
            end;
          //Объект_2
          23456: // ID вашего объекта (смотреть в ответе, лучше в Postman)
            begin
            aVar1[1]:= 0;
            Объект_2_ipDevice.Value:= aDevice['ip'].AsStr;
            end;
          //Объект_3
          34567: // ID вашего объекта (смотреть в ответе, лучше в Postman)
            begin
            aVar1[2]:= 0;
            Объект_3_ipDevice.Value:= aDevice['ip'].AsStr;
            end;
          //Объект_4
          56789: // ID вашего объекта (смотреть в ответе, лучше в Postman)
            begin
            aVar1[3]:= 0;
            Объект_4_ipDevice.Value:= aDevice['ip'].AsStr;
            end;
          end;



          {//Сброс битов массива пропуска
          case aDevice['id'].AsInt of
          //Объект_1
          12345:  Объект_1_ipDevice.Value:= aDevice['ip'].AsInt;
          //Объект_2
          23456: Объект_2_ipDevice.Value:= aDevice['ip'].AsInt;
          //Объект_3
          34567: Объект_3_ipDevice.Value:= aDevice['ip'].AsInt;
          //Объект_4
          56789: Объект_4_ipDevice.Value:= aDevice['ip'].AsInt;
          end;}

    aResult := aResult +
      'Device name = ' + aDevice['name'].AsStr + ', ' + aDevice['notes'].AsStr + Chr(10)+
      'id = ' + aDevice['id'].AsStr + ', ' +
      'ip = ' + aDevice['ip'].AsStr + Chr(10);

    //Проверка связи с объектом
    If aDevice['online'].AsStr = 'true' then
        begin
        aResult := aResult +  ' Связь есть';
        Disconnect1:= false;
        Disconnect2:= false;
        Disconnect3:= false;
        Disconnect4:= false;
        end
    else
        begin
          aResult := aResult +  ' Связи нет';

          case aDevice['id'].AsInt of
          //Объект_1
          12345:  Disconnect1:= true;
          //Объект_2
          23456: Disconnect2:= true;
          //Объект_3
          34567: Disconnect3:= true;
          //Объект_4
          56789: Disconnect4:= true;
          end;

        end;




    // читаем свойство sim_in_device
    aSimInDevice := aDevice['sim_in_device'];

    if aSimInDevice <> nil then  // если оно существует
    begin
      // извлекаем из sim_in_device свойство foreign_msisdn
      aForeignMsisdn := aSimInDevice['foreign_msisdn'];
      if aForeignMsisdn <> nil then // если оно существует, то добавляем в результат
        aResult := aResult + ', номер СИМ карты - ' + aForeignMsisdn.AsStr;
    end;

    // разбор вложенного массива thermometers
    aThermArray := aDevice['thermometers']; // получаем массив thermometers
    aResultTerm := '';
    for J := 0 to aThermArray.Count - 1 do
    begin
      aTherm := aThermArray.Nodes[J];       // поочередно извлекаем термометры из массива aThermArray



      //проверка регистрации датчика в термостате
      if aTherm['is_assigned_to_slot'].AsStr = 'true' then
      begin

        //ВЫВОД ПОКАЗАНИЙ ИЗ ДАТЧИКОВ
        case aDevice['id'].AsInt of
        //Объект_1
        12345:
            begin
               if aTherm['name'].AsStr = 'Темп.КК' then
                 begin
                   aTemp1:= aTherm['last_value'].AsFloat;
                   aStatus1 := aTherm['last_state'].AsStr;
                   aVar1[0] := SetBit(aVar1[0],0,true);
                 end
               else
               if aTherm['name'].AsStr = 'Темп. Отопле' then
                 begin
                   aTemp2:= aTherm['last_value'].AsFloat;
                   aStatus2 := aTherm['last_state'].AsStr;
                   aVar1[0] := SetBit(aVar1[0],1,true);
                 end
               else
               if aTherm['name'].AsStr = 'Темп. ГВС' then
                 begin
                   aTemp3:= aTherm['last_value'].AsFloat;
                   aStatus3 := aTherm['last_state'].AsStr;
                   aVar1[0] := SetBit(aVar1[0],2,True);
                 end;
            end;
        //Объект_2
        23456:
            begin
               if aTherm['name'].AsStr = 'Обратная  КК' then
                 begin
                   aTemp4:= aTherm['last_value'].AsFloat;
                   aStatus4 := aTherm['last_state'].AsStr;
                   aVar1[1] := SetBit(aVar1[1],0,True);
                 end
               else
               if aTherm['name'].AsStr = 'Прямая  КК' then
                 begin
                   aTemp5:= aTherm['last_value'].AsFloat;
                   aStatus5 := aTherm['last_state'].AsStr;
                   aVar1[1] := SetBit(aVar1[1],1,True);
                 end;
             end;
        //Объект_3
        34567:
            begin
               if aTherm['name'].AsStr = 'Датчик подачи ТС' then
                 begin
                   aTemp6:= aTherm['last_value'].AsFloat;
                   aStatus6 := aTherm['last_state'].AsStr;
                   aVar1[2] := SetBit(aVar1[2],0,True);
                 end
               else
               if aTherm['name'].AsStr = 'Датчик обратки ТС' then
                 begin
                   aTemp7:= aTherm['last_value'].AsFloat;
                   aStatus7 := aTherm['last_state'].AsStr;
                   aVar1[2] := SetBit(aVar1[2],1,True);
                 end;
             end;
        //Объект_4
        56789:
            begin
               if aTherm['name'].AsStr = 'Подача ТС' then
                 begin
                   aTemp8:= aTherm['last_value'].AsFloat;
                   aStatus8 := aTherm['last_state'].AsStr;
                   aVar1[3] := SetBit(aVar1[3],0,True);
                 end
               else
               if aTherm['name'].AsStr = 'Обратная ТС' then
                 begin
                   aTemp9:= aTherm['last_value'].AsFloat;
                   aStatus9 := aTherm['last_state'].AsStr;
                   aVar1[3] := SetBit(aVar1[3],1,True);
                 end
               else
               if aTherm['name'].AsStr = 'Подача ГВС' then
                 begin
                   aTemp10:= aTherm['last_value'].AsFloat;
                   aStatus10 := aTherm['last_state'].AsStr;
                   aVar1[3] := SetBit(aVar1[3],2,True);
                 end;
             end;
        end;
      end;




      if aTherm['is_assigned_to_slot'].AsStr = 'true' then
        begin
          aResultTerm := aResultTerm +          // в переменную результата добавляем значения нужных свойств термометра
          'name = ' + aTherm['name'].AsStr + ', ' +
          'last_value = ' + aTherm['last_value'].AsStr + Chr(10);
        end;

    end;

    aResult := aResult + Chr(10) + aResultTerm + Chr(10);

  end;
 
  Text20.Text := aResult;
                                           

  //вывод значений Объект_1
  Объект_1_Tkk.Value:= aTemp1;
  Объект_1_Totopl.Value:= aTemp2;
  Объект_1_Tgvs.Value:= aTemp3;
  Объект_1_Disconnection.Value:= Disconnect1;

      //извлекаем биты проверки пропуска
      Объект_1_Tkk_Lost.Value   := NOT GetBit(aVar1[0],0);
      Объект_1_Totopl_Lost.Value:= NOT GetBit(aVar1[0],1);
     Объект_1_Tgvs_Lost.Value  := NOT GetBit(aVar1[0],2);

      //Tkk
      if aStatus1 = 'ok' then
        Объект_1_Tkk_ERR.Value := 0
      else
        Объект_1_Tkk_ERR.Value := 1;

      //Totopl
      if aStatus2 = 'ok' then
        Объект_1_Totopl_ERR.Value := 0
      else
        Объект_1_Totopl_ERR.Value := 1;

      //Tgvs
      if aStatus3 = 'ok' then
        Объект_1_Tgvs_ERR.Value := 0
      else
        Объект_1_Tgvs_ERR.Value := 1;


  //вывод значений по остальным объектам, аналогично
  ...........................

end.

Для понимания, как разбирать ваш массив данных, рекомендую сначала выполнить запрос в программе Postman, где будет видна структура ответа, ID ваших Device, названия датчиков и прочая информация.


3
Ваши вопросы / Re: Simple-Scada 2, HTTP GET POS, ZONT API
« : 22 Сентября 2022, 10:37:57 »
У нас все получилось с Zont. Вытащили показания датчиков температуры,  наличие связи между контроллером и сервером, и исправность датчиков.
Чуть позже отказы вытащим,  но для этого надо сам кортроллер переконфигурировать.
Что у вас конкретно не получается?

Страницы: [1]