自定义引擎支持包.综合服务
子系统 恩吉。综合服务 之间提供交互 AnyMath 和外部硬件通过客户端程序和支持包。
您可以通过扩展*Engee子系统的功能来开发自己的自定义支持包。整合*。 支持包是一个Python模块,它在客户端程序中运行,并将结果返回到 AnyMath .
使*Engee子系统。集成*接受的自定义包, AnyMath 用Julia语言自动为它们生成代码。 这允许您直接从 命令行 AnyMath
或者从街区。
技术是这一机制的核心。 RPC(远程过程调用)。 您正在调用Julia中的一个函数,该函数通过网络将参数传递给客户端计算机。 在那里,您的支持包使用这些参数执行相应的Python函数,并将结果返回到 AnyMath .
执行架构
了解代码执行的分布很重要:
Python代码*在客户端程序过程中直接在用户计算机上执行; Julia*代码在子系统中执行 AnyMath 并协调互动。
例如,当调用:
using Main.EngeeDeviceManager.Devices.EXTDEVICE
device = EXTDEVICE.Extdevice()
device.function()
Julia-代码在 AnyMath ,而Python是一个函数 功能() --在客户端计算机上,其结果返回到 AnyMath .
可用的Python包
在开发自定义支持包时,您可以使用所有标准Python包以及以下第三方包:
可用Python包列表
| 包裹 | 资料描述 |
|---|---|
aiohttp |
异步HTTP客户端/服务器框架(asyncio) |
自动闪光 |
删除未使用的导入和变量 |
强盗 |
静态Python代码安全分析器 |
[医]贝特型 |
运行时快速混合类型检查 |
黑色 |
一个不妥协的代码格式化程序 |
证明;证明 |
Mozilla的CA捆绑包 |
cffi |
从Python调用C代码的外部函数接口 |
doc格式,doc格式 |
根据PEP257格式化文档字符串 |
高射炮8 |
模块化源代码检查器:pep8pyflakes和其他 |
gpib-ctypes |
PYTHON的GPIB接口,使用ctypes实现 |
隐藏 |
Hidapi的Ctypes绑定 |
httpx |
下一代HTTP客户端 |
intelhex |
用于操作英特尔十六进制文件的Python库 |
伊斯特 |
用于排序Python导入的实用程序/库 |
jinja2 |
一个非常快速和富有表现力的模板引擎 |
jupyter-客户端 |
Jupyter协议实现和客户端库 |
jupyter-核心 |
Jupyter基本包 |
jwcrypto的 |
JOSE Web标准的实施 |
mdurl |
标记URL实用程序 |
味精背包 |
MessagePack序列化器 |
多区 |
多领域的实施 |
n.麻木,麻木 |
Python中计算数组的基本包 |
订购-套装 |
记住其顺序的OrderedSet |
n.贴片,贴片 |
用于更改动态链接器和RPATH ELF可执行文件的实用程序 |
路径规格 |
用于匹配gitignore样式中的文件路径的实用程序 |
平台,平台 |
确定合适的平台特定目录 |
[医]疯狂 |
使用Python类型提示进行数据验证 |
大西洋-核心 |
Pydantic验证和序列化的主要功能 |
pydantic-设置 |
使用Pydantic管理设置 |
[医]皮杜诺克利 |
Arduino-cli周围的包装器 |
[医]火烧 |
被动Python程序检查器 |
[医]皮莫德总线 |
Python中的全功能Modbus协议栈 |
[医]皮塞里亚 |
Python串口扩展 |
[医]皮乌斯布 |
来自Python的USB访问模块 |
[医]皮维萨 |
Gpib、RS232、TCPIP和USB工具的PYTHON VISA绑定 |
皮维萨-py |
VISA库的纯Python实现 |
[医]皮亚姆 |
Python的YAML解析器和发射器 |
[医]pyzmq |
0mq的Python绑定 |
n.redis |
Python客户端用于Redis数据库和键值存储 |
请求 |
Python中人的HTTP |
设置工具 |
轻松下载、构建、安装、更新和删除Python包。 |
汤姆尔 |
Python库为汤姆的明显,最小的语言 |
鹿untokenize |
将令牌转换为源代码(同时保留空格) |
urllib3 |
具有线程安全连接池、文件发送和其他功能的HTTP库 |
创建多文件支持包的示例
为了您的方便,我们准备了 存档与完成的项目结构和代码示例。 您将在存档中找到完整的文件夹结构。 设备 和 目标 与工作的例子。
|
让我们用我们自己的文件层次结构创建一个支持包。 为此,我们使用模板文件夹。 扩展,里面有目录 设备 和 目标.
Device(设备)是*不*与模型交互的任意自定义类。 *AnyMath 并且不使用他们的数据。 Target*是*与模型交互*的自定义类 AnyMath ,从其接收数据进行处理并在另一个平台(微控制器,独立计算机等)上执行。).
在我们的示例中,我们将创建一个具有多文件结构的*device*。
-
在文件夹中创建
设备一个新文件夹外接/外接. -
里面
外接/外接创建文件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}" -
创建文件
models.py在同一文件夹中外接/外接: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类,必须继承自 数据结构必须继承自 *所有方法必须包含参数和返回值的完整类型注释。*例如:
如果没有注释,系统将无法正确生成Julia代码并在Python和Julia之间转换数据类型。 用于从块调用的方法不应以 |
| 您可以清楚地看到上面描述的创建自己的支持包的机制是如何在实践中应用于使用社区示例的真实硬件的。: 为Engee开发硬件支持包。整合。 |
上传自定义包到Engee。综合服务
在客户端程序中 恩吉。综合服务 按照以下步骤操作:
-
打开硬件状态窗口。
-
选择选项卡 «扩展».

