Учебник по flexible драйверу (Входящие данные)

В текущей статье мы рассмотрим возможности flexible драйвера и то, как его можно использовать для обработки произвольных входящих данных из TCP соединения.

AggreGate включает в себя драйверы для множества различных устройств, что упрощает их интеграцию в систему. В случаях, когда в AggreGate нет драйвера для определенного устройства (например, для устройства, использующего проприетарный протокол), существует несколько вариантов интеграции устройства. Первый вариант - написать плагин для AggreGate на Java, и хотя это просто, но трудоемко. Другой вариант - настроить один или несколько экземпляров flexible драйвера для обработки входящих данных в виде переменных или событий.

Введение в операцию с драйвером

В данном руководстве приведено множество выражений, использующих команду переменной окружения. В различных выражениях на эту переменную ссылается {env/command}. В AggreGate, использующем flexible драйвер, настроенный на получение входящих данных, эта переменная содержит данные, которые были получены и обрабатываются драйвером.

Настроить flexible плагин

Первым шагом будет настройка плагина драйвера Flexible для корректной маршрутизации входящих данных на определенное устройство Flexible драйвер. В корневом контексте откройте контекст Драйверы/расширения и выберите Редактировать свойства драйвера/расширения flexible драйвера.

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

Имя свойства

Значение

Заметки

Описание

Гибкие конфигурации TCP

Удобное для пользователя имя для конфигурации устройства.

Протокол

TCP

Тип данных, которые будет обрабатывать устройство flexible драйвера.

Порт

5040

Укажите порт, на котором AggreGate должен прослушивать входящие TCP-соединения. 3010 - типичный порт для TCP-соединений, но вы можете выбрать любой доступный порт.

Защищенный

Ложь

Укажите, зашифровано ли соединение с помощью SSL/TLS.

Выражение разделитель входного потока

length({env/command})

Определяет количество байт, которые будут взяты из входного потока данных. Необработанная команда доступна в переменной окружения command, которая здесь упоминается как {env/command}. Должно возвращать количество байт, которые нужно вернуть из сообщения.

Режим разделителя входного потока

"Попытка разделить в конце блока"

Указывает, когда запускать Выражение расширенного поиска разделителя входного потока; в текущем случае оно будет запущено один раз, в конце сообщения.

Если выбрана опция Попытка разделить на каждом байте, Выражение разделителя входного потока сработает один раз для каждого байта в блоке, где {env/command} будет включать первый байт, затем первые два байта, первые три байта и так далее, до конца блока.

Выражение расширенного поиска

{env/command}

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

Выражение раскодирования

{env/command}

Используется при получении пакета данных. Текущее выражение предварительно обрабатывает пакет данных перед дальнейшей обработкой. Текущее выражение может использоваться для простой обрезки терминальных символов из пакета или для полного преобразования данных, например, путем их расшифровки/декомпрессии.

Выражение метода обнаружения ID устройства

1

Выражение, определяющее метод вычисления идентификатора, который возврат:

  • 0 - Результат Выражения чтения идентификатора устройства отправляется устройству для запроса идентификатора устройства. Ответ на эту команду затем отправляется в Выражение расширенного поиска результата чтения ID устройства.

  • 1 - Идентификатор устройства обрабатывается из первого сообщения. Все первое сообщение отправляется в Выражение результата чтения идентификатора устройства, а результатом оценки является идентификатор устройства.

В текущем примере используется значение 1, так как мы будем отправлять произвольные данные.

Выражение чтения ID устройства

Не используется в данном примере.

Если Выражение метода обнаружения ID устройства равно 0, это выражение должно вернуть строку, представляющую команду, которая будет отправлена устройству для запроса ID устройства.

Ответ на команду запроса ID устройства затем отправляется в Выражение результата чтения ID устройства для определения ID устройства.

Выражение результата чтения ID устройства

"1"

