Cannot get habapp rule work with instance of class in other class

i try to get a habapp rule work but i am lost. i create for each shutter in my home one instance of the class ‘Shutter’ (i want to control each shutter separately to be able to enable / disable opening and closing, sun protection, … for each shutter separately).
my shutters shall be closed when dusk, so i added this event. most shutters only get the command DOWN so it is easy. but some shutters shall close with spezial commands, therefore i created another class that is called then.

my problem is that wenn i call the ‘evening_close()’ via
self.run.on_sun_dusk(self.__check_evening_close)
then the
self.run.countdown(5, self.close_iBalkon_Ro_body).reset()
will never start. if i call it direct like
self.evening_close()
then it works as espected

this is my code (cleared easy):

class Shutter(HABApp.Rule):
    def __init__(self):
        super().__init__()
        self.log = logging.getLogger('My_HABApp')

        # this calls 'close_iBalkon_Ro' but the countdown there does not call close_iBalkon_Ro_body
        self.run.on_sun_dusk(self.evening_close)
        # this also does not work
        # self.run.soon(self.evening_close)

        # but this works:
        # self.evening_close()


    def evening_close(self):
        self.log.debug('### evening_close started ###')
        self.shutter_name = 'iBalkon_Ro'
        getattr(ShutterSpecial(), "close_" + self.shutter_name)()


class ShutterSpecial(HABApp.Rule):
    def __init__(self):
        super().__init__()
        self.log = logging.getLogger('My_HABApp')
        self.log.setLevel(10)                       # 10 = debug / 20 = info / 30 = warning


    # *********************************************************************************************
    # Closing-Spezial für iBalkon_Ro
    # *********************************************************************************************
    def close_iBalkon_Ro_body(self):
        self.log.debug('Shutter: Closing-Spezial iBalkon_Ro start close_iBalkon_Ro_body')


    def close_iBalkon_Ro(self):
        self.log.debug('Shutter: Closing-Spezial für iBalkon_Ro gestartet')

        self.run.countdown(5, self.close_iBalkon_Ro_body).reset()

Shutter()

any hints would be appreciated.

You’re trying to dynamically create a rule every time in evening_close which is not good.
I guess I should add an error message.
Also if you write something with getattr it’s often an indicator that you are doing something wrong and there is a more elegant way.
Here’s how I would do it:

import logging

from HABApp import Rule
from HABApp.openhab.items import RollershutterItem


class Shutter(Rule):
    def __init__(self, item_name: str):
        super().__init__()
        self.log = logging.getLogger('My_HABApp')

        self.shutter = RollershutterItem.get_item(item_name)
        self.run.on_sun_dusk(self.evening_close)

    def evening_close(self):
        self.log.debug('### evening_close started ###')


Shutter('ShutterItem1')
Shutter('ShutterItem2')


class ShutterSpecial(Shutter):

    def __init__(self, item_name: str):
        super().__init__(item_name)
        self.log.setLevel(logging.DEBUG)    # <--- !!

        self.countdown = self.run.countdown(5, self.close_iBalkon_Ro_body)

    # This replaces the behavior from Shutter
    def evening_close(self):
        self.log.debug('### evening_close started ###')
        self.countdown.reset()

    def close_iBalkon_Ro_body(self):
        self.log.debug('Shutter: Closing-Spezial iBalkon_Ro start close_iBalkon_Ro_body')


Shutter('ShutterSpecialItem1')
Shutter('ShutterSpecialItem2')

All rules are created when the file gets loaded so you’ll properly get events and the scheduler.
Note that I inherited from Shutter and just replaced the behavior I want to change, e.g. evening_close

2 Likes

thanks a lot for the helpful answer! in this way it works.

i had all my rules in jython and now i try to convert them to habapp one after each other. some are easy and some make me real headache (because some where also not good coded in jython).

my main problem is i never learned python ‘correct’ - just searched over the internet and much is try and error, so for many things i dont know the way they have to be done.

