HABApp - Easy automation with openHAB

Sounds good.
If you run HABApp on the same machine as openhab it should still be available without https.
For testing from another machine it is indeed needed.

Hi @Spaceman_Spiff,

i have added a PR to enable ssl connections to openhab, since iā€™m also running my test instance behind an (ssl-enabled) reverse proxy - would you mind verifying?

Cheers,
Alex

I would like to create an event listener to listen to events to all events. While the docs of listen_event suggest that passing None as item name would allow to listen to events of all items there is an assert in the constructor of the EventBusListener preventing this.

Any idea how to listen to events independent of a particular item? In particular I would be interested in listening ItemAdded events from openhab.

Dominik

That was the way it was implemented before but I did not like it. I removed the implementation but it seems that I forgot to modify the docs.
Currently itā€™s only possible to subscribe to changes if you already know the item names which means the item has to already exist.

You can iterate over the existing items and create the according listeners for every item.

What exactly are you trying to do?

Since the upgrade to OH 3 my influxdb persistence did not work any more and I had implemented it with a few lines of code in HABApp. Currently I iterate at startup over all items to create listeners. However, this way I miss Items that got created after HABApp was started and I need to rember to refresh that rule. An alternative would of course would also to check for new items.
Funfact: Since I updated yesterday to OH 3.2 M4 the OH persistence is working again.

An alternative would be to cache the name and listener in a dict and periodically iterate over all items again and add the missing listeners. But thatā€™s just a workaround.
Iā€™ll create something for the listeners in the next releases.

But Iā€™m happy you were able to come up with a quick and easy workaround in HABApp!

Hi All,

again i think that i do not see the forest because there are so many trees.

Please assume that my house has a bunch of windows and i like to get a notification if a windows i open for more than 15 minutes. WIndows (the state) are defined as a gourp of window contacts with an or function, because sole window have more than one wing. If there is only wing thant a windows is represented just as an contact.

So far i managed to get a notification after 15 minutes with the countdown job and distinguish between a contact group and a contact to set the listeners.

Now i am at the point the creat the different window watchers.

One way is to create a parameter file with all the windows an iterate through the entries an create a watcher. I have done that for my thermostates.

for thermostat in HABApp.Parameter('thermostats', 'thermostats').value:
    Thermostat(thermostat)

Works like a charm. My question is now could i do a simlilar thing with a group like this?

for thermostat in get_item('myGroup).members:
    Thermostat(thermostat)

Didā€™nt get it in my mind at the moment and what ist the best solution.

One benefit from the parameter file i see is that i could trigger to reload the rule if the file changes

An new question to understand the count down better.

1.) countdown(time) creates a countdown job that runs time seconds if the job ist started with reset()

2.) get_next_run() return the timestamp the countdown is down to zero. it return Null if the countdown is not started with reset

3.) cacel() cancels the countdown and the countdown could not be restartet with reset() after a cancel and the job is deffered

Are these statements are correct?

So there is no way to stop, reset and restart the countdown. That means that if for any reason the count down needs to be stopped the way ist to call canel und create a new countdown job afterwards.

How about using the item watcher and watch for item changes?

def __init__(self):
    self.item = Item.get_create_item('MyWindow')
    self.item.watch_change(15 * 60).listen_event(self.window_const)

def window_const(self, event):
    if self.item.is_closed():
        return None
    # do_notification
    ...

You could iterate through the group members as you described and it will work, too.
Imho it depends how you do your abstraction.
If itā€™s just a simple rule that displays Window MyWindow is open! then itā€™s fine either way.
If you want to create more sophisticated rules and e.g. want to group window wings logically together or even want different timeouts Iā€™d definately go the param file way because itā€™s easier to add/remove additional information in it. And if you attach the parameter to the rule youā€™ll always have the most recent values even without reloading the rule file.


The countdown is actually a rather simple implementation:
A call to .reset() will start the countdown with the specified time. It doesnā€™t matter if the countdown is already expired or if itā€™s currently running. It will always start again with the configured time.
A call do .cancel() will ā€œdestroyā€ the countdown object so you have to create a new one if you want to use it again.
There currently is no way to stop the countdown without letting it expire. If you create an issue maybe Iā€™ll add it some day :wink: .

1 Like

As always thanks a lot for your answer. They give me everytime new insights.

Ok, the countdown thing - Check

The wathcer, nice idea, never tought in this way. Itvtriggers the state check every 15 minutes of stable state and my solution startes triggering only if the state changes. I try to keep that option in Mind.

The group thing. I am with you that if i need additional information. But i did not bring it to work to creat instances of a rule from a group. Checkt a group within a rule works. I do it for battery checking.

As you se from my last request it may take some time to create an issue :slight_smile:

Hi! Iā€™m finally starting my adventure into habAPP.

