In wenigen Minuten zum eigenen Plugin

Plugins sind Erweiterungen von SmartHomeNG mit zusätzlichen Funktionen. Sie sind in Python geschrieben. Um ein neues Plugin hinzuzufügen, wird der Plugin-Code und ein entsprechender Eintrag in der Konfigurationsdatei plugin.yaml benötigt.

Eine gute Basis für ein eigenes Plugin ist das Beispielplugin, welches komplett mit allen notwendigen Dateien auf github unter https://github.com/smarthomeng/smarthome im dev-Ordner zur Verfügung steht.

Beschreibung des Plugins

Übersicht

Das Plugin wird in einem eigenen Ordner unterhalb des plugins-Ordner abgelegt. Der Name des Ordners entspricht dem Namen des Plugins in Kleinschreibung.

Derzeit besteht ein Plugin mindestens aus drei Dateien, die alle im Plugin Ordner liegen. Dies sind:

  • __init__.py

  • plugin.yaml

  • user_doc.rst

Die Datei __init__.py enthält den Python-Code des Plugins.

Die Datei plugin.yaml enthält die Metadaten des Plugins. Diese geben eine formale Beschreibung des Plugins und werden verwendet, um die Dokumentation zu erstellen und das Plugin im Admin-GUI verwalten zu können.

Die Datei user_doc.rst beinhaltet zusätzliche Dokumentation zum Plugin, ausführlichere Beschreibungen, umfangreichere Beispiele oder Anwendungsmöglichkeiten über die plugin.yaml hinaus. Auch diese Datei wird verwendet, um die Dokumentation von SmartHomeNG zu erstellen.

Optional werden im Unterverzeichnis webif die Dateien dabgelegt, welche das Webinterface implementieren. Das Verzeichnis hat folgenden Inhalt:

  • __init__.py

  • Verzeichnis static

  • Verzeichnis templates

Die Datei __init__.py enthält den Python-Code des Webinterfaces des Plugins.

Im Verzeichnis static werden Dateien abgelegt, die durch das Webinterface an den Browser ausgeliefert werden. Es gibt mindestens das Unterverzeichnis img, in dem das Logo des Plugins under dem Namen plugin_logo.png gespeichert wird. Zulässig als Plugin Logos sind auch plugin_logo.jpg und plugin_logo.svg

Weiterhin kann es ein Unterverzeichnis assets geben, in dem weitere Dateien (z.B. zur Dokumentation user_doc) abgelegt werden.

Hinweis

Das in früheren Versionen verwendete README-Format für die Dokumentation von Plugins ist veraltet. Ein Großteil der Dokumentation ist in die Metadaten-Dokumentation in plugin.yaml übergegangen. Die restliche Dokumentation sollte nur noch im user_doc-Format erfolgen.

Soweit möglich, sollten bestehende README im Rahmen von Aktualisierungen in entsprechende user_doc überführt werden.

Um das Plugin zu laden, muss es in der Konfigurationsdatei /etc/plugin.yaml eingebunden und konfiguriert werden.

Die Metadaten: plugin.yaml

Diese Datei stellt Metadaten über das Plugin in den folgenden Abschnitten bereit:

  • plugin - globale Attribute des Plugins

  • parameters - Definition der Konfigurationsoptionen in etc/plugin.yaml

  • item_attributes - Definition der Item-Attribute, die durch dieses Plugin genutzt werden

  • item_structs - Vorlagen für Item-Structs (Teilbäume) des Plugins

  • logic_parameters - Definition von Parametern für Logiken, soweit das Plugin diese implementiert

  • plugin_functions - Funktionen, die das Plugin für die Nutzung z.B. in Logiken bereitstellt

Der Typ des Plugins muss aus der folgenden Liste ausgewählt werden:

  • gateway

  • interface

  • protocol

  • system

  • web

Beispiel einer Metadaten-Datei:

# meta data for the plugin
plugin:
    # Global plugin attributes
    type: interface                # plugin type (gateway, interface, protocol, system, web)

parameters:
    # Definition of parameters to be configured in etc/plugin.yaml

item_attributes:
    # Definition of item attributes defined by this plugin

item_structs: NONE

logic_parameters: NONE

plugin_functions: NONE

Die Dokumentation: user_doc.rst

Die Dokumentation beginnt mit dem Titel, der dem Namen des Plugins entspricht.