Результат выполнения этой команды определяет идентификатор устройства. Мы установили значение "1" для всех входящих сообщений на выбранном порту.

Если бы мы ожидали, что на одном порту будут взаимодействовать разные устройства, мы могли бы установить это значение динамически, основываясь на входящем сообщении или ответе на Выражение чтения ID устройства. Как и в случае с предыдущими {env/command}

Закодированный

US-ASCII

Существует несколько различных кодировок, для данного примера мы используем ASCII.

На следующем скриншоте показана строка глобальных настроек flexible драйвера, настроенная в соответствии с предыдущей таблицей.

Вы настроили глобальные конфигурации flexible драйвера на прием TCP-пакетов на порт 5040, интерпретацию каждой полезной нагрузки как кодированной в ASCII и пересылку полезной нагрузки на устройство flexible драйвера с идентификатором "1". В следующем разделе необходимо настроить устройство с идентификатором "1", которое будет далее обрабатывать входящие полезные нагрузки TCP.

Создание устройства

Чтобы создать flexible устройство, нажмите Добавить устройство из контекста Устройства в корневом контексте. Настройте устройство с помощью следующих параметров:

Имя свойства

Значение

Заметки

Драйвер устройства

Flexible

Текущее руководство предназначено для драйвера Flexible

Имя устройства

flexible_incoming

Это будет частью контекстного пути для ссылки на устройство в AggreGate.

Описание устройства

Входящее гибкое

Удобное для пользователя имя устройства.

Подключение

Входящее

Указывает, что данное устройство будет обрабатывать входящие соединения.

Идентификатор устройства

1

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

На следующем скриншоте показаны приведенные выше конфигурации, введенные в окно "Добавить устройство". Нажмите OK, чтобы сохранить и открыть страницу Свойства аккаунта устройства .

После создания устройства окно Свойства аккаунта устройства должно открыться автоматически. Окно также можно открыть, нажав Редактировать свойства аккаунта устройства из контекстного меню вновь созданного устройства.

Добавление переменной в устройство

Для того чтобы связать поступающие данные с устройством, создайте хотя бы одну переменную. Перейдите на вкладку Статические переменные и добавьте строку со следующими данными:

Поле

Значение

Заметки

Имя

data

Текущий будет частью контекстного пути для ссылки на переменную в языке выражений AggreGate.

Описание

data

Удобное для пользователя имя переменной

Формат

  • Минимальное количество записей - 1

  • Максимальное количество записей - 1

  • Поля

    • Значение - value

    • Тип - String

    • Описание - value

    • Может быть NULL - True

Описание полей таблицы данных переменной. Мы описываем таблицу с одним полем с именем value и типом String. Если установить минимальное и максимальное количество записей в 1, переменная будет отображать единственное значение.

Читаемая

True

Позволяет читать переменную

Writable

True

Позволяет записывать переменную

Настроив строку на вкладке Статические переменные , вы получите следующее:

Теперь у устройства есть переменная данных, в которую могут быть записаны входящие данные.

Конфигурирование события для устройства

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

Поле Имя

Значение

Заметки

Имя

updateData

Текущий будет частью контекстного пути для ссылки на событие в языке выражений AggreGate.

Описание

Обновить данные

Удобное для пользователя имя события.

Формат

  • Минимальное количество записей - 1

  • Максимальное количество записей - 1

  • Поля

    • Значение - value

    • Тип - String

    • Описание - value

    • Может быть NULL - True

Описание полей таблицы данных для события. Мы описываем таблицу с одним полем с именем value и типом String. Если установить минимальное и максимальное количество записей равным 1, таблица данных события будет отображать одно значение.

Уровень

Информация

Установка уровня события в качестве информационного.

Настроив статическое событие с указанными выше значениями, вы получите следующее:

Это позволит устройству инициировать события при получении определенных пакетов данных.

Настроить свойства Операции

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

Операции с данными

Имя свойства

