Tutorial

The feature base class

Creating the door controller feature base class

The feature base class

Hint

For a more thorough explanation on feature implementation and base classes, refer to the feature concept page.

First, we need to create a folder and the Python file for the base class. We'll call our door feature "Door Controller" and stick to the SiLA 2 naming convention using Controller ("controls the device in some way"), Provider ("provides information"), and Service ("both controlling and providing") as feature suffix where suitable. The base class is marked with the additional _base suffix:

├── src
  ├── connector
    ├── feature
      ├── door_controller
        ├── door_controller_base.py

Within the Python file, we define our base class as follows:

door_controller_base.py
import abc
import asyncio
from unitelabs.cdk import sila


class DoorControllerBase(sila.Feature, metaclass=abc.ABCMeta):
    """
    Controls the door of the thermocycler and provides functions to 
    monitor its state.
    """

    def __init__(self):
        super().__init__(
            originator="org.silastandard",
            category="examples",
            version="0.1",
            maturity_level="Draft",
        )
        self._door_open: bool = False
        self._door_open_change_event = asyncio.Event()

Code explanation

door_controller_base.py
class DoorControllerBase(sila.Feature, metaclass=abc.ABCMeta):
    """
    Controls the door of the thermocycler and provides functions to 
    monitor its state.
    """
defines a class with the superclass sila.Feature. The metaclass argument defines this class as an abstract base class (abc). Methods defined within this base class don't have to be implemented directly. These so-called abstract methods must be implemented in any class inheriting from the base class.The class docstring (""" ... """) is turned into the feature description that is displayed to the user.
door_controller_base.py
    def __init__(self):
        super().__init__(
            originator="io.unitelabs",
            category="tutorial",
            version="0.1",
            maturity_level="Draft",
        )
The sila.Feature superclass provides the __init__ initialisation method that which is invoked with super().__init__(...) in the base class. Originator, category, version, and maturity level are all arguments we need to pass to the super().__init__(...) call. This basic information provides clients the basic feature information such as versioning and is defined by the SiLA 2 standard. In case of any uncertainty in entering these arguments, refer to the feature concept page for best practices.Within the __init__ method, we add two protected properties:
door_controller_base.py
        self._door_open: bool = False
        self._door_open_change_event = asyncio.Event()
Protected properties in Python are defined with an underscore (_) before the name, indicating that this property should not be accessed/changed directly but rather over methods (see observable property and command methods later in this tutorial). You will learn what these properties do as soon as we interact with them.

Adding the __init__ file

Create an __init__.py file in the same folder to turn the feature into a package. We will add the base class and other classes defined in this base class file, such as defined execution errors or defined data types to the door controller namespace to make the import of those components easier throughout the connector project.

├── src
  ├── connector
    ├── feature
      ├── door_controller
        ├── __init__.py
        ├── door_controller_base.py

This is the code we need in the __init__.py file.

__init__.py
from .door_controller_base import DoorControllerBase, DoorMalfunctionError


__all__ = ["DoorControllerBase", "DoorMalfunctionError"]

Code explanation

The first line contains the imports of the classes we want to export: the door controller base class (DoorControllerBase) and a defined execution error (DoorMalfunctionError, see Defining a new Error) that will be raised in the implementation if there is an error with the closing mechanism.The __all__ statement in the last line defines the symbols that are exported in the door_controller namespace.


Copyright © 2024