Wichtig

Die erste Überschrift der Dokumentationsdatei user_doc MUSS dem Kurznamen des Plugins in Kleinbuchstaben entsprechen.

Dieser Eintrag wird als Einstiegspunkt für die Navigation in der Dokumentation genutzt. Ein anderer Eintrag als Überschrift sorgt für Inkonsistenzen in den Navigationselementen.

Die Datei sollte die folgende Struktur haben.

Die Konfigurationsparameter selbst müssen in der user_doc.rst nicht beschrieben werden. Die Dokumentation der Konfigurationsparameter und der Item Attribute wird automatisch aus den Metadaten (aus der plugin.yaml) generiert. Falls gewünscht kann jeweils auf die (automatisch generierte) Seite mit der Konfigurationsdokumentation verwiesen werden.

user_doc.rst des Sample Plugins

.. index:: Plugins; Pluginname (in Kleinbuchstaben)
.. index:: Pluginname (in Kleinbuchstaben)


===============================
Pluginname (in Kleinbuchstaben)
===============================


.. comment set image name and extension according to the image file you use for the plugin-logo

.. image:: webif/static/img/plugin_logo.png
   :alt: plugin logo
   :width: 300px
   :height: 300px
   :scale: 50 %
   :align: left

<Hier erfolgt die allgemeine Beschreibung des Zwecks des Plugins>


Anforderungen
=============

...

Notwendige Software
-------------------

<Hier wird weitere benötigte Software beschrieben. Falls keine weitere Software benötigt wird, kann dieser
Abschnitt entfallen.>

Unterstützte Geräte
-------------------

<Hier werden unterstützte Geräte beschrieben. Falls keine keine speziell zu beschreibenden Geräte unterstützt
werden, kann dieser Abschnitt entfallen.>


Konfiguration
=============

.. comment Den Text **Pluginname (in Kleinbuchstaben)** durch :doc:`/plugins_doc/config/pluginname` ersetzen

Die Plugin Parameter, die Informationen zur Item-spezifischen Konfiguration des Plugins und zur Logik-spezifischen
Konfiguration sind unter **Pluginname (in Kleinbuchstaben)** beschrieben.

Dort findet sich auch die Dokumentation zu Funktionen, die das Plugin evtl. bereit stellt.


Funktionen
----------

<Hier können bei Bedarf ausführliche Beschreibungen zu den Funktionen dokumentiert werden.>

<Sonst diesen Abschnitt löschen>

|

Beispiele
=========

Hier können bei Bedarf Konfigurationsbeispiele dokumentiert werden.

|

Web Interface
=============

<Hier erfolgt die Beschreibung des Web Interfaces>

Tab 1: <Name des Tabs>
----------------------

<Hier wird der Inhalt und die Funktionalität des Tabs beschrieben.>

.. image:: assets/webif_tab1.jpg
   :class: screenshot

<Zu dem Tab ist ein Screenshot im Unterverzeichnis ``assets`` des Plugins abzulegen.

|

Version History
===============

<In diesem Abschnitt kann die Versionshistorie dokumentiert werden, falls der Plugin Autor dieses möchte.
Diese Abschnitt ist optional.>



Konfigurieren des Plugins in der Systemkonfiguration /etc/plugin.yaml

Die Konfigurationsdatei plugin.yaml befindet sich im Unterordner etc der SmartHomeNG-Installation. Hier wird SmartHomeNG mitgeteilt, welche Plugins geladen werden sollen, wo sie zu finden sind und welche Optionen sie ggf. benötigen.

Dies ist ein typischer Abschnitt für ein neues Plugin. Wir nehmen an, dass das Plugin myplugin heißt:

# etc/plugin.yaml
myplugin_instance:
    plugin_name: myplugin
    parameter1: 42

Werfen wir einen Blick auf die einzelnen Angaben:

myplugin_instance:

Das ist der Name der tatsächlich geladenen Instanz des Plugins. Er kann frei gewählt werden. Wenn mehrere Instanzen eines Plugins geladen werden (z.B. für mehrere Geräte des gleichen Typs), wird anhand dieses Namens zwischen den Instanzen (und damit den Geräten) unterschieden.

plugin_name:

Das ist der Name des Plugin, der auch für den Plugin-Ordner verwendet wurde (wieder in Kleinbuchstaben).