Iā€™m running the docker image from ā€œspacemanspiff2007/habappā€ on a Pi4 (bullseye).
Itā€™s connecting to MQTT, I can publish, itā€™s connecting to openHAB, itā€™s updating the HABApp_Ping itemā€¦ It adds the rule from my python file! So far so good ā€“ looking great, in fact.

But out of all the possible things I could be having problems withā€¦

How is it that the First rule, the one that is designed to print ā€œThat was easyā€, doesnā€™t print anything?? :slight_smile:

I started docker with sudo docker-compose up, without the -d flag, so that I can see the console output. I remember habAPP had some output that way when I first started it ā€¦ but no. no output there now.
then tail -f HABApp.log. Lots of output there. The rule gets loaded. But no print output!

I figured, maybe I can print to the log like in OH2 with jsr223 and jython?
Googled that, found this page in the habapp manual and tried it. log.debug("that was not that easy") ā€” no output.

Finally, with log.warning("that wasn't easy at all" or log.error("really???") I do get output. In the console thatā€™s stuck running docker-compose without the -d flag. Still nothing in the log.

So, at least I know the rules are running.
I also tried mqtt publishing, and that worked too!

So the only thing Iā€™m missing is printing.

Surely there must be a way? What way do you recommend, @Spaceman_Spiff?

In my own projects, whether a gui-app or a service in windows or an embedded project on an ESP8266 or ESP32, I always have a telnet server i can print to and connect a console too. This works beautifully and it might be a good thing for habAPP to have, if it doesnā€™t already.

MQTT subscriptionsā€¦
subscribe(self, topic: str[, qos: int = None]) ā†’ int

ā€œSubscribe to a MQTT topic. Subscriptions will be active until next disconnect. For persistent subscriptions use the configuration fileā€

Uh, thatā€™s quite a limitation actually. I use MQTT a lot. It would be extremely difficult and error-prone to keep track of the MQTT subscriptions if every single one has to get its own line in the config file.

Or, am I missing something?
The example mqtt rule doesnā€™t use subscribe, it seems to simply add a listen event, thus it looks like itā€™s relying on the ā€˜#ā€™ subscription in the default config.yml fileā€¦ which is fine by me in that case, so maybe Iā€™m worrying for nothing?

But, if that is the case, then I think ā€œSubscriptions will be active until next disconnect. For persistent subscriptions use the configuration fileā€ is misleading and could be written more clearly. :slight_smile:


I keep getting these warnings in the habapp log:

[2021-12-11 01:23:08,458] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevator-chandelier-dev but item does not exist!
[2021-12-11 01:23:30,433] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevatorcontrol but item does not exist!
[2021-12-11 01:23:38,557] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevator-chandelier-dev but item does not exist!
[2021-12-11 01:24:00,532] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevatorcontrol but item does not exist!
[2021-12-11 01:24:08,655] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevator-chandelier-dev but item does not exist!
[2021-12-11 01:24:30,631] [HABApp.openhab.connection]  WARNING | Received ThingStatusInfoEvent for mqtt:homie300:main:elevatorcontrol but item does not exist!

Any idea what they are? These are happening continuously, the Things are mine but there is no update in status as far as I know. I donā€™t see any corresponding status changes in the openhab main or event logs.


Other than that:

Self-made Homie Device ā†’ OH3 Thing ā†’ Channel mapped to item ā†’ HABapp listen_event/ValueUpdateEvent, log warning(ā€˜update {}ā€™.format(event.value))

ā€¦WORKS. Okay, that was easy. Very, very nice work @Spaceman_Spiff, I donā€™t remember JSR223/Jython being this easy to get going! :slight_smile:

Hello,
i have the same problem as described in posting 426.
I followed the instructions, but Iā€™m not able to start HabApp.

sudo python3 -m pip install --upgrade pip
Looking in indexes: Simple index, piwheels - Simple index
Requirement already satisfied: pip in /usr/local/lib/python3.7/dist-packages (21.3.1)

But if i want do install habapp:

Command ā€œpython setup.py egg_infoā€ failed with error code 1 in /tmp/pip-install-crbnvgbf/pendulum/

Im not a pro but I have to work with habapp for a project.
Maybe you can find the mistake.

Itā€™s an issue with the installation of pendulum. Could you try this workaround of the workaround in the next post?

This works if you start HABApp from the console or locally on your main machine. The docker container probably doesnā€™t catch the process output.
I just log everything to different files with separate loggers.

You have to setup an output file for your logger.
I modified the docs so it should be more clear now.

You are worrying for nothing! :wink:
Just use the mqtt wildcards or ā€˜#ā€™ if you donā€™t have thousands of events per sec and you will be fine.

The functions are there to dynamically change the subscriptions during rule execution. For static subscription the config file should be used.
If you have a better wording Iā€™ll gladly use it. Any improvement of the docs is very much appreciated. Just make a suggestion and Iā€™ll add it to the docs.

Probably things that have been added after you started HABApp. Currently openhab does not provide an event when a thing has been added/changed and I havenā€™t created a workaround yet.
After a restart of HABApp it should be gone.

1 Like

Hello,
thank you for your quick help.
But the workaround, doesnt work :wink:

ERROR: Failed building wheel for pendulum
Failed to build pendulum
ERROR: Could not build wheels for pendulum, which is required to install pyproject.toml-based projects

Is it possible that pendulum causes this problem?

(habapp) openhabian@openhabian:/opt $ sudo systemctl start habapp.service
Failed to start habapp.service: Unit habapp.service not found.

Thanks a whole bunch!

Clear! Works, too.

That is the best kind of worry, way less stressful than when itā€™s justified :smiley:

Sure! How about this:

Please note that subscriptions made this way are volatile, and will only remain until the next disconnect. HABApp is already subscribed to ā€˜#ā€™ (everything) by default, so rather than making a temporary subscription, you can get any topics you need simply by using listen_event, as described in the below Example MQTT rule.

Ah! Also clear.

Thanks again!

Yes - can we please continue in the topic that I linked.
Can you there please post everything you have done and the output (properly formatted with code fences).

Itā€™ll be included in the next release

1 Like

May I just take a moment to mention how nice it is that in HABApp, when an event callback function is called, whether in response to Update or Change, and whether you check event.value or item.get_value()ā€¦ the value you get in each case is the new value. None of the aforementioned combination of conditions ever returns the previous, un-updated valueā€¦ meaning simple script development is not booby-trapped with race conditions.

When youā€™re accustomed to OH2 JSR223 Jython scripting, you learn to appreciate the little things, and not take anything for granted.

Thank you, @Spaceman_Spiff.

3 Likes

You can also check item.value or just if item == compare_value.
item.get_value() is only there if you want to specify a default in case the item.value is None and normally not needed.

You should also check out the MultiModeItem. I makes writing overlapping states really easy and they are a very powerful tool for automation!

1 Like

Thanks for the tip! I looked at MultiModeItem now, itā€™s going to take a while to wrap my head around it, but it seems like it can avoid having to use proxy items for certain things. Could be useful.

Also, Iā€™m using PyCharm as you suggested in the tutorial. Great suggestion ā€“ I just installed it, and syntax highlighting and autocomplete just works automatically. That makes an incredible difference for a novice Python programmer.

Iā€™ve written my first script! Itā€™s working perfectly, but itā€™s ugly ā€“ Iā€™ve written it as I would have in C++, not taking advantage of anything Python since I donā€™t know it (yet).

One common problem in home automation is asymmetrical delays.

That is:
While X is 1, do A
While X is 0, do B, and 10 seconds after that do C, as long as X didnā€™t become 1 again within that time.

I did that the arduino wayā€¦ that is, I literally implemented a millis function and used timestamps:

def millis():
	return int(time.monotonic_ns() / 1000000)

def __init__(self):
	self.chandelier_level = 0
	self.chandelier_on = 0
	self.chandelier_on_timeout = 30000
	self.chandelier_on_millis = millis() - 9999999
	self.chandelier_power = -1

def periodicUpdate(self):
	desired_on = 0
	if self.chandelier_level > 0:
		desired_on = 1

	if desired_on:
		self.chandelier_on = 1
		self.chandelier_on_millis = millis()
	elif millis() - self.chandelier_on_millis > self.chandelier_on_timeout:
		self.chandelier_on = 0


	if self.chandelier_power != self.chandelier_on:
		self.chandelier_power = self.chandelier_on
		self.ctrl_mcu5_elchand.oh_send_command("ON" if self.chandelier_power else "OFF")

Imagine the chandelier controller is WiFi controlled, and this power to the controller is itself connected to a WiFi relay with lots of channels that control multiple things. This saves a lot of power, compared to having everything in the house on active standby, because this way only the multichannel WiFi relay stays on.

self.chandelier_level is the desired brightness of the chandelier.

When chandelier_level is greater than zero, then obviously the power to the chandelier controller needs to be on, and we need to tell it the level to be at.

When chandelier_level becomes zero again, we tell the chandelier controller to fade out, and then we give it plenty of time to fade out before we actually cut its power.

It works fine this way, but this seems like a lot of code for what is a common home automation problem!
@Spaceman_Spiff, since youā€™re a native Python programmer, Iā€™ll bet you know a much more efficient way to accomplish the same thing, making use of HABApp and Python magic? :slight_smile:


I also have a question regarding HABApp logging. With the default settings itā€™s logging every message on my MQTT server. I will change the level to WARNING of course, but:

  • It doesnā€™t seem to obey the size restriction. logging.yml specifies maxBytes: 1_048_576 and yet the events.log grows to a gigabyte before it rolls over.
  • Itā€™s nice to have detailed logging but not if it kills my SSD ā€“ is there an easy way to keep a log ONLY in RAM?

That blows my mind a little bit. As a C++ programmer, I assumed item to be a handle or pointer.
Shouldnā€™t item == compare_value always return false since theyā€™re different types? What sorcery is this? :slight_smile: