Документация Engee

Пользовательские пакеты поддержки Engee.Интеграции

Подсистема Engee.Интеграции обеспечивает взаимодействие между Engee и внешним оборудованием через клиентскую программу и пакеты поддержки.

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

Чтобы подсистема Engee.Интеграции принимала пользовательские пакеты, Engee автоматически генерирует для них код на языке Julia. Это позволяет вызывать ваши функции прямо из командной строки Engee img 41 1 2 или из блоков.

В основе этого механизма лежит технология RPC (Remote Procedure Call — удаленный вызов процедур). Вы вызываете функцию в Julia, которая передает аргументы по сети на клиентский компьютер. Там ваш пакет поддержки выполняет соответствующую Python-функцию с этими параметрами и возвращает результат обратно в Engee.

Архитектура выполнения

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

  • Код на Python выполняется непосредственно на компьютере пользователя в процессе клиентской программы;

  • Код на Julia выполняется в подсистеме Engee и координирует взаимодействие.

Например, при вызове:

using Main.EngeeDeviceManager.Devices.EXTDEVICE
device = EXTDEVICE.Extdevice()
device.function()

Julia-код выполняется в Engee, а Python-функция function() — на клиентском компьютере, и ее результат возвращается в Engee.

Доступные пакеты Python

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

Список доступных пакетов Python
Пакет Описание

aiohttp

Асинхронный HTTP клиент/сервер фреймворк (asyncio)

autoflake

Удаляет неиспользуемые импорты и переменные

bandit

Статический анализатор безопасности Python кода

beartype

Быстрая гибридная проверка типов во время выполнения

black

Бескомпромиссный форматировщик кода

certifi

Пакет для предоставления Mozilla’s CA Bundle

cffi

Интерфейс внешних функций для вызова Си кода из Python

docformatter

Форматирует строки документации в соответствии с PEP 257

flake8

Модульный проверщик исходного кода: pep8 pyflakes и другие

gpib-ctypes

Интерфейс GPIB для Python, реализованный с использованием ctypes

hid

Привязки ctypes для hidapi

httpx

HTTP клиент следующего поколения

intelhex

Библиотека Python для манипуляций с файлами Intel HEX

isort

Утилита/библиотека для сортировки импортов Python

jinja2

Очень быстрый и выразительный шаблонизатор

jupyter-client

Реализация протокола Jupyter и клиентские библиотеки

jupyter-core

Основной пакет Jupyter

jwcrypto

Реализация стандартов JOSE Web

mdurl

Утилиты для URL Markdown

msgpack

Сериализатор MessagePack

multidict

Реализация multidict

numpy

Фундаментальный пакет для вычислений с массивами в Python

ordered-set

OrderedSet, который запоминает свой порядок

patchelf

Утилита для изменения динамического linker и RPATH ELF исполняемых файлов

pathspec

Утилита для сопоставления путей файлов в стиле gitignore

platformdirs

Определение подходящих платформо-специфичных директорий

pydantic

Валидация данных с использованием подсказок типов Python

pydantic-core

Основная функциональность для валидации и сериализации Pydantic

pydantic-settings

Управление настройками с использованием Pydantic

pyduinocli

Обертка вокруг arduino-cli

pyflakes

Пассивный проверщик Python программ

pymodbus

Полнофункциональный стек протокола Modbus на python

pyserial

Расширение для последовательного порта Python

pyusb

Модуль доступа к USB из Python

pyvisa

Привязки Python VISA для инструментов GPIB, RS232, TCPIP и USB

pyvisa-py

Чистая Python реализация библиотеки VISA

pyyaml

Парсер и эмиттер YAML для Python

pyzmq

Привязки Python для 0MQ

redis

Python клиент для базы данных Redis и key-value хранилища

requests

HTTP для людей на Python

setuptools

Легко загружайте, собирайте, устанавливайте, обновляйте и удаляйте пакеты Python

toml

Библиотека Python для Tom’s Obvious, Minimal Language

untokenize

Преобразует токены в исходный код (с сохранением пробелов)

urllib3

HTTP библиотека с потокобезопасным пулом соединений, отправкой файлов и прочее

Пример создания мультифайлового пакета поддержки

Для вашего удобства мы подготовили архив с готовой структурой проекта и примерами кода. В архиве вы найдете полную структуру папок devices и targets с рабочими примерами.