-
点击 «添加扩展».
-
选择包含要添加到客户端程序的自定义支持包的文件夹。

如果下载成功,客户端程序的诊断窗口中将显示一条消息。:
INFO: Расширение с именем extension было успешно загружено!
要在诊断窗口中获取有关支持包的找到的类及其方法的扩展信息,请在开发人员模式下运行客户端程序。:
engee-device-manager.exe -d
成功下载支持包后,诊断窗口中将显示其他信息。:

注册和使用支持包 AnyMath
对于自定义支持包出现在 工程师。装置。 或 工程师。目标。,在命令行上运行 AnyMath :
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)
每次运行客户端程序时,都会自动下载您的支持包。 如果不再需要,那么您可以将其从客户端程序中的启动中删除。:

调试支持包
使用内置日志记录系统调试支持包。 添加到代码中:
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.info ("讯息")--资讯讯息; -
伐木工人。警告("讯息")--警告; -
伐木工人。错误("讯息")--错误。
消息将显示在客户端程序的诊断窗口中。 您还可以在上面附加的存档中找到日志记录使用的示例。
在客户端程序界面中显示支持包状态
客户端程序显示 恩吉。综合服务#status【已安装硬件状态】:驱动是否加载,设备是否连接。 若要将有关支持包的信息添加到硬件状态窗口,请在device类中实现静态方法。 __get_机会_列表.
它是如何工作的:
-
在启动时,客户端程序从包中导入所有模块。
设备和目标. -
为每个注册的类检查一个私有方法。
__get_机会_列表. -
如果找到该方法,则调用它并返回一个列表。
机会,机会. -
客户端程序每3秒轮询一次此列表,并在硬件状态窗口中显示信息。
字段 机会,机会:
-
钥匙-唯一行标识符。 例子::"my_driver" -
[医]钥匙-界面中的标题。 例子::"MyDevice驱动程序:" -
值_键-状态文本。 例子::"加载"/"未加载" -
值_args-格式化值的参数。 例子::() -
颜色-指示颜色:"绿色","橙色","红色". 例子::"绿色" -
类别:-硬件状态窗口中的选项卡:-
"硬件"— «设备» -
"协议"— «协议» -
"软件"— «软件集成» (默认情况下) -
"嵌入式"— «嵌入式系统»
-
如果未指定字段,则类别由设备包的名称自动确定。
自定义支持包的示例:
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客户端程序中。整合*。