Dynamically create HABApp Rules with auto discovery

Helle @Spaceman_Spiff,

I added a couple of python modules that dynamically create objexcts for each HW found in the network.

I can successfully set/read/change/… items and things in openHAB. That works like a charm.

But when I try to use the scheduler to create a cyclic (self.run.every) task it does not work. The call properly returns an instance of ScheduledCallbackBase (e.g. ReoccurringJob next_run: 2022-12-08T22:12:24.226000). But the function never gets scheduled.

        if device['type'] == "BrickletIo16V2":
            new_device = BrickletIo16V2(ipcon, device, log)
        elif device['type'] == "BrickletIo16V2Switch":
            new_device = BrickletIo16V2Switch(ipcon, device, log)
        elif device['type'] == "BrickletIo16V2Window":
            new_device = BrickletIo16V2Window(ipcon, device, log)
        elif device['type'] == "BrickletOut4":
            new_device = BrickletOut4(ipcon, device, log)
        else:
            log.error("unknown type: %s", device["type"])
class BrickletOut4(TinkerforgeBase, OhBase):
    """abstracts the handling of BrickletOut4 bricklets of tinkerforge"""

    def __init__(self, ipconnection, deviceconfig, logger):
        """initialize the output bricklet"""

        TinkerforgeBase.__init__(self, ipconnection, logger)
        OhBase.__init__(self, logger)

I derive my class from HABApp.Rule.
I initialize the super class

class OhBase(HABApp.Rule):
    """abstracts the handling of openHAB interaction"""

    def __init__(self, logger):
        """initialize the base class"""
        super().__init__()
        # lagger passed via constructor
        self.logger = logger
.
.
.
.
    def run_every(self, startTime, intervalTime):
        """support cyclic tasks"""
        ret = self.run.every(
            start_time=datetime.timedelta(seconds=startTime),
            interval=intervalTime,
            callback=self.test
        )
        self.logger.info(
            f"{startTime} : {intervalTime} : {callbackFunction} :: {ret}")

    def test(self):
        """test function

        just log something to see if the function was called"""
        self.logger.info("Hallo")

What am I missing?

Can you describe a little bit further how you are doing this? Do you create rules on discovery and everything runs in a rule file? Or is this code from inside the module?
Where do you keep the code?

Hi sure,

I have a main module that parses the network and creates a class for each device found.
This class is derived from HABapp.Rule and from the BaseDevice (Tinkerforge ip-Handler and the Tinkerforge device specific Python module).
So I created a lib that contains all the devices (Input, Output and Sensor devices). Each single device is in its own file but derived from HABapp.Rule.
The files import needed Item- and Event -definition and independently sets/reads items.

BUT as I create the instances “on demand” I do not have the usual instance of the class at the end of the file (e.g. Additional rule examples — HABApp beta documentation last line MyRule()

Give me a day (or two) I will create a minimum reproduction scenario.

The rules you want to load have to be created when execution of the file is complete.
Dynamically adding rules after the file has been loaded is currently not supported.
In the HABApp.log you’ll see which kind of rules have been found and loaded for the file.
Are your rules there?

There are some “Warnings”

2022-12-10 12:13:09.402 [INFO ] [HABApp.Rules ] - Added rule “MyOpenhabRule” from rules/myOpenHABRule.py
2022-12-10 12:13:09.666 [INFO ] [HABApp.Rules ] - Added rule “zigbee2Mqtt_Bridge” from rules/myZigbeeToMqtt.py
2022-12-10 12:13:09.704 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/BrickletIo16V2.py
2022-12-10 12:13:09.713 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/BrickletIo16V2Switch.py
2022-12-10 12:13:09.719 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/BrickletIo16V2Window.py
2022-12-10 12:13:09.733 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/BrickletOut4.py
2022-12-10 12:13:09.740 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/OhBase.py
2022-12-10 12:13:09.747 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/TinkerforgeBase.py
2022-12-10 12:13:09.752 [WARN ] [HABApp.Rules ] - Found no instances of HABApp.Rule in /etc/openhab/habapp/rules/tinkerforge_oh/init.py

I though it’s OK to ignore then, as it is intended and the rest of the functionality is working great.

[2022-12-10 12:13:09,773] [ Tinkerforge] INFO | Started tinkerforge_oh_.py
Name = /etc/openhab/habapp/rules/tinkerforge_oh_.py
[2022-12-10 12:13:09,776] [ Tinkerforge] INFO |
[2022-12-10 12:13:09,777] [ Tinkerforge] INFO | started at: 10.Dec 2022 12:13:09
[2022-12-10 12:13:09,777] [ Tinkerforge] INFO | PID = 3022
[2022-12-10 12:13:09,787] [ Tinkerforge] INFO | initializing bricklet IO-16 Bricklet 2.0 with uid: io1
[2022-12-10 12:13:09,794] [ Tinkerforge] INFO | added device:
UID : io1
connected to : 5W3ivb
at position : c
HW version : 1.0.0
FW version : 2.0.2
device ident : 2114
[2022-12-10 12:13:09,802] [ Tinkerforge] INFO | uid: io1 - Channel 00 : ‘SchalterWerkstatt’ : state - CLOSED
[2022-12-10 12:13:09,806] [ Tinkerforge] INFO | period: 200ms - has to change = True
.
.
.
[2022-12-10 12:23:54,519] [ Tinkerforge] INFO | received LichtWohnzimmer_State ← ON
[2022-12-10 12:24:08,129] [ Tinkerforge] INFO | received LichtKaminzimmer_State ← ON

Can’t you put the logic in the file and create the classes there?

Hi @Spaceman_Spiff,
sorry for the really late reply - but I was sick last week.

Thanks - I tried your solution and it works :slight_smile:

I now create the timer in the main class directly and just cyclically call the member function of the dynamically created objects.

That’s one way to tackle it.

I thought more about

my_rule.py:

for cls, parameters in discover_tinkerforge():
    cls(parameters):

with discover_tinkerforge returning a list of class / parameters.

I think it’s even possible to create the rules in discover_tinkerforge, the important part is that they are created when the file is completely executed.
The log messages will be your guide.

Imho you can also put all the rules in the “tinkerforge_oh” folder, just don’t make it a package.
Then you can have one rule doing the auto discovery and then dynamically reloading the rules.
Could you describe in a couple of short sentences describe how the auto discovery works?

@rlkoshak
Could you split the last couple of posts starting from Schrott.Micha starting Dec8 in a new thread “Dynamically create HABApp Rules with auto discovery”?

Yes - I found that out yesterday as well.

I missed to remove one change that was a left over from the previous setup. There the process run as a daemon and the main-logic never terminated.

Only after I removed this I could use the scheduler properly.

Thanks for your help.

Done. Let me know if I messed it up.

1 Like

Perfect - thank you for your help!