Пожалуйста, включите JavaScript для просмотра этого сайта.

Скрипты Simple-Scada

Важно! Пример проекта доступен для скачивания по ссылке.

Рассмотрим получение данных c сервиса zont-online.ru на примере демонстрационного профиля ZONT доступного по ссылке. Допустим, требуется периодически получать данные с сервиса ZONT и выводить их на мнемосхемы или записывать во внутренние переменные для последующей работы с ними. В качестве примера рассмотрим получение данных с устройства ZONT H2000+. Для других устройств ZONT принцип будет аналогичен.

В соответствии с рекомендациями ZONT API, предпочтительной является авторизация с помощью токена. Т.е., сначала нужно выполнить запрос и получить от сервера токен авторизации, а затем использовать этот токен в последующих запросах. Для решения задачи удобнее всего создать в скриптах глобальный модуль и описать в нем нужные процедуры, а затем вызывать их в других скриптах.

Создадим новый скрипт с типом события "Глобальный модуль" и таким кодом (см. комментарии чтобы понять принцип работы):

interface
 
var
  AuthToken: string = '';  // в эту глобальную переменную будет получен токен
 
procedure DoAuthOpen;
procedure DoZontDevices;
 
implementation
 
// Процедура аутентификации. После её выполнения сервер вернёт
// токен. Значение токена будет записано в переменную AuthToken
procedure DoAuthOpen;
var
  aHTTP: TM_HTTP;
  aPOST: TM_HTTPPost;
begin
  AuthToken := '';
  aPost := TM_HTTPPost.Create(hptJSON);
  aPost.Add('{"client_name": "Simple-Scada"}');                           // произвольное имя
 
  aHTTP := RequestHTTP;
  aHTTP.SetSSL(stSSLv23);
  aHTTP.SetHeader('ContentType''application/json');
  aHTTP.SetHeader('Authorization''Basic ' + Base64Encode('demo:demo')); // логин/пароль профиля ZONT, закодированные в Base64
  aHTTP.SetHeader('X-ZONT-Client''ilya@microline.ru');                  // e-mail профиля ZONT
  aHTTP.Post('https://zont-online.ru/api/get_authtoken', aPost, 1);       // отправляем запрос и отмечаем его тегом = 1
end;
 
// эта процедура отправляет запрос используя полученный ранее токен авторизации
procedure DoZontDevices;
var
  aHTTP: TM_HTTP;
  aPOST: TM_HTTPPost;
begin
  // прерываем выполнение, если токен ещё не был получен
  if AuthToken = '' then 
    Exit;
 
  // создаём данные для отправки серверу
  aPost := TM_HTTPPost.Create(hptJSON);
  aPost.Add('{"load_io": true}');                                         // получить данные по датчикам
 
  aHTTP := RequestHTTP;
  aHTTP.SetSSL(stSSLv23);
  aHTTP.SetHeader('ContentType''application/json');
  aHTTP.SetHeader('X-ZONT-Client''ilya@microline.ru');                  // e-mail профиля ZONT
  aHTTP.SetHeader('X-ZONT-Token', AuthToken);                             // авторизуемся с помощью токена
  aHTTP.Post('https://zont-online.ru/api/devices', aPost, 2);             // отправляем запрос и отмечаем его тегом = 2
end;
end.

 

Теперь можно вызвать процедуру аутентификации DoAuthOpen. Проще всего для этого использовать скрипт с типом события "Полностью запущен". Данный скрипт позволит получить токен сразу после запуска проекта.

begin
  DoAuthOpen;
end.

 

Далее необходимо создать новый скрипт с типом события "Выполнен POST/GET запрос", обработать ответ от сервера ZONT и получить токен аутентификации:

var
  aNode: TM_JSONNode;
begin
  if Response.Tag = 1 then                  // тег = 1 (выполнена процедура аутентификации)
    if Response.Code = 200 then             // код ответа сервера равен 200 (ОК)
    begin
      aNode := Response.NodesStr['token'];  // извлекаем поле "token"
      if Assigned(aNode) then               // если такое поле существует
      begin
        AuthToken := aNode.AsStr;           // то сохраняем значение токена в глоб. переменную AuthToken
        DoZontDevices;                      // запрашиваем данные ZONT сразу после получения токена
      end;
    end else
      AddMessage(Now, mkAlarm, 'Запрос на аутентификацию вернул ошибку!' + ' Код = ' + IntToStr(Response.Code), True, False);
end.

 

Так как нам требуется получать данные периодически, создадим скрипт с типом события "Таймер" - в параметре скрипта "Интервал" укажем, с какой частотой должен выполняться скрипт, например 60 секунд. Напишем код скрипта:

begin
  DoZontDevices;  // запрашиваем данные ZONT
end.

 

Далее необходимо создать новый скрипт с типом события "Выполнен POST/GET запрос" и обработать ответ от сервера ZONT, содержащий данные по устройствам. В скрипте ниже рассмотрен пример записи полученных данных в ячейки таблицы, пример получения данных из вложенного массива, а также пример записи текущих значений во внутренние переменные.

var
  I, J: Integer;
  aDeviceArray, aThermArray, aTherm, aThermCurr, aDevice: TM_JSONNode;
  aVar: TM_Variable;
