Devices and Controllers#

Device is the base class of every device, from sensors to motors. Controller is a special type of device that can contain child devices. By introducing controllers, we have a device tree. The tree always starts from a controller node known as the main controller.

Register a Controller#

from leads import controller, MAIN_CONTROLLER
from leads_emulation import RandomController


@controller(MAIN_CONTROLLER)
class MainController(RandomController):
    pass

The example above registers RandomController as the main controller. MAIN_CONTROLLER is the tag of the controller. In the device tree, every device have a tag. You can use these predefined tags or custom strings.

Tip

All tags should be composed of lowercase letters and underscores only. It is not fatal, but it will make your project more disciplined.

Pass Arguments to the Controller#

To pass arguments to the device constructor, just include them in the decorator.

from leads import controller, MAIN_CONTROLLER
from leads_emulation import RandomController


@controller(MAIN_CONTROLLER, args=(10, 100), kwargs={"skid_possibility": 0.5})
class MainController(RandomController):
    pass

Register a Device#

As the top node of the device tree is always a controller, all devices must have a parent.

from leads import device, controller, MAIN_CONTROLLER, ODOMETER, Odometer
from leads_emulation import RandomController


@controller(MAIN_CONTROLLER)
class MainController(RandomController):
    pass


@device(ODOMETER, MAIN_CONTROLLER)
class ChildDevice(Odometer):
    pass

Register a Child Controller#

Controllers can be child devices of other controllers as well.

from leads import controller, MAIN_CONTROLLER
from leads_emulation import RandomController, SinController


@controller(MAIN_CONTROLLER, args=(10, 100), kwargs={"skid_possibility": 0.5})
class MainController(RandomController):
    pass


@controller("secondary_controller", MAIN_CONTROLLER)
class SecondaryController(SinController):
    pass

Define a Custom Device#

In many cases the built-in devices are not sufficient. You can define your devices in a separate module or along with the registration, which is shown below.

from typing import override as _override

from leads import controller, MAIN_CONTROLLER, device, Device, L
from leads_emulation import RandomController


@controller(MAIN_CONTROLLER, args=(10, 100), kwargs={"skid_possibility": 0.5})
class MainController(RandomController):
    pass


@device("my_device", MAIN_CONTROLLER)
class MyDevice(Device):
    def __init__(self) -> None:
        super().__init__()
        self._value: int = 0

    @_override
    def initialize(self, *parent_tags: str) -> None:
        super().initialize(*parent_tags)
        L.info("My device is initializing")

    @_override
    def write(self, payload: int) -> None:
        L.info(f"My device receives an input: {payload}")
        self._value = payload

    @_override
    def read(self) -> int:
        return self._value

Important

In most cases you should call super().initialize(*parent_tags) unless you know you want to break the initialization chain.