parameter1:

Es können mehrere Parameter definiert werden, deren Werte dem Plugin bei der Initialisierung übergeben werden. Sie können zur Konfiguration verwendet werden.

Der Plugin-Code: __init__.py

Das Nächste ist das Plugin selbst. Der Code befindet sich in der Datei /plugins/myplugin/__init__.py. Alle Plugins haben die gleiche Struktur. Der Einfachheit halber wird das oben verlinkte Beispielplugin als Grundlage verwendet.

Es gibt mehrere Funktionen, die erforderlich sind, damit SmartHomeNG mit dem Plugin korrekt kommunizieren kann. Die meisten davon werden vom SmartHomeNG-Scheduler aufgerufen.

Zusätzlich werden eigene Funktionen im Plugin definiert, die die eigentlichen Aufgaben ausführen. Der Scheduler kann angewiesen werden, diese zu bestimmten Zeiten oder in festgelegten Intervallen aufzurufen. Das ist näher im Abschnitt „Der Scheduler“ beschrieben.

Hinweis

Der folgende Code ist direkt aus dem Beispielplugin (dev/sample_plugin/__init__.py) entnommen. Im Zweifel gilt immer die dort vorliegende, aktuelle Version als Referenz.

Die Klasse des Plugins erbt von SmartPlugin (aus lib.model.smartplugin). Der Klassenname muss dem classname-Parameter in der plugin.yaml entsprechen. Im Folgenden werden die Funktionen beschrieben, die für ein Plugin benötigt werden bzw. benötigt werden können.

Vordefinierte Funktionen des Plugins

def __init__(self, sh=None, **kwargs):

Die __init__-Funktion wird einmal aufgerufen, wenn SmartHomeNG im Rahmen der Initialisierung das Plugin lädt, bevor die Items geladen sind. Hier wird der Code eingefügt, den das Plugin zur Einrichtung benötigt - zum Beispiel könnte ein serieller Port zur Verbindung mit einem externen Gerät vorbereitet, Dateien geöffnet oder Variablen initialisiert werden.

Die eigene __init__-Methode muss super().__init__() aufrufen, damit die von SmartPlugin intern benötigten Strukturen (u.a. für die Item-Verwaltung, siehe unten) korrekt pro Instanz angelegt werden - wird das vergessen, teilen sich versehentlich alle Instanzen des Plugins dieselben Strukturen.

Auf die Parameter aus etc/plugin.yaml wird über self.get_parameter_value(parametername) zugegriffen. Für den (in den meisten Fällen nicht mehr benötigten) direkten Zugriff auf das SmartHomeNG-Objekt steht self.get_sh() zur Verfügung.

        """
        Initalizes the plugin.

        If you need the sh object at all, use the method self.get_sh() to get it. There should be almost no need for
        a reference to the sh object any more.

        Plugins have to use the new way of getting parameter values:
        use the SmartPlugin method get_parameter_value(parameter_name). Anywhere within the Plugin you can get
        the configured (and checked) value for a parameter by calling self.get_parameter_value(parameter_name). It
        returns the value in the datatype that is defined in the metadata.
        """

        # Call init code of parent class (SmartPlugin)
        super().__init__()

        # cycle time in seconds, only needed, if hardware/interface needs to be
        # polled for value changes by adding a scheduler entry in the run method of this plugin
        # (maybe you want to make it a plugin parameter?)
        #
        # self._cycle = 60

        # if you want to use an item to toggle plugin execution, enable the
        # definition in plugin.yaml and uncomment the following line
        #
        # self._pause_item_path = self.get_parameter_value('pause_item')

        # Initialization code goes here

        # On initialization error use:
        #
        # self._init_complete = False
        # return

        self.init_webinterface(WebInterface)
        # if plugin should not start without web interface
        #
        # if not self.init_webinterface():
        #     self._init_complete = False


def run(self):