Давайте создадим пакет поддержки с собственной иерархией файлов. Для этого используем шаблон — папку extension, внутри которой есть директории devices и targets.

  • Устройство (Device) — это произвольный пользовательский класс, который не взаимодействует с моделями Engee и не использует их данные.

  • Таргет (Target) — это пользовательский класс, который взаимодействует с моделью Engee, получает из нее данные для обработки и исполняется на другой платформе (микроконтроллере, отдельном компьютере и т.д.).

В нашем примере мы создадим устройство с многофайловой структурой.

  1. Создадим в папке devices новую папку extdevice.

  2. Внутри extdevice создадим файл extdevice.py со следующим кодом:

    import time
    from devices.base_device import BaseDevice
    from .models import DeviceConfig, CalculationResult
    
    class Extdevice(BaseDevice):
        def __init__(self, device_id: int, calibration_factor: float) -> None:
            self.device_id = device_id
            self.calibration_factor = calibration_factor
    
        def __del__(self) -> None:
            pass
    
        def complex_calculation(self, config: DeviceConfig) -> CalculationResult:
            # Сложные вычисления с использованием конфигурации
            result_value = (config.parameter_a * config.parameter_b +
                           config.parameter_c) * self.calibration_factor
    
            return CalculationResult(
                success=True,
                value=result_value,
                timestamp=time.time()
            )
    
        def get_status(self) -> str:
            return f"Device {self.device_id} operational with factor {self.calibration_factor}"
  3. Создадим файл models.py в той же папке extdevice:

    from devices.base_models import BaseModel
    
    class DeviceConfig(BaseModel):
        parameter_a: float
        parameter_b: int
        parameter_c: float
    
    class CalculationResult(BaseModel):
        success: bool
        value: float
        timestamp: float

Для пользовательских RPC-классов обязательно наследование от BaseDevice (если это устройство) или от BaseTarget (если это таргет)

Для структур данных обязательно наследование от BaseModel!

Все методы должны содержать полные аннотации типов для параметров и возвращаемого значения. Например:

# НЕПРАВИЛЬНО - без аннотаций
def __init__(self, param1, param2):
    pass

# ПРАВИЛЬНО - с полными аннотациями
def __init__(self, param1: int, param2: float) -> None:
    pass

def calculate(self, x: float, y: int) -> str:
    return "result"

Без аннотаций система не сможет корректно сгенерировать Julia-код и преобразовать типы данных между Python и Julia.

Методы, предназначенные для вызова из блока, не должны начинаться с _ и __ — такие методы не будут доступны из скриптов и блоков.

Наглядно увидеть, как описанный выше механизм создания собственного пакета поддержки применяется на практике для работы с реальным оборудованием, можно в примере Сообщества: Разработка пакета поддержки оборудования для Engee.Интеграции.

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

Загрузка пользовательского пакета в Engee.Интеграции

В клиентской программе Engee.Интеграции выполните следующие шаги:

  1. Откройте окно статусов оборудования.

  2. Выберите вкладку «Расширения».

    engee integrations custom packages 1 ru

  3. Нажмите «Добавить расширение».

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

    engee integrations custom packages 2 ru

В случае успешной загрузки в окне диагностики клиентской программы появится сообщение:

INFO: Расширение с именем extension было успешно загружено!

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

engee-device-manager.exe -d

После успешной загрузки пакета поддержки в окне диагностики отобразится дополнительная информация:

engee integrations custom packages 4 ru

Регистрация и использование пакета поддержки в Engee

Чтобы пользовательский пакет поддержки появился в EngeeDeviceManager.Devices.* или EngeeDeviceManager.Targets.*, выполните в командной строке Engee:

using Main.EngeeDeviceManager
using Main.EngeeDeviceManager.UTILS_API

utils = UTILS_API.Utils()
UTILS_API.syncExtensions()

Если изменили сигнатуры методов или добавили новые методы, вызовите syncExtensions() снова.

После регистрации пакет поддержки становится доступен для использования:

