spacemanspiff2007 / HABApp

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

Clean approach to rule libraries #455

Open SPF79 opened 1 week ago

SPF79 commented 1 week ago

Heya,

I've been using HABApp very intensively for a few years now and completely replaced all other OpenHAB rule configurations. First of all, many thanks for all the good work.

But second of all, I'm a little puzzled in regards to how to organise my ever growing rule library and utilise it correctly.

To give a brief hint of what my issue here is: I'm using Milight devices extensively in my home automation. I'm hitch-hiking their native lightweight protocol with MilightHubs (node MCU's) to provide wireless interfaces for almost everything in conjunction with RaspberryMatic and other Pi's for custom e.g. relay operations as well as MQTT as the obvious standard middle-ware.

The problem I'm facing, is I now developed a highly-sophisticated low-level python library for Milight based on your HABApp rule system and would really like to employ it as a common dependency for further rule development, but I have no idea how to approach it. You know, having a milight rule module, that I can e.g. import when writing new rules (and as the cream on top, having JetBrains' IntelliJ showing me proper inspection results, so I can ditch more trial & error).

I'm not sure whether this is the right scenery for this request, but I would really like you to give me a hint/setup that is most viable to employ with in-depth Python programming when using your framework.

All the best,

Seb

spacemanspiff2007 commented 1 week ago

As always it depends. If your work is relatively stable you can create a module in the lib folder (see docs) and import that module in your rule files. This will also provide IDE hints as expected. However changes in the module will not be picked up during runtime so you have to restart HABApp every time you change something in the module. The second way is to use self.get_rule to access a rule you might have created for a device. See docs how to make that work with type hints. The upside is that this way you can dynamically reload your library without having to restart HABApp. It's a little bit more verbose when making the calls so whether it's feasible depends on your implementation. The third way is to just use HABApp internal items. Since they can hold any data structure it's possible to e.g. pass dataclasses around. The pro is that you'll have a nice interface and proper decoupling, however if you want to work with e.g. return values of functions calls it's not very nice. This works also with type hints (same as the second option). For option 2 and 3 it's also possible to define the source files as a dependency and I recommend doing so that the files will be loaded in correct order.

I mostly use the HABApp internal items and for pushover notifications I use the get rules. The internal items make nice processing pipelines, because I can trigger on changes and on updates. E.g. I have a rule which loads the weather forecast and posts the whole forecast into one item. Then I have another rule in another file which on an update of that item does some logic depending on the forecast.

Without knowing the details I can't recommend you which way to go but these are your options. However I recommend you play a little bit with option 3 or 2 and only if that's not a good fit I'd try out option 1.

SPF79 commented 1 week ago

Hi again,

cheers, mate. That should be it for now and I'll do my research on options 2 and 3. Maybe I find something that works well for my setup.

If you should ever need anything (and be it a beta tester), give me a holler. I'm a man of duty and honour and you, my friend, deserve both when it comes to me.

All the best and hang in there,

Seb

Am Fr., 27. Sept. 2024 um 14:52 Uhr schrieb spacemanspiff2007 < @.***>:

As always it depends. If your work is relatively stable you can create a module in the lib folder (see docs) and import that module in your rule files. This will also provide IDE hints as expected. However changes in the module will not be picked up during runtime so you have to restart HABApp every time you change something in the module. The second way is to use self.get_rule to access a rule you might have created for a device. See docs how to make that work with type hints. The upside is that this way you can dynamically reload your library without having to restart HABApp. It's a little bit more verbose when making the calls so whether it's feasible depends on your implementation. The third way is to just use HABApp internal items. Since they can hold any data structure it's possible to e.g. pass dataclasses around. The pro is that you'll have a nice interface and proper decoupling, however if you want to work with e.g. return values of functions calls it's not very nice. This works also with type hints (same as the second option). For option 2 and 3 it's also possible to define the source files as a dependency and I recommend doing so that the files will be loaded in correct order.

I mostly use the HABApp internal items and for pushover notifications I use the get rules. The internal items make nice processing pipelines, because I can trigger on changes and on updates. E.g. I have a rule which loads the weather forecast and posts the whole forecast into one item. Then I have another rule in another file which on an update of that item does some logic depending on the forecast.