Die run-Funktion wird einmalig aufgerufen, wenn SmartHomeNG startet - zu diesem Zeitpunkt sind die Items bereits geladen und parse_item() wurde bereits für jedes Item aufgerufen. Die Variable self.alive muss hier auf True gesetzt werden (Ausnahme: bei Nutzung von asyncio wird self.alive von der Coroutine selbst gesetzt).

        """
        Run method for the plugin
        """
        self.logger.dbghigh(self.translate("Methode '{method}' aufgerufen", {'method': 'run()'}))

        # connect to network / web / serial device
        # (enable the following lines if you want to open a connection
        #  don't forget to implement a connect (and disconnect) method.. :) )
        #
        # self.connect()

        # setup scheduler for device poll loop
        # (enable the following line, if you need to poll the device.
        #  Rember to un-comment the self._cycle statement in __init__ as well)
        #
        # self.scheduler_add(self.get_fullname() + '_poll', self.poll_device, cycle=self._cycle)

        # Start the asyncio eventloop in it's own thread
        # and set self.alive to True when the eventloop is running
        # (enable the following line, if you need to use asyncio in the plugin)
        #
        # self.start_asyncio(self.plugin_coro())

        self.alive = True  # if using asyncio, do not set self.alive here. Set it in the session coroutine

        # let the plugin change the state of pause_item
        if self._pause_item:
            self._pause_item(False, self.get_fullname())

        # if you need to create child threads, do not make them daemon = True!
        # They will not shutdown properly. (It's a python bug)
        # Also, don't create the thread in __init__() and start them here, but
        # create and start them here. Threads can not be restarted after they
        # have been stopped...


def stop(self):

Diese Routine wird aufgerufen, wenn SmartHomeNG beendet wird oder das Plugin neu geladen wird (siehe deinit() weiter unten). Hier müssen alle Verbindungen und Threads beendet werden, die das Plugin gestartet hat. Die Variable self.alive muss auf False gesetzt werden.

Wenn self.alive auf False gesetzt ist, sollte das Plugin Änderungen an Items nicht mehr weitergeben und auch keine Daten empfangen und in Items sichern.

        """
        Stop method for the plugin
        """
        self.logger.dbghigh(self.translate("Methode '{method}' aufgerufen", {'method': 'stop()'}))
        self.alive = False  # if using asyncio, do not set self.alive here. Set it in the session coroutine

        # let the plugin change the state of pause_item
        if self._pause_item:
            self._pause_item(True, self.get_fullname())

        # this stops all schedulers the plugin has started.
        # you can disable/delete the line if you don't use schedulers
        self.scheduler_remove_all()

        # stop the asyncio eventloop and it's thread
        # If you use asyncio, enable the following line
        #
        # self.stop_asyncio()

        # If you called connect() on run(), disconnect here
        # (remember to write a disconnect() method!)
        #
        # self.disconnect()

        # also, clean up anything you set up in run(), so the plugin can be
        # cleanly stopped and started again


def parse_item(self, item):

Diese Funktion wird während des Starts für jedes Item einmal aufgerufen, wenn SmartHomeNG die Item-Konfiguration liest - und danach jedes Mal, wenn zur Laufzeit ein neues Item angelegt wird (dynamische Item-Verwaltung, siehe Abschnitt Item-Verwaltung weiter unten). Hier wird geprüft, ob das Item für dieses Plugin relevant ist, üblicherweise über ein plugin-eigenes Item-Attribut, das über self.has_iattr(item.conf, 'attributname') geprüft wird.

Ist das Item relevant, muss es über self.add_item(item, ...) beim Plugin registriert werden. Soll das Plugin außerdem über Änderungen des Items informiert werden, wird zusätzlich die Methode update_item zurückgegeben; diese wird dann von SmartHomeNG jedes Mal aufgerufen, wenn sich der Wert des Items ändert.

        """
        Default plugin parse_item method. Is called when the plugin is initialized.
        The plugin can, corresponding to its attribute keywords, decide what to do with
        the item in future, like adding it to an internal array for future reference
        :param item:    The item to process.
        :return:        If the plugin needs to be informed of an items change you should return a call back function
                        like the function update_item down below. An example when this is needed is the knx plugin
                        where parse_item returns the update_item function when the attribute knx_send is found.
                        This means that when the items value is about to be updated, the call back function is called
                        with the item, caller, source and dest as arguments and in case of the knx plugin the value
                        can be sent to the knx with a knx write function within the knx plugin.
        """
        # check for pause item
        if item.property.path == self._pause_item_path:
            self.logger.debug(f'pause item {item.property.path} registered')
            self._pause_item = item
            self.add_item(item, updating=True)
            return self.update_item

        if self.has_iattr(item.conf, 'foo_itemtag'):
            self.logger.debug(f'parse item: {item}')
            # Register the item so update_item() is called when the item changes.
            # updating=True means the item is also tracked in get_trigger_items().
            self.add_item(item, updating=True)
            return self.update_item