begin
  // прерываем выполнение, если тег не равен 2
  if Response.Tag <> 2 then
    Exit;
 
  // если код ответа сервера не равен 200 (ОК), то выдаём ошибку
  if (Response.Code <> 200then
  begin
    AddMessage(Now, mkAlarm, 'Ошибка выполнения HTTP-запроса, Тег = ' + IntToStr(Response.Tag) + '. Код = ' + IntToStr(Response.Code), TRUE, FALSE);
    Exit;  // прерываем выполнение
  end;
 
  // получаем массив устройств
  aDeviceArray := Response['devices'];
  for I := 0 to aDeviceArray.Count - 1 do
  begin
    aDevice := aDeviceArray.Nodes[I];  // извлекаем очередное устройство из массива в aDeviceArray
 
    // ищем устройство ZONT H2000+ (ID 202303)
    // ID устройства можно посмотреть в личном кабинете ZONT
    if aDevice['id'].AsInt = 202303 then
    begin
      // пример записи свойств в ячейки таблицы
      tblDevice.GetCell(10).Text := aDevice['name'].AsStr;             // имя устройства
      tblDevice.GetCell(11).Text := aDevice['id'].AsStr;               // ID устройства
      tblDevice.GetCell(12).Text := aDevice['online'].AsStr;           // статус устройства
      tblDevice.GetCell(13).Text := aDevice['serial'].AsStr;           // серийный номер
 
      // некоторые данные могут находиться во вложенных массивах
      // для примера рассмотрим получение данных из вложенного массива термометров (wired_temperature_sensors)
      aThermArray := aDevice['z3k_config']['wired_temperature_sensors']; // получаем массив термометров
      for J := 0 to aThermArray.Count - 1 do
      begin
        // поочередно извлекаем термометры из массива aThermArray
        // и записываем нужные данные в строки таблицы tblSensors
        aTherm := aThermArray.Nodes[J];
        tblSensors.GetCell(0, J + 1).Text := aTherm['name'].AsStr;
        tblSensors.GetCell(1, J + 1).Text := aTherm['id'].AsStr;
        tblSensors.GetCell(2, J + 1).Text := aTherm['serial'].AsStr;
 
        // ниже рассмотрен пример получения данных из списка текущих значений (z3k-state)
        // и запись полученных значений во внутренние переменные Simple-Scada
        aThermCurr := aDevice['io']['z3k-state'];                        // получаем список текущих значений
        aVar := GetVariableByName('vrTemp' + IntToStr(J + 1));           // поиск внутренней переменной для записи значения
        if aVar <> nil then                                              // проверка существования переменной
          // значения температур в списке z3k-state хранятся в соответствии с ID термометра из массива wired_temperature_sensors
          // поэтому, для получения значения используем ID термометра из массива wired_temperature_sensors
          aVar.Value := aThermCurr[aTherm['id'].AsStr]['curr_temp'].AsFloat;
      end;
    end;
  end;
end.

 

Если требуется получать только текущие значения по ID датчиков, то можно использовать следующий скрипт по событию "Выполнен POST/GET запрос":

// текущие значения датчиков ZONT H2000+ хранятся в списке z3k-state в соответствии с ID датчика
// при необходимости, можно брать значения напрямую из списка z3k-state по ID датчика как это описано ниже
var
  I: Integer;
  aDeviceArray, aTherm, aDevice: TM_JSONNode;
begin
  // прерываем выполнение, если тег не равен 2
  if Response.Tag <> 2 then
    Exit;
 
  // если код ответа сервера не равен 200 (ОК), то выдаём ошибку
  if (Response.Code <> 200then
  begin
    AddMessage(Now, mkAlarm, 'Ошибка выполнения HTTP-запроса, Тег = ' + IntToStr(Response.Tag) + '. Код = ' + IntToStr(Response.Code), TRUE, FALSE);
    Exit;  // прерываем выполнение
  end;
 
  // получаем массив устройств
  aDeviceArray := Response['devices'];
  for I := 0 to aDeviceArray.Count - 1 do
  begin
    aDevice := aDeviceArray.Nodes[I];  // извлекаем очередное устройство из массива в aDeviceArray
 
    // ищем устройство ZONT H2000+ (ID 202303)
    // ID устройства можно посмотреть в личном кабинете ZONT
    if aDevice['id'].AsInt = 202303 then
    begin
       aTherm := aDevice['io']['z3k-state'];                   // получаем список текущих значений
       // получаем значение по ID датчика и записываем его во внутреннюю переменную
       vrTemp25.Value := aTherm['4276']['curr_temp'].AsFloat;  // улица
       vrTemp26.Value := aTherm['4264']['curr_temp'].AsFloat;  // стрелка
       vrTemp27.Value := aTherm['4263']['curr_temp'].AsFloat;  // 1контур(1эт.бат.)
       vrTemp28.Value := aTherm['4265']['curr_temp'].AsFloat;  // 2контур(пол)
       vrTemp29.Value := aTherm['4266']['curr_temp'].AsFloat;  // 3контур(2эт.бат.)
       vrTemp30.Value := aTherm['4281']['curr_temp'].AsFloat;  // 4 контур
       vrTemp31.Value := aTherm['4288']['curr_temp'].AsFloat;  // 1эт.кухня
       vrTemp32.Value := aTherm['4290']['curr_temp'].AsFloat;  // 1эт.зал
       vrTemp33.Value := aTherm['4278']['curr_temp'].AsFloat;  // 1эт.гостевая
    end;
  end;
end.