Without knowing the details I can't recommend you which way to go but these are your options. However I recommend you play a little bit with option 3 or 2 and only if that's not a good fit I'd try out option 1.

— Reply to this email directly, view it on GitHub https://github.com/spacemanspiff2007/HABApp/issues/455#issuecomment-2379213067, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJOVLWDI6QHGSUTDKR62ZCLZYVIKHAVCNFSM6AAAAABO7BKTL6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNZZGIYTGMBWG4 . You are receiving this because you authored the thread.Message ID: @.***>

SPF79 commented 6 days ago

Hi again,

I have another (minor) problem, that's haunting me and I thought I clear it up right now, as I triggered you already and then leave you to it:

I developed a party gimmick, fetching the album art of the currently playing Spotify song, save it to disc, load it with pillow and grab the most dominant colours therein with colorthief to provide HSB/RGB values for MIlight mood lighting whenever the song changes. It looks great and is fun, but I'm facing bytes assertion errors (that I didn't really handle yet, because I was reverting a lot on GIT to keep my important stuff running - so disabled for now).

Now for the tiny issue: When this assertion issue happens HABApp slams the frickin' whole image at that time into the log! Which means my /var/log partition is full in the matter of a day. My question is: How can I stop this (omit the content of this specific item for the log) and have some peace when tinkering instead of everything shutting down because of "No space left on device"?

Best,

Seb

EDIT: Horrible English, my apologies.

EDIT 2: I'm sorry to have mixed things up in this issue (I thought, I'd go pragmatic), but I've no intention to stain your project with my (lazy) rubbish. If it's not to much work for you, please move it to a new one, titled e.g. "Omitting very large item content strings in HABApp logs" or similar and please keep in mind, that I deem my private time more than worthy to contribute. 'Nuff said, but I'm down to "pretend" that we are professionals here. 'Tis more complex and exciting, than what I've got to do at work anyway (naval warfare engineering) and that means a lot. ;-)

Am Fr., 27. Sept. 2024 um 14:52 Uhr schrieb spacemanspiff2007 < @.***>:

As always it depends. If your work is relatively stable you can create a module in the lib folder (see docs) and import that module in your rule files. This will also provide IDE hints as expected. However changes in the module will not be picked up during runtime so you have to restart HABApp every time you change something in the module. The second way is to use self.get_rule to access a rule you might have created for a device. See docs how to make that work with type hints. The upside is that this way you can dynamically reload your library without having to restart HABApp. It's a little bit more verbose when making the calls so whether it's feasible depends on your implementation. The third way is to just use HABApp internal items. Since they can hold any data structure it's possible to e.g. pass dataclasses around. The pro is that you'll have a nice interface and proper decoupling, however if you want to work with e.g. return values of functions calls it's not very nice. This works also with type hints (same as the second option). For option 2 and 3 it's also possible to define the source files as a dependency and I recommend doing so that the files will be loaded in correct order.

I mostly use the HABApp internal items and for pushover notifications I use the get rules. The internal items make nice processing pipelines, because I can trigger on changes and on updates. E.g. I have a rule which loads the weather forecast and posts the whole forecast into one item. Then I have another rule in another file which on an update of that item does some logic depending on the forecast.

Without knowing the details I can't recommend you which way to go but these are your options. However I recommend you play a little bit with option 3 or 2 and only if that's not a good fit I'd try out option 1.

— Reply to this email directly, view it on GitHub https://github.com/spacemanspiff2007/HABApp/issues/455#issuecomment-2379213067, or unsubscribe https://github.com/notifications/unsubscribe-auth/AJOVLWDI6QHGSUTDKR62ZCLZYVIKHAVCNFSM6AAAAABO7BKTL6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNZZGIYTGMBWG4 . You are receiving this because you authored the thread.Message ID: @.***>

spacemanspiff2007 commented 4 days ago

Sounds like a nice feature. You could write a custom logging filter which prevents lines where this name occurs to be printed. The filter can be loaded during startup via the HABAppUser module. However the more simple solution would be to just remove the assertion or handle it gracefully. Do the check and if it fails emit a small log message and return from the function. Or wrap the whole function, catch the AssertionError and log only the error.