HABApp - Easy automation with openHAB

All openHAB items are synced into HABApp during start up so you can use all of them.

I don’t understand that question. Can you rephrase or post an example where I can see how something doesn’t work as expected?

Hi @Spaceman_Spiff

sure i do have an example. I just slightly changed the rule to

import HABApp
from HABApp.openhab.events import ItemStateEvent, ItemCommandEvent, ItemStateChangedEvent
from HABApp.core.events import ValueUpdateEventFilter, ValueChangeEventFilter, ValueChangeEvent, ValueUpdateEvent
from HABApp.openhab.items import SwitchItem, ContactItem, DatetimeItem

class MySwitchRule(HABApp.Rule):

    def __init__(self):
        super().__init__()

        self.my_switch = SwitchItem.get_item('MQTT_EG_Kinderzimmer_Links')
        print("my_switch: " + self.my_switch.get_value())
        self.my_switch.listen_event(self.item_changed, ValueUpdateEventFilter())

    def item_changed(self, event: ValueUpdateEvent):
        # Check if event is ValueUpdateEvent
        assert isinstance(event, ValueUpdateEvent), type(event)


        print('Changed '+event.name+' to: '+event.value)

MySwitchRule()

Which then gives in the console when i toggle the Switch in openHAB twice (toggeling ON and following OFF). See that the phrase “Changed …” is repeated.

 14:14:10  patrick@openHAB  ~  33s 
$ /opt/habapp/bin/habapp -c /etc/openhab/habapp
  _   _    _    ____    _
 | | | |  / \  | __ )  / \   _ __  _ __
 | |_| | / _ \ |  _ \ / _ \ | '_ \| '_ \
 |  _  |/ ___ \| |_) / ___ \| |_) | |_) |
 |_| |_/_/   \_|____/_/   \_| .__/| .__/
                            |_|   |_|
                                        1.0.8
my_switch: OFF
Changed MQTT_EG_Kinderzimmer_Links to: ON
Changed MQTT_EG_Kinderzimmer_Links to: ON
Changed MQTT_EG_Kinderzimmer_Links to: OFF
Changed MQTT_EG_Kinderzimmer_Links to: OFF

Frontail gives:

2023-06-10 14:13:57.750 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'MQTT_EG_Kinderzimmer_Links' received command ON
2023-06-10 14:13:57.752 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'MQTT_EG_Kinderzimmer_Links' predicted to become ON
2023-06-10 14:13:57.769 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'MQTT_EG_Kinderzimmer_Links' changed from OFF to ON
2023-06-10 14:14:33.497 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'MQTT_EG_Kinderzimmer_Links' received command OFF
2023-06-10 14:14:33.499 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'MQTT_EG_Kinderzimmer_Links' predicted to become OFF
2023-06-10 14:14:33.513 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'MQTT_EG_Kinderzimmer_Links' changed from ON to OFF

What do you think where this is coming from.

Thx
Patrick

Edit: I also see this in HABApp.log. How can i fix this?

