Permissions on the log files looked consistent, but I should have thought to apply that option. It should be step 1 in many troubleshooting situations…
There’s either a bug/limitation importing lib modules or I’m making a silly mistake.
I’ve a file habapp_utils.py in my lib folder which I import into my rules with “import habapp_utils” and “from habapp_utils import *”. This works fine, however any changes I make into habapp_utils.py aren’t reflected when I run my rules unless I first restart habapp.
Is it intentional, a bug, or am I doing something dumb?
As far as i understand. HabApp reconises your change, but the already loaded rules do not. There is a specific dependency option. With this option you could say reload my rule if file xyz changes.
@Dibbler42 While file properties are really nice they don’t apply here
@dan12345
It’s a library folder that gets imported on startup.
Currently there is no proper method in python to dynamically reload libraries, that’s why changes to the libraries don’t get picked up during runtime.
And to be fair most of the time this is not necessary:
HABApp can build rules dynamically based on parameter files and reload the rule files on parameter change (see the link from Thomas).
As a third option you can create HABApp internal items and use these to transfer data between rules/files.
Overlaying states and a device driver/logic model can be created with the MultiModeIItem
With these mechanisms creating libraries in the original sense of library is not necessary any more.
And when it makes sense it’s so static that restarts don’t matter
It’s interesting how different people have different approaches. I like building a big library with all the utility functions, and then having short simple rules files. But restarting when the library changes isn’t a hardship!
I used to try that too, but I changed that to create a rule class that does exactly one thing and I’m rather creating multiple instances of the rule than try working with a big library.
For example I now have six rules per rollershutter and they are combined through the multimode item.
If you like you can create a thread and I’ll have a look at your things and give you an example how I would have done it. If not and you’re happy restarting HABApp that’s fine with me, too!
Whatever suits you the best!
This is just a small release which brings some bugfixes and small features
Changelog:
Item and Thing loading from openHAB is more robust and disconnects now properly if openHAB is only partly ready
Renamed command line argument “-s” to “-wos” or “–wait_os_uptime”
Now waits until the system uptime is at least the specified value before starting HABApp
Renamed HABApp.openhab.exceptions to HABApp.openhab.errors
I just moved from OH 2.5 to OH 3.1, and it was made so much easier with having all my rules in HABApp! all my rules just worked after the upgrade. Thank you.
I do have a question about OH 3.1. I used to use the “System started” trigger (in my one and only DSL rule) to restart HABApp when OH stated up, and whenever I edited an .items file.
Now with OH3.1, this rule does not trigger when an .items file is edited, so the question is - what happens to HABApp if it’s running, and I edit an '.items file? do I need to manually restart HABApp for it to pick up the changes in the .items files? would touching all my rules achieve the same thing? (assuming I haven’t changed anything vital, say changing the label or group or adding an item).
Is there a way to set HABApp up so that changing any .items file trigger a rules reload in HABApp (or a restart if that is what is needed).
I have updated my CreateTimer class to use your new coundown timer. Here it is, if anyone else is interested (this is in my utils.py library).
Basically it makes the basic countdown timer into a persistent, cancellable timer with some added methods and properties.
This solves the problem that you can’t cancel() a countdown timer and then restart it, you have to recreate the countdown timer, if you cancel() it early.
import datetime, logging
from eascheduler.const import FAR_FUTURE
from threading import Lock
class createTimer(HABApp.Rule):
'''
General timer class
Restartable Timer, with cancel and reschedule functions
accepts float, int or datetime.timedelta as seconds parameter (not claiming that the timer is that accurate though)
based on countdown timer (new in Habapp V0.30)
'''
def __init__(self, seconds=0.0, exec_func=None, run=False, *args, **kwargs):
super().__init__()
self.log = logging.getLogger('MyRule.'+self.__class__.__name__)
self.t = seconds
self.exec_func = exec_func
self.args = args
self.kwargs = kwargs
self._task = self.run.countdown(self.t, self.exec_func, *args, **kwargs)
self.lock = Lock() #needed to prevent race condition
if run:
self.reset()
@property
def is_running(self):
return self.time_till_run != 0
@property
def time_till_run(self):
if self._task._next_run < FAR_FUTURE:
return (self._task.get_next_run() - datetime.datetime.now()).total_seconds()
return 0
def get_next_run(self):
return self._task.get_next_run()
def reset(self):
with self.lock:
self._task.reset()
def reschedule(self, seconds=0.0):
self.start(seconds)
def start(self, seconds=0.0, *args, **kwargs):
if args:
self.args = args
if kwargs:
self.kwargs = kwargs
if args or kwargs:
self.cancel()
self.countdown(seconds)
self.reset()
def countdown(self, seconds=0.0):
if seconds > 0:
self.t = seconds
with self.lock:
self._task.countdown(self.t)
def cancel(self, job=False):
with self.lock:
if self._task._parent is not None:
self._task.cancel()
if not job:
self._task = self.run.countdown(self.t, self.exec_func, *self.args, **self.kwargs)
You could simplify it more - reset(), reschedule() and start() are all basically the same thing, but I didn’t want to make too many changes to my original.
You use this as a drop in replacement for self.run.countdown()
Yep - the only difference to the built in counter is the is_running property and the time_till_run.
But you already had it in place before the new scheduler in HABApp so it’s valid to keep this around.
HABApp will pick up the changed item definitions automatically.
There is no need to restart HABApp if you change the *.items file.
You’ll see the corresponding events on the event bus.
Of course you have to reload the rules that used the existing items.
Any ideas on how to do that? I have 39 rules files, and it’s not easy to know which files uses which items - is there a way of triggering a reload on all rules when any .items file is changed?
Weird things happen if I don’t reload after editing .items files.
If its adding items or modifying e.g. a label (not the type/name) it is fine.
Things go south if you rename items or delete existing ones.
The only way I can think of is to take one or two items of every *.items file and listen to the ItemAddedEvent or the ItemRemovedEvent and then issue a FileLoadEvent with all rule names.
But it might be easier to just create a button in openhab and link a shell execute with a systemctl reload HABApp and just flick it once you’re done editing.