spacemanspiff2007 / HABApp

Easy home automation with MQTT and/or openHAB
Apache License 2.0
54 stars 23 forks source link

added ability to listen to all events #379

Open dobernhardt opened 1 year ago

dobernhardt commented 1 year ago

For scenarios where not all possible items are know upfront it might be beneficial to be able to listen to all events on the bus. This change adds the ability to add a catch all event listener by specifying the topic HABApp.Any

spacemanspiff2007 commented 1 year ago

This was actually possible in older versions of HABApp. However I removed it due to the lack of usage and because I haven't had a use case which I couldn't solve by dynamically creating the listeners based on the name. E.g. by passing the Shelly-ID to a rule I was able to construct all required topics.

Can you outline the use case and why you want to achieve that?

dobernhardt commented 1 year ago

I currently have two usecases for the catch_all listener:

  1. I have a persistence solution in habapp that currently grabs all items and attaches listeners to all of them

    for item in Items.get_items ():
            if isinstance(item, OpenhabItem):
                self.logger.debug (str(item.name))
                num_items = num_items +1
                item.listen_event(self.item_updated,ValueUpdateEventFilter()) 

    Whenever I add an item I need to restart this rule. Having a catch_all listener a HABApp persistence solution would be a bit simpler

  2. As already mentioned in the openhab forum I have some rules dealing with shellies and tasmotas. To do autodiscovery it would be beneficial to listen to all mqtt topics below a certain prefix. For shellies not really necessary as they all use shellies/announce

For the MQTT sub hirarchy handling an alternative option would be to directly work with the MQTT client and bypass the habapp event bus.

In sumary non of my scenarious would be impossible without the catchall but they would be easier. Where do you see a concern in having catch all functionality?

spacemanspiff2007 commented 1 year ago

Whenever I add an item I need to restart this rule. Having a catch_all listener a HABApp persistence solution would be a bit simpler

You can listen to openHAB.Items. All ItemAdded / ItemRemoved / ItemUpdatedEvent events will appear there. So there is no need to manually restart the rule. You just have to create listeners for all items on startup and then can track the changes through the topic. Maybe I have to add an example to the docs but I think that's much more elegant than to listen to all events.

2. To do autodiscovery it would be beneficial to listen to all mqtt topics below a certain prefix.

I agree this is a tricky one and I have not yet come up with a simple and elegant solution. Does tasmota use retain for auto discovery? Retained topics will be stored in a MqttItem. HABApp connects to mqtt before it loads the rule so at least it's possible to auto generate all devices when the rule is loaded for the first time. Maybe it makes sense to implement something for retained messages? Maybe MQTT.Items and issue some kind of ItemAddedEvent there?

In sumary non of my scenarious would be impossible without the catchall but they would be easier. Where do you see a concern in having catch all functionality?

I'm hesitant to add this again because it feels like there has to be a more elegant and better solution than to additionally process every event. However this is not a very strong opinion so you might be as well successful to convince me otherwise. In the mean time you can use your implementation of the EventBus and override the HABApp.core.internals.EventBus with your implementation and play around with it.

dobernhardt commented 1 year ago

You can listen to openHAB.Items. All ItemAdded / ItemRemoved / ItemUpdatedEvent events will appear there.

That's a good hint. I will give that a try.

Does tasmota use retain for auto discovery? Retained topics will be stored in a MqttItem.

Yes, the tasmota topics are retained. I.e. if I could iterate over all MqttItems that would also be an option. But I still think that a typical use of Mqtt is, to listen to a complete hierarchy of topics. That is probably quite different to how to deal with openhab items.

In the mean time you can use your implementation of the EventBus and override the HABApp.core.internals.EventBus with your implementation

Could give me one more hint how to use custom startup code to override the internal EventBus implementation? My approach would have been to just work on my branch

dobernhardt commented 1 year ago

I'm hesitant to add this again because it feels like there has to be a more elegant and better solution than to additionally process every event.

I completely understand this concern. If we want to keep the event processing in EventBus one option would be to introduce a new kind of MqttItem that represents a complete subtree. At the end I'm not so much interested in listening to all events but primarily to listen to some Mqtt events where I do not know the exact topic upfront

spacemanspiff2007 commented 1 year ago

if I could iterate over all MqttItems that would also be an option.

It works exactly like you iterate over the openHAB items.

Could give me one more hint how to use custom startup code to override the internal EventBus implementation? My approach would have been to just work on my branch

Just create a HABAppUser module as described in the docs and there you can assign your own event bus. Somehow like this (untested).

import HABApp

class MyEventBus(HABApp.core.internals.EventBus)
    pass

HABApp.core.internals.EventBus = MyEventBus