160 2023-06-10 14:15:27.367 [WARN ] [HABApp.Rule ] - /opt/habapp/lib/python3.11/site-packages/paho/mqtt/client.py:1782: ResourceWarning:unclosed <ssl.SSLSocket fd=10, family=2, type=1, proto=6, laddr=('192.168.x.x', 3    2923)>
161 2023-06-10 14:16:31.371 [WARN ] [HABApp.Rule ] - /opt/habapp/lib/python3.11/site-packages/paho/mqtt/client.py:1782: ResourceWarning:unclosed <ssl.SSLSocket fd=10, family=2, type=1, proto=6, laddr=('192.168.x.x, 3    7687)>
162 2023-06-10 14:18:31.375 [WARN ] [HABApp.Rule ] - /opt/habapp/lib/python3.11/site-packages/paho/mqtt/client.py:1782: ResourceWarning:unclosed <ssl.SSLSocket fd=10, family=2, type=1, proto=6, laddr=('192.168.x.x', 4    4707)>
163 2023-06-10 14:20:31.378 [WARN ] [HABApp.Rule ] - /opt/habapp/lib/python3.11/site-packages/paho/mqtt/client.py:1782: ResourceWarning:unclosed <ssl.SSLSocket fd=10, family=2, type=1, proto=6, laddr=('192.168.x.x', 4    0557)>

It should be

print(f'my_switch: {self.my_switch.value}')

You listen to the item state update events. These events are not shown in fronttail.
Check the HABApp_events.log, there you will find all events.
Then you’ll probably see thet it gets issued twice.
If not then you have probably a duplicate rule running

Changed the print as recommended.

You were right, HABApp_events.log mentions 2 Item State Events. Why is this the case? There is only 1 file in the rules folder, i.e. the one posted above. In addition, i have deactivated mqtt so that the other issue mentioned above does not occur anymore.

I would expect just one “Changed MQTT_EG_Kinderzimmer_Links to: …”

173 [2023-06-10 20:43:33,131] [HABApp.EventBus] INFO | MQTT_EG_Kinderzimmer_Links: <ItemCommandEvent name: MQTT_EG_Kinderzimmer_Links, value: OFF>
174 [2023-06-10 20:43:33,147] [HABApp.EventBus] INFO | MQTT_EG_Kinderzimmer_Links: <ItemStatePredictedEvent name: MQTT_EG_Kinderzimmer_Links, value: OFF>
175 [2023-06-10 20:43:33,147] [HABApp.EventBus] INFO | MQTT_EG_Kinderzimmer_Links: <ItemStateEvent name: MQTT_EG_Kinderzimmer_Links, value: OFF>
176 [2023-06-10 20:43:33,151] [HABApp.EventBus] INFO | MQTT_EG_Kinderzimmer_Links: <ItemStateChangedEvent name: MQTT_EG_Kinderzimmer_Links, value: OFF, old_value: ON>
177 [2023-06-10 20:43:33,162] [HABApp.EventBus] INFO | MQTT_EG_Kinderzimmer_Links: <ItemStateEvent name: MQTT_EG_Kinderzimmer_Links, value: OFF>

The HABApp_event log shows the events from openHAB. I can not answer why there are two ItemStateEvents. It’s probably specific to your openHAB installation

Then you need to trigger on a ItemStateChengedEvend or a ValueChangedEvent.
Currently you you listening to a ValueUpdateEvent

Good news everyone! HABApp 1.1.0 is out!

Because I’m still on 1.0.8 I ask here.

I want to get rid of a blown habapp events log (200 MB per day). Most of the power entries from several electrical devices like shellys are not needed to be logged.

So I tried to follow your description Advanced Usage — HABApp beta documentation and added a module HABAppUser.py in the directory openhab-conf/habapp/lib with code

import logging

_ignore_events = [ "power", "more power", "other stuff" ]

def event_not_to_be_ignored(record: logging.LogRecord) -> bool:
    for ign in _ignore_events:
        if ign in record.msg:
            return False
        
    return True


logging.getLogger('HABApp.EventBus').addFilter( event_not_to_be_ignored )

But after reboot the lines cotaining one of these _ignore_events strings are still logged.

What do I have to change?

This module gets loaded before the logging config is loaded.
I’m guessing the logging config overwrites the existing filter.

But you can define the filter in the logging.yml like this, there is no need to use the HABAppUser.

    "filters": {
        "warnings_and_below": {
            "()" : "my_module.filter_maker",
        }
    }

my_module.py:

def filter_maker():
    def event_not_to_be_ignored(record: logging.LogRecord) -> bool:
        for ign in _ignore_events:
            if ign in record.msg:
                return False
    
        return True

Thank you. I’ll give it a try

Is it working as expected?

Yes, it’s working well.

For those who are interested:

Create or use an already existing lib below habapp/lib (in my case called “logger.py”) and add a function filter factory like

def event_filter_factory():

    _ignore_events = [ "power", "more power", "other stuff" ]

    def event_not_to_be_ignored(record: logging.LogRecord) -> bool:
        for ign in _ignore_events:
            if ign in record.msg:
                return False
            
        return True
    
    return event_not_to_be_ignored

Then add the filter to logging.yml

levels:
  ...

formatters:
  ...

filters:
  event_filter:
    (): logger.event_filter_factory

handlers:
  ...
  
  EventFile:
    ..
    filters:
      - event_filter

Hey @Spaceman_Spiff

again after some time i have to come back with an question again. Remember you told me to recreate the configs by simply deleting them? I did so and in addition i had to change the HABApp_events.log and HABApp.log file from my user (pi) to the openhab user. It was working then.

So when i logged in today i did not see HABApp.service running but failed and had a look into it and saw, that it again throws an error on the events.log.

Error loading logging config: Unable to configure handler 'EventFile'

So after looking around i found, that the logging files are again reset to my user (pi). If i fix this again, with

sudo chown openhab:openhab HABApp* 

everything works fine. So i was thinking about what changed since then and there is nothing but some time in between and 2 or 3 reboots of the pi. Can you tell me now, why the log files are created with my normal user and not in the context of the openhab user?

Thanks in advance
Patrick

OLD

-rw-r--r-- 1 pi openhab 3.3M Jun 18 01:54 HABApp_events.log
-rw-r--r-- 1 pi openhab  41M Jun 17 23:59 HABApp_events.log.1
-rw-r--r-- 1 pi openhab  42M Jun 16 23:59 HABApp_events.log.2
-rw-r--r-- 1 pi openhab  41M Jun 15 23:59 HABApp_events.log.3
-rw-r--r-- 1 pi openhab  44K Jun 18 01:43 HABApp.log
-rw-r--r-- 1 pi openhab  44K Jun 11 21:46 HABApp.log.1
-rw-rw-r-- 1 openhab openhab 1.2K Jun 11 11:05 HABApp.log.2
-rw-rw-r-- 1 openhab openhab  36K Jun 10 20:58 HABApp.log.3
-rw-r--r-- 1 openhab openhab 133K Jun 21 21:05 openhab.log

NEW

-rw-r--r-- 1 openhab openhab 3.3M Jun 18 01:54 HABApp_events.log
-rw-r--r-- 1 openhab openhab  41M Jun 17 23:59 HABApp_events.log.1
-rw-r--r-- 1 openhab openhab  42M Jun 16 23:59 HABApp_events.log.2
-rw-r--r-- 1 openhab openhab  41M Jun 15 23:59 HABApp_events.log.3
-rw-r--r-- 1 openhab openhab  44K Jun 18 01:43 HABApp.log
-rw-r--r-- 1 openhab openhab  44K Jun 11 21:46 HABApp.log.1
-rw-rw-r-- 1 openhab openhab 1.2K Jun 11 11:05 HABApp.log.2
-rw-rw-r-- 1 openhab openhab  36K Jun 10 20:58 HABApp.log.3
-rw-r--r-- 1 openhab openhab 133K Jun 21 21:05 openhab.log

Are you using openHABian? If so the issue might be openHABian related.
HABApp is started as a certain user and creates the logfiles accordingly.
So I suspect this might be an issue with ZRAM restore or the HABApp user of the service is wrong

HABApp.Rules] ERROR | ValueError: Sun is always above the horizon on this day, at this location