so i am really happy about your help that pointed me the correct direction, thanks a lot!

ps:

i have a jython file with all my shutter item names and all other paramters that are individual for each shutter, eg:

{
  "iEGFlur_Fenster_Ro": {
    "shutter_type": "shutter",
    "actor_own": "89#4#01",
    "pos_bevore_storm": 78.0,
    "group_name": "iG_EWoK",
    "automatic": "ON",
    "auto_protect": 0,
    "protect_active": "OFF",
    "protect_pos": 0,
    "act_dev_max": 0,
    "temp_item": "iEGFlur_Heizung",
    "temp_start": 0.0,
    "max_clouds": 0,
    "start_azimuth": 120,
    "end_azimuth": 210,
    "dis_morning": "OFF",
    "dis_evening": "OFF",
    "contact_check": "OFF",
    "opentime_work": 420,
    "opentime_holiday": 600,
    "closing_time": 30,
    "closing_special": "OFF",
    "state_item_name": "iEGFlur_Fenster_Ro_State"
  },
  "iWC_Ro": {
    "shutter_type": "shutter",
...

the first name is the item name of the shutter. for example when the key 'closing_special' is ON then i use gettattr to call the funcition that is extra for this single shutter and that i coded with ‘close_’ followed by the name of the shutter:

getattr(self, "close_" + self.shutter_name)()

You should use a HABApp Parameter and pass the DictParameter directly to the Rule.
That way changes will even be picked up without having to reload the rule file.
Then you can use the normal dict loopup with ["key"]

thank you for your effort and the hint. i am afraid my skills are not good enough and obviously i have a complete differnt approach so i am not able to implement that.

but with your first hint i got it work, although i need the getattr because i cannot imagine how to call different methods only by passing a parameter.

i will try to improve my knowledge to produce better code next time :blush:

No - the approach is almost identical you’re just doing it the hard way :wink: .

You can just copy the content of the dict in your jython file in a .yml file (e.g. shutters.yml) in your parameter directory. Your code should still work as before but you don’t have to reload files when you change parameters . You just have to replace the getattr calls with the [] operator.
Then modify your shutter rule creation like this

import logging
from HABApp import DictParameter, Rule
from HABApp.openhab.items import RollershutterItem


class Shutter(Rule):
    def __init__(self, shutter_name: str):
        super().__init__()
        self.log = logging.getLogger('My_HABApp')
        self.shutter = RollershutterItem.get_item(shutter_name)

        self.config = DictParameter('shutters', shutter_name)    # this will now hold the shutter config

        # access the configuration like this instead of getattr
        actor = self.config['actor_own']
        closing_time = self.config['closing_time']
        closing_time = self.config['closing_time']

        # you can build the keys dynamically
        prefix = 'opentime'
        dyn_access_opentime_work = self.config[f'{prefix:s}_work']
    ...

class ShutterSpecial(Shutter):

    def __init__(self, item_name: str):
        super().__init__(item_name)
        self.log.setLevel(logging.DEBUG)    # <--- !!

        self.countdown = self.run.countdown(5, self.close_iBalkon_Ro_body)
    ...


# Build the rules based on the parameter file
for shutter_name, shutter_config in DictParameter('shutters').items():
    if shutter_config['closing_special'] == 'OFF':
        Shutter(shutter_name)
    else:
        ShutterSpecial(shutter_name)

I would recommend to at least make a small tutorial which explains the built in data types (e.g. strings, lists, tuple, sets and dictionaries). They are your bread and butter and you’ll have it way easier if you can work with them properly. Additionally maybe an easy and short introduction into object oriented programming (OOP) and class and instance attributes. It will be time well spend, e.g. take a look e.g. at “Grundlagen von Python” on the free online course (german).
If you need further hints you can of course PM me.

1 Like

thats amazing nice, thank you :blush:

i will have a look at this and see how far i get :+1: