Engee documentation

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.

  1. Create a new demo folder in the devices folder.

  2. 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.