Значение

Заметки

Выражение детектор асинхронных команд

TRUE

Это выражение может обращаться к {env/command} и должно возвращать булево значение, указывающее, должно ли содержимое {env/command} быть обработано как ответ на команду, ранее отправленную драйвером, или как "независимое" сообщение устройства (событие или обновление переменной):

  • TRUE - Обработать содержимое {env/command} как обновление переменной или событие.

  • FALSE - Вычисление содержимого {env/command} как ответа на предыдущую команду драйвера.

Выражение классификатора события/обновления переменной

contains({env/command}, "переменная") ? 1 : (contains({env/command}, "event") ? 0 : 1)

Вычислено только в том случае, если Выражение детектора асинхронных команд выполнено в TRUE. Возврат должен быть либо 1, либо 0, что означает:

  • 1- дальнейшую обработку как обновление переменной

  • 0 - Дальнейшая обработка как событие

В текущем случае, если входящая командная строка содержит подстроку переменной, то команда будет считаться обновлением переменной. Если команда содержит подстроку event, то команда будет обработана как событие.

Выражение ID команды

"1"

Поле Выражение ID команды и поле Выражение ID ответа принимаются в операцию только в том случае, если Выражение детектора асинхронных команд возвращает FALSE. Они определяют номер команды при отправке и номер ответа от устройства для их соответствия. Механизм отправки и приема команд будет рассмотрен позже.

Выражение расширенного поиска ответа ID

"1"

Асинхронная обработка переменных

Имя свойства

Значение

Заметки

Выражение имени переменной

"updateData"

Указывает имя переменной, которая будет обновлена, если Выражение классификатора события/обновления переменной возвращает 1.

Выражение временной метки переменной

now()

Временная метка для применения к обновлению переменной.

Выражение качества переменной

null

Качество данных, применяемое к обновлению переменной

Выражение значения переменной

table("<<value><S><F=N>>",{env/command})

Таблица данных, с помощью которой обновляется переменная. Соответствует формату, определенному для переменной.

Обработка асинхронных событий

Имя свойства

Значение

Заметки

Выражение имени события

"updateData"

Указывает имя события, которое будет создано, если Выражение классификатора события/обновления переменной возвращает 0.

Выражение временной метки события

now()

Дата/время события для применения к обновлению события.

Выражение уровня события

2

Уровень, на котором будет создано событие

Выражение расширенного поиска значения события

table("<<value><S><F=N>>",{env/command})

Таблица данных для события. Соответствует формату, определенному для таблицы данных события.

Остальные разделы можно оставить пустыми. Настроив свойства вкладки Операции, вы должны получить нечто подобное приведенному ниже скриншоту

Сейчас, когда устройство AggreGate настроено на обработку входящих сообщений с помощью flexible драйвера, его можно протестировать, отправив несколько сообщений.

Отправка данных на устройство AggreGate

Существует несколько способов отправки произвольных TCP-данных. Один из них заключается в использовании специализированного инструмента, такого как Пакет Отправитель, другой - в написании простой программы, которая создает TCP-соединение и отправляет нужные данные.

Использование программы Пакет Отправитель для отправки пакетов

  • Загрузите и установите пакетный отправитель в той же операционной системе, в которой запущен сервер AggreGate.

  • Создайте пакет со следующими конфигурациями:

Свойства

Значение

Описание

Имя

Test Packet

Если вы хотите сохранить пакет для повторного использования

ASCII

var: Обновить переменную "data" произвольными данными TCP.

Текст ASCII для отправки.

HEX

76 61 72 3a 20 55 70 64 61 74 65 20 22 64 61 74 61 22 20 76 61 72 69 61 62 6c 65 20 20 77 69 74 68 20 73 6f 6d 65 20 61 72 62 69 74 72 61 72 79 20 54 43 50 20 64 61 74 61 2e

Автоматически закодированное HEX-значение указанного ASCII-текста.