def parse_logic(self, logic):

Diese Funktion wird beim Systemstart für jede Logik aufgerufen. Hier kann geprüft werden, ob ein plugin-spezifischer Parameter in der Logik-Konfiguration gesetzt ist. Soll das Plugin über die Ausführung der Logik informiert werden, wird eine selbst gewählte Callback-Methode zurückgegeben - im Beispiel unten heißt sie run_logic. Das ist kein reservierter Methodenname von SmartPlugin, sondern frei wählbar, genau wie update_item bei parse_item(). Diese Methode wird dann bei Ausführung der Logik aufgerufen, mit denselben Parametern wie update_item().

        """
        Default plugin parse_logic method
        """
        if 'xxx' in logic.conf:
            # self.function(logic['name'])
            pass


def update_item(self, item, caller=None, source=None, dest=None):

Diese Funktion wird jedes Mal aufgerufen, wenn sich der Wert eines Items ändert, für das der Aufruf in parse_item() eingerichtet wurde. Sie erhält die folgenden Parameter:

caller

Dieser String gibt an, wer das Item geändert hat, z.B. der Name eines anderen Plugins.

source

Optionale, genauere Angabe zur Quelle der Änderung.

dest

Optionales Ziel der Änderung.

Um eine Rückkopplungsschleife zu vermeiden, sollte der neue Wert nur dann an das Gerät weitergegeben werden, wenn das Plugin läuft (self.alive) und die Änderung nicht von diesem Plugin selbst ausgelöst wurde (caller != self.get_fullname()).

        """
        Item has been updated

        This method is called, if the value of an item has been updated by SmartHomeNG.
        It should write the changed value out to the device (hardware/interface) that
        is managed by this plugin.

        To prevent a loop, the changed value should only be written to the device, if the plugin is running and
        the value was changed outside of this plugin(-instance). That is checked by comparing the caller parameter
        with the fullname (plugin name & instance) of the plugin.

        :param item: item to be updated towards the plugin
        :param caller: if given it represents the callers name
        :param source: if given it represents the source
        :param dest: if given it represents the dest
        """
        # check for pause item
        if item is self._pause_item:
            if caller != self.get_shortname():
                self.logger.debug(f'pause item changed to {item()}')
                if item() and self.alive:
                    self.stop()
                elif not item() and not self.alive:
                    self.run()
            return

        if self.alive and caller != self.get_fullname():
            # code to execute if the plugin is not stopped
            # and only, if the item has not been changed by this plugin:
            self.logger.info(
                f"update_item: '{item.property.path}' has been changed outside this plugin "
                f"by caller '{self.callerinfo(caller, source)}'"
            )

            # OPTIONAL (asyncio): bridge the synchronous update_item call into
            # the plugin's async event loop.  run_asyncio_coro() blocks until
            # the coroutine returns, so update_item stays synchronous to shNG.
            # result = self.run_asyncio_coro(self._async_send('some_command', item()))

            pass


Item-Verwaltung: add_item, remove_item, parse_item/unparse_item, init/deinit

SmartHomeNG unterstützt dynamische Item-Verwaltung: Items können zur Laufzeit angelegt, geändert oder gelöscht werden, und Plugins können neu geladen werden, ohne dass SmartHomeNG neu gestartet werden muss. Damit das funktioniert, muss ein Plugin seine Item-Zuordnungen sauber auf- und wieder abbauen können. Dafür gibt es folgende, zueinander passende Methodenpaare.

add_item / remove_item

Diese beiden Methoden sind in SmartPlugin bereits vollständig implementiert und dürfen nicht überschrieben werden. add_item(item, config_data_dict=None, mapping=None, updating=False) wird aus parse_item() heraus aufgerufen, um ein Item mit seinen plugin-spezifischen Konfigurationsdaten zu registrieren - danach ist das Item z.B. über self.get_item_list() auffindbar. remove_item(item) macht das rückgängig; es wird automatisch von deinit() aufgerufen (siehe unten) und muss nicht selbst aufgerufen werden.

parse_item / unparse_item

