Creation and usage of custom extensions through the Engee hardware support package
Page in progress. |
Hardware Support Package Engee allows you to organize interaction between Engee and client program of the user.
Now you can create your own Python modules that will be executed on the client program and return the result back to Engee. For this purpose, automatic generation of Julia code from your Python modules is provided. This allows you to call your functions directly from the Engee command line or from blocks.
At the heart of this mechanism is technology RPC (Remote Procedure Call — remote procedure call). You call a function in Julia that sends arguments over the network to the client computer. There, the hardware support package executes the corresponding Python function with these parameters and returns the result back.
An example of creating a simple extension
Let’s create a simple custom extension. To do this, use the template folder module
, inside which there are directories devices
and `targets'.
-
Device (Device) is an arbitrary custom class that does not*interact with *Engee models and does not use their data.
-
Target is a user class that interacts with the Engee model, receives data from it for processing and executes on another platform (microcontroller, separate computer, etc.).
In our example, we will create a device.
-
Create a new
demo
folder in thedevices
folder. -
Create a file inside the
demo
`demo.py ` with the following code:
import time
import datetime
from devices.base_device import BaseDevice
class Demo(BaseDevice):
def __init__(self) -> None:
pass
def __del__(self) -> None:
pass
def solve_equation(self, x: float, y: float, z: float) -> float:
return x * y - z
def get_host_time(self) -> str:
host_time = time.localtime()
return str(host_time)
This is an example of a simple device. Our Demo
class can calculate the result of the equation with the specified parameters and return the current time from the client program to Engee.
Note that the Demo
class inherits from BaseDevice'. This is necessary for the hardware support package to register it as an RPC class. If we were creating a target, we would inherit from 'BaseTarget
:
from targets.base_target import BaseTarget
For custom RPC classes, it is mandatory to inherit from BaseDevice (if it is a device) or from BaseTarget (if it is a target).
|
Transfer of data structures
If you want to transfer complex data structures, then create a demo
file in the same directory `models.py `. For example:
from devices.base_models import BaseModel
class MyStruct(BaseModel):
parameter_x: int
parameter_y: int
parameter_z: float
For data structures, it is mandatory to inherit from `BaseModel'! |
Then you can use this structure in your main class:
from devices.demo.models import MyStruct
class Demo(BaseDevice):
...
def func(self, comp_s: MyStruct) -> float:
return comp_s.parameter_x + comp_s.parameter_y + comp_s.parameter_z
Registration and usage of the module in Engee
After creating the Python module, you need to generate the appropriate Julia code and register the module in Engee.
First, let’s look at the list of existing devices:
engee> using Main.EngeeDeviceManager.Devices.
CAN COM ECHO HID
HTTP L502BOARD LOGITECHG29WHEEL MODBUSMASTER
SOCKET TFLEXDOCS THRUSTMASTERJOYSTICK THRUSTMASTERTHROTTLE
UM UTILS VISA
Our DEMO
module is not here yet.
Specify the path to our module
folder and download the extension:
engee> module_path = "/path/to/module"
engee> using Main.EngeeDeviceManager.Devices.UTILS
engee> using Main.EngeeDeviceManager.UTILS_API
engee> utils = UTILS.Utils()
engee> UTILS_API.loadExtension(utils, module_path)
If everything was successful, a message will appear in the client program logs:
INFO | Extension with name: module was loaded successfully!
Now the module is registered. Reboot the Engee kernel and restart the hardware support package:
engee> engee.clear_all()
# Waiting for the kernel reboot
engee> engee.package.start("Engee-Device-Manager")
Let’s look at the list of devices again:
engee> using Main.EngeeDeviceManager.Devices.
CAN COM DEMO ECHO
HID HTTP L502BOARD LOGITECHG29WHEEL
MODBUSMASTER SOCKET TFLEXDOCS THRUSTMASTERJOYSTICK
THRUSTMASTERTHROTTLE UM UTILS VISA
Now the DEMO
module is in the list and it can be used:
engee> demo = DEMO.Demo()
Main.EngeeDeviceManager.Devices.DEMO.Demo("Demo", UUID("1ffb2334-3176-42ac-931e-c278af2506cb"), ["solve_equation", "get_host_time"], "Demo_1ffb2334-3176-42ac-931e-c278af2506cb_reply", Main.EngeeDeviceManager.Devices.DEMO.var"#solve_equation#3"{String, UUID}("Demo", UUID("1ffb2334-3176-42ac-931e-c278af2506cb")), Main.EngeeDeviceManager.Devices.DEMO.var"#get_host_time#4"{String, UUID}("Demo", UUID("1ffb2334-3176-42ac-931e-c278af2506cb")))
engee> demo.solve_equation(5.5, 6.6, 7.7)
28.599999999999998
engee> demo.get_host_time()
"time.struct_time(tm_year=2025, tm_mon=8, tm_mday=27, tm_hour=19, tm_min=32, tm_sec=52, tm_wday=2, tm_yday=239, tm_isdst=0)"
Your extension will be automatically loaded every time you run the client program. If it is no longer needed, then you can delete it from startup:
engee> UTILS_API.deleteExtension(utils, module_path)
The 'deleteExtension` function removes the extension from the startup list. In order for the changes to take effect, it is necessary to completely restart the Engee hardware support package. |
Thus, we created a "bridge" between Engee and custom Python code, performed calculations on the client program and got the result in Engee.