Trying to use .on_sunrise and on_sunset… and fair enough, where I live, at this time of year, the sun is always up, but not in the spring/autumn/winter. Should HABApp throw an “ERROR” on this? :thinking:

1 Like

That’s interesting - here you you live (just an estimate)?

I think there should be no error but HABApp should select the next day where there is a a sunrise (e.g. the first day in autumn. Is that what you would have expected, too?

1 Like

I live in northern part of Norway

Yes I agree, that would make sense :slight_smile:

Finally, after a good amount of work and hours I’ve migrated all my jython code to HabApp and just wanna share a little of my experience.
It took some time to understand how HabApp works so I migrated some of my simpler rules first just to get the feeling of it. Even though HabApp can’t use “actions” because of the Rest API limitations it was never really a problem since most of my actions are notification services like mail/pushover etc. and could easily be solved by using 3rd party libraries or just write them myself.
The biggest challenge for me was Persistence, which I wrote my own “library”, to make a simple drop-in replacement for functions like averageSince, maximumSince etc. for Influxdb (and that’s the beauty of python :wink: )
Estimate I migrated perhaps 70% of my code “as-is” and only had to rewrite the functions like getting item value etc. The rest needed some changes on a bigger level but also gave me the opportunity to optimize the code. :slight_smile:

I’m sure there are other ways to Rome but this was the easiest for me and also makes my code more inline of how I want it to work.
Huge thanks to @Spaceman_Spiff for all the effort in creating and maintaining HabApp! :smiley:

PS: The HabApp documentation is very good but if I could come with a suggestion it would’ve been nice to add more examples of using the different scheduler functions, datetime, looping groupmembers etc. :innocent:

4 Likes

Could you share your implementations of persistence? I would need to implement the delt since functionality myself.

Just to reply to me:

here is the simple and fast implementation of delta_since:

from influxdb import InfluxDBClient
import yaml
from datetime import datetime, timedelta 
import os

class InfluxDBHelper:
    
    def __init__(self, config_file=os.path.join(os.environ.get('HABAPP_CONF'), "influxdb.yml")):
        self.config = self.load_config(config_file)
        self.client = InfluxDBClient(
            host=self.config['host'], 
            port=self.config['port'], 
            username=self.config['username'], 
            password=self.config['password'], 
            database=self.config['database']
        )

    @staticmethod
    def load_config(filename):
        with open(filename, 'r') as file:
            config = yaml.safe_load(file)
            return config['influxdb']

    def get_delta_since(self, item: str, period: timedelta) -> float:

        # Convert the timedelta to an InfluxDB-compatible time string
        minutes = int(period.total_seconds() / 60)
        
        # Define the query
        query = f'SELECT last("value") - first("value") AS "delta" FROM "{item}" WHERE time >= now() - {minutes}m'

        # Execute the query
        result = self.client.query(query)

        # Process the result
        points = list(result.get_points())
        
        if not points:
            return 0
        else:
            return points[0]['delta']

Howdy! I haven’t been here for a while but I am very much still enjoying HABApp, definitely not idle. My rules folder is now 600 kilobytes :-).

Question. Is there a way to get the openhab item description rather than just the identifier?

Example: .items file definition:

Switch EM_AC_Woodshop  "Woodshop A/C"

SwitchItem.get_item(“EM_AC_Woodshop”).name == “EM_AC_Woodshop”
I would like to get the “Woodshop A/C” string for UI purposes.

I’ve looked through the HABApp openHAB item types documentation with no luck.