unparse_item(item) ist das symmetrische Gegenstück zu parse_item() und wird automatisch von remove_item() aufgerufen, wenn ein Item entfernt wird (z.B. weil es aus der Konfiguration gelöscht wurde oder das Plugin neu geladen wird).

Ruft parse_item() für ein Item nur self.add_item(...) auf (wie im Beispielplugin oben), muss unparse_item() nicht implementiert werden - die Standardimplementierung tut nichts, und die von add_item() angelegte Buchführung wird bereits automatisch durch remove_item() aufgeräumt:

        """
        Remove user-/plugin-specific bookkeeping of items. Overwrite as needed.

        :param item: item to unparse
        :type item: class Item
        """
        pass

Führt parse_item() darüber hinaus eigene Buchführung durch - z.B. wird das Item zusätzlich in eine eigene Liste oder ein eigenes Dictionary des Plugins eingetragen - muss unparse_item() überschrieben werden, um diesen Eintrag beim Entfernen des Items wieder zu löschen.

__init__ / deinit

deinit() ist das Gegenstück zu __init__() bzw. run()/stop() und wird aufgerufen, kurz bevor ein Plugin entladen wird (z.B. beim Neuladen des Plugins über die AdminUI). Die Standardimplementierung stoppt das Plugin, falls es noch läuft, und entfernt alle registrierten Items über remove_item():

        """
        This method "deinitializes" the plugin, i.e. prepares for unloading.
        The plugin is stopped and all (or all provided) items are un-registered.

        If the Plugin needs special code to be executed before it is unloaded, this method
        has to be overwritten with the code needed for de-initialization. Keep the
        original code or call super().deinit()...

        If called without parameters, all registered items are unregistered.
        items is a list of items (or a single Item() object).
        """
        if self.alive:
            self.stop()

        if items is None:
            items = []
        if not items:
            items = self.get_item_list()
        elif not isinstance(items, list):
            items = [items]

        for item in items:
            self.remove_item(item)

Reicht diese Standardimplementierung nicht aus - etwa weil __init__() oder run() dauerhafte Strukturen angelegt haben (z.B. eigene Threads, Prozesse oder Verbindungen, die über das hinausgehen, was stop() bereits abbaut) - muss deinit() überschrieben werden, um diese vor dem Entladen sauber zu beenden. Der eigene Code sollte dann zusätzlich super().deinit() aufrufen (oder den obigen Code sinngemäß nachbilden), damit Plugin-Stop und Item-Abmeldung weiterhin passieren.

Das Beispielplugin oben implementiert weder unparse_item() noch deinit() - beides ist hier nicht nötig, da parse_item() nur add_item() nutzt und __init__()/run() keine über stop() hinausgehenden dauerhaften Strukturen anlegen.


Erstellung eines Webinterfaces

Die Datei dev/sample_plugin/webif/templates/index.html sollte als Grundlage für Webinterfaces genutzt werden. Um Tabelleninhalte nach Spalten filtern und sortieren zu können, muss der entsprechende Code Block mit Referenz auf die relevante Table ID eingefügt werden (siehe Doku).

SmartHomeNG liefert eine Reihe Komponenten von Drittherstellern mit, die für die Gestaltung des Webinterfaces genutzt werden können. Erweiterungen dieser Komponenten usw. finden sich im Ordner /modules/http/webif/gstatic.

Wenn das Plugin darüber hinaus noch Komponenten benötigt, werden diese im Ordner webif/static des Plugins abgelegt.

Neben diesen vordefinierten Funktionen können auch eigene Funktionen erstellt werden, die Funktionen im Plugin ausführen.

Funktionen von SmartHomeNG

Der Scheduler

Der Scheduler ist eine der wichtigsten Komponenten von SmartHomeNG. Es ist die zentrale Uhr, die Funktionen zu bestimmten Zeiten aufruft. Damit eigene Funktionen ausgeführt werden, müssen diese dem Scheduler bekannt gemacht werden. Dies erfolgt durch den Aufruf spezieller Funktionen, die SmartPlugin bereitstellt (self.scheduler_add() usw.) - ein direkter Zugriff auf den Scheduler von SmartHomeNG ist dafür nicht nötig.

Die wichtigste Funktion ist add:

scheduler_add