Адрес

localhost

Хост или IP-адрес, на который следует отправить пакет.

Порт

5040

Порт, на который нужно отправить пакет

Задержка повторной отправки

0

Задержка перед повторной отправкой пакета

Тип связи

TCP

Тип соединения с сервером.

Настроенное окно Отправитель пакетов будет выглядеть следующим образом.

Кликните Отправить, чтобы отправить пакет на устройство с flexible драйвером AggreGate.

Использование Python для отправки пакета

  • Установите Python 3 на ту же машину, на которой запущен сервер AggreGate.

  • Сохраните приведенный ниже пример сценария в файле с именем sendpacket.py:

  • import socket

    # Set up the socket connection
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # Hostname or IP address where server is running
    host = 'localhost'
    # Port where Flexible Driver is configured to listen to incoming data
    port = 5040
    # Start connection
    s.connect((host, port))

    # Send data
    data = b'var: Update data with some arbitrary TCP data.'
    s.sendall(data)

    # Close the connection
    s.close()
  • Запустите сценарий из командной строки командой python3 sendpacket.py

Подтвердите, что пакет был принят устройством с flexible драйвером

  • Откройте контекстное меню устройства из корневого контекста и нажмите Управление устройством...

  • Текущий откроет окно со всеми переменными устройства, в данном случае переменной data, с данными, которые мы отправили как пакет var: Обновить переменную "data" произвольными данными TCP.

  • Доступ к переменной можно получить на языке выражений с помощью контекстного пути {users.admin.devices.incoming_flexible:data}.

Триггер события в flexible устройстве

Мы можем вызвать событие updateData, которое мы настроили выше, вместо обновления переменной, просто изменив данные, отправляемые на устройство.

Напомним, что Выражение классификатора события/обновления переменной определяет, будут ли входящие данные обрабатываться как событие или как операция обновления переменной. Мы использовали следующее выражение:

contains({env/command}, "variable") ? 1 : (contains({env/command}, "event") ? 0 : 1)

Текущее выражение сначала проверяет, содержит ли команда строку "переменная". Если да, то оно принимает значение 1, и команда обрабатывается как обновление переменной. Если команда не содержит строку "переменная", выполняется проверка, содержит ли команда строку "событие". Если команда содержит строку "событие", выражение оценивается в 0, и команда обрабатывается как событие. Если ни "переменная", ни "событие" не присутствуют, по умолчанию устанавливается значение 1 и обновляется переменная.

Чтобы вызвать событие, просто измените содержимое тестового пакета так, чтобы оно содержало строку "event" и удалите строку "variable". Например: event: Текущее событие!

Используяотправитель пакетов , обновите данные в формате ASCII и HEX, как указано ниже:

Свойство

Значение

Описание

Имя

Test Packet

Если вы хотите сохранить пакет для повторного использования

ASCII

событие: Текущее событие!

Текст ASCII для отправки.

HEX

65 76 65 6e 74 3a 20 54 68 69 73 20 69 73 20 61 6e 20 65 76 65 6e 74 21

Автоматически закодированное HEX-значение указанного ASCII-текста.

Адрес

localhost

Хост или IP-адрес, на который следует отправить пакет.

Порт

5040

Порт, на который нужно отправить пакет

Задержка повторной отправки

0

Задержка перед повторной отправкой пакета

Тип связи

TCP

Тип соединения с сервером.

При использовании сценария Python обновите переменную данных, как указано ниже:

...
# Send data
data = b'event: Текущее событие!'
...

В Контекстном дереве AggreGate откройте контекстное меню Входящего flexible устройства и выберите Просмотр событий.

Появится окно, в котором отображаются все текущие события Входящего flexible устройства. В нашем случае активных событий нет, поэтому таблица данных пуста.

Отправьте пакет из программы Пакет Отправитель или запустите сценарий Python и убедитесь, что событие сработало:

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