using Main.EngeeDeviceManager.Devices.EXTDEVICE
device = EXTDEVICE.Extdevice(123, 1.5)
Main.EngeeDeviceManager.Devices.EXTDEVICE.Extdevice("Extdevice", Base.UUID("0aac33b9-4ed5-4786-abb7-9855c0b80265"), ["complex_calculation", "get_status"], "Extdevice_0aac33b9-4ed5-4786-abb7-9855c0b80265_reply", Main.EngeeDeviceManager.Devices.EXTDEVICE.var"#complex_calculation#complex_calculation##0"{String, Base.UUID}("Extdevice", Base.UUID("0aac33b9-4ed5-4786-abb7-9855c0b80265")), Main.EngeeDeviceManager.Devices.EXTDEVICE.var"#get_status#get_status##0"{String, Base.UUID}("Extdevice", Base.UUID("0aac33b9-4ed5-4786-abb7-9855c0b80265")))
device.get_status()
"Device 123 operational with factor 1.5"
config = EXTDEVICE.DeviceConfig(2.5, 10, 3.14)
DeviceConfig(2.5, 10, 3.14)
result = device.complex_calculation(config)
CalculationResult(true, 42.21, 1.7851401913931458e9)

Ваш пакет поддержки будет автоматически загружаться при каждом запуске клиентской программы. Если он больше не нужен, то его можно удалить из автозагрузки в клиентской программе:

engee integrations custom packages 3 ru

Отладка пакетов поддержки

Для отладки пакета поддержки используйте встроенную систему логирования. Добавьте в код:

from main_logger import MainLogger

class Extdevice(BaseDevice):
    def __init__(self, device_id: int, calibration_factor: float) -> None:
        self.logger = MainLogger()
        self.logger.info(f"Initializing device {device_id}")
        self.device_id = device_id
        self.calibration_factor = calibration_factor

    def complex_calculation(self, config: DeviceConfig) -> CalculationResult:
        self.logger.debug("Starting complex calculation")
        # ... ваш код ...
        self.logger.info("Calculation completed successfully")
        return result

Доступные уровни логирования:

  • logger.debug("сообщение") — отладочная информация;

  • logger.info("сообщение") — информационные сообщения;

  • logger.warning("сообщение") — предупреждения;

  • logger.error("сообщение") — ошибки.

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

Отображение статуса пакета поддержки в интерфейсе клиентской программы

Клиентская программа отображает статус установленного оборудования: загружен ли драйвер, подключено ли устройство. Для добавления информации о пакете поддержки в окно статусов оборудования реализуйте в классе устройства статический метод __get_opportunity_list.

Как это работает:

  1. При запуске клиентская программа импортирует все модули из пакетов devices и targets.

  2. Для каждого зарегистрированного класса проверяется наличие приватного метода __get_opportunity_list.

  3. Если метод найден, он вызывается и возвращает список OpportunityStatus.

  4. Клиентская программа опрашивает этот список каждые 3 секунды и отображает информацию в окне статусов оборудования.

Поля OpportunityStatus:

  • key — уникальный идентификатор строки. Пример: "my_driver"

  • title_key — заголовок в интерфейсе. Пример: "MyDevice driver:"

  • value_key — текст статуса. Пример: "Loaded" / "Not loaded"

  • value_args — аргументы для форматирования значения. Пример: ()

  • color — цвет индикатора: "green", "orange", "red". Пример: "green"

  • category — вкладка в окне статусов оборудования:

    • "hardware" — «Оборудование»

    • "protocols" — «Протоколы»

    • "software" — «Интеграции с ПО» (по умолчанию)

    • "embedded" — «Встраиваемые системы»

Если поле не указано, категория определяется автоматически по имени пакета устройства.

Пример для пользовательского пакета поддержки:

from devices.base_device import BaseDevice

class MyDevice(BaseDevice):

    @staticmethod
    def __get_opportunity_list() -> list[BaseDevice.OpportunityStatus]:
        status = BaseDevice.opportunity_status

        driver_loaded = False
        try:
            import some_library  # замените на вашу зависимость
            driver_loaded = True
        except ImportError:
            pass

        results = []

        if driver_loaded:
            results.append(status(
                key="my_driver",
                title_key="MyDevice driver:",
                value_key="Loaded",
                color="green",
                category="hardware",
            ))
        else:
            results.append(status(
                key="my_driver",
                title_key="MyDevice driver:",
                value_key="Not loaded",
                color="orange",
                category="hardware",
            ))

        results.append(status(
            key="my_device",
            title_key="MyDevice status:",
            value_key="Available",
            color="green",
            category="hardware",
        ))

        return results

После добавления этого метода пакет поддержки появится на вкладке «Оборудование» в клиентской программе Engee.Интеграции.