self.scheduler_add('name',
                   obj,
                   prio=3,
                   cron=None,
                   cycle=None,
                   value=None,
                   offset=None,
                   next=None)

scheduler_add fügt dem Scheduler einen Eintrag hinzu. Es müssen mindestens name, object und einer der Timing-Parameter übergeben werden.

name=string

Das ist der Name, der diesem Scheduler-Eintrag gegeben wird. Er wird benötigt, um den Scheduler-Eintrag zu verändern oder zu löschen.

obj=function

obj ist eine Funktion, die im Plugin definiert wird (ein sogenannter Callback). Diese Funktion wird vom Scheduler aufgerufen. Wenn die Funktion Parameter benötigt, können diese mit **kwargs übergeben werden (siehe weiter unten in der Beschreibung der Parameter).

cron=string

Der Parameter für cron ist ein String im SmartHomeNG spezifischen crontab Format. Siehe Dokumentation zu Crontab Damit wird der Scheduler angewiesen, die Funktion obj entsprechend oft aufzurufen.

cycle=int

cycle ist eine Ganzzahl in Sekunden. Damit wird der Scheduler angewiesen, die Funktion obj alle cycle Sekunden aufzurufen. Wenn das Intervall auf 60 gesetzt wird, ruft der Scheduler die Funktion alle 60 Sekunden auf, so lange SmartHomeNG läuft.

next=dateobject

next fordert die einmalige Ausführung von obj zu dem Zeitpunkt an, der als Argument übergeben wird. Das Argument ist ein dateobject, das z.B. mit datetime erstellt werden kann:

nd = datetime.strptime('Jan 14 2015 8:09PM','%b %d %Y %I:%M%p').replace(tzinfo=self.shtime.tzinfo())

Wichtig

Die Zeitzone muss im datetime-Objekt mit angegeben werden, ansonsten kann der Scheduler abstürzen. Im Beispiel wird die Zeitzone von SmartHomeNG benutzt.

value

Mit dem Parameter value können Argumente an die Funktion obj übergeben werden, wenn der Scheduler sie aufruft. Dies ist eine Liste von keyword=value-Wertpaaren. Diese können wie folgt definiert werden:

_bla(self, **kwargs):
    if 'heinz' in kwargs:
        logger.info("found")
        em = kwargs['heinz']

In dem Fall sollte der Scheduler mit einer Werteliste aufgerufen werden:

self.scheduler_add('name',
                    self._bla,
                    value={'heinz': bla, 'tom': 10},
                    next=_ndate)

..warning:

Werte können über den Scheduler nur weitergegeben werden, wenn dieser mit dem Parameter ``next`` für eine einmalige Ausführung aufgerufen wird. Für eine periodische Ausführung können keine Argumente übergeben werden.
offset=int

Wenn eine periodische Ausführung mit cycle angefordert wurde, wird die erste Ausführung um offset Sekunden verzögert. Wenn z.B. ein cycle=10 und offset=20 gesetzt wurde, dann wird die erste Ausführung 20 Sekunden nach Abschluss der Initialisierung erfolgen und jede weitere jeweils 10 Sekunden später.

Wenn offset nicht definiert oder auf 0 gesetzt wird, legt SmartHomeNG einen Zufallswert zwischen 10 und 15 Sekunden fest.

scheduler_remove

self.scheduler_remove(name)

Diese Funktion löscht den mit name bezeichneten Eintrag aus dem Scheduler.

Name=string

Der Name der Schedulereintrags als String.

Items suchen

from lib.item import Items
items = Items.get_instance()

items.return_item(item_path)

return_item gibt das Item mit dem Pfad item_path zurück. Innerhalb einer Logik ist das items-Objekt bereits initialisiert und kann direkt genutzt werden.

item_path=string

Der Pfad des Items, wie er in der Item Konfiguration festgelegt ist, z.B. Ebene1.Raum4.Lampe2 Die Funktion gibt das Item-Objekt zurück, welches aufgerufen werden kann, um den Wert zu lesen oder zu ändern oder auf andere Eigenschaften zuzugreifen.

Items verändern

item(value, caller)

value

Der Wert, der dem Item zugewiesen werden soll. Für boolesche Items ist dies True oder False.

caller=string

Ein selbst gewählter Name, der denjenigen identifiziert, der das Item verändert hat. Dieses Argument wird an die Funktion update_item übergeben.