Having recently migrated quite a bit of JSR223 Jython2 code to HABapp, I’d like to jotted down some notes on my experience, and hopefully create a PR to put this in the HABApp doc. @Spaceman_Spiff recently added some notes on what HABApp is. I’d like to focus on the pros and cons.
First thing to note is that both these frameworks are based on Python (albeit different versions) and both target superusers (i.e. software developers), so in that sense there are more in common than differences. Both also have maintainer(s) that are very active on the forum.
Pros of HABApp:
Based on Python 3, and as such allows full usage of Python modules via
In addition, it is easier to leverage a proper IDE such as PyCharm for development. Having previously coded JSR223 code in vim on the Rasperry PI, moving to PyCharm was a big upgrade. The IDE catches many errors that I wouldn’t detect until the code path is executed at run time.
PyCharm also allows running unit tests directly within the IDE without the need to have HABApp running (more on unit testing below).
JSR223 code will remain at Python 2.7 version as there is no development effort to bring it up to Python 3.
With JSR223, it is also possible to install additional 2.7 modules via pip but it is more difficult as you have to resolve the dependencies yourselves. See Michael’s comment below.
Much better turn-around time:
This is achieved via multiple factors:
- The use of CPython and Python3.
- The HABApp process is much lighter weight than OpenHab with all its bindings, and scripting environments.
- The easier use of IDE such as PyCharm.
In JSR223, if we make a change deep in a referenced module, sometimes the only way to ensure that OH loads the change correctly is to restart OH, and that takes very long time. With HABApp, you can just restart it in 2 or 3 seconds.
Provide additional deployment flexibility:
HABApp interacts with OH via its REST interface. The HABApp process can be run as a separate process on the same machine that hosts OH, or it could be deployed on a totally different machine and / or different network.
The usage of REST interface has drawback and I will touch on them in the cons section.
More resilient toward changes in the core OH:
As the rules and modules are now in a different framework, upgrading OH will be less painful and less fragile. OH will mostly be used for the item definitions and the bindings. The chance of OH and HABapp change majorly at the same time is low.
This strength also comes with a cons.
Flexibility in the helper libraries:
When interacting with external devices or services, HABApp code has the choice of leverage the OH bindings or the devices/services’ Python API directly (when available).
Proper error messages.
If one of your rule throws an exception in HABApp there is enough information in the log to pinpoint the issue.
The core framework is flexible enough to allow decoupling from OH when necessary.
HABapp has a set of abstractions that map to various OH types. These can be remote and link to OH items or they can be local items that are visible within HABapp only. In the majority of cases, we work with remotely linked items, but local items are very useful in certain scenarios such as data sharing between rules and unit testings. JSR223 allows data sharing via injection into the runtime context. But a unified data types in HABapp provides much better emulation of the runtime in the context of unit testing. For example, you can write an unit test to simulate certain condition in the home such a motion sensor triggered and verify that the rule behaves correctly. And the unit tests can be run independently without the need of OH and HABapp processes.
Now here are the cons:
- As an independent process, HABapp adds more complexity to the pipeline. We already have OpenHab, mqtt, and many other devices/sensors and services.
- While leveraging the official OH REST API, in a sense HABApp still makes the OH eco system more fragmented dues to itself being another development choice.
- The REST API doesn’t expose everything. Notably, actions are not accessible via REST API. This can be worked around via usage of bridging items and complement JSR223 rules, but they are not out of the box solutions nonetheless.
- The REST API has additional latency. In the majority of cases, it doesn’t matter at all. One area that is somewhat noticeable is light management; i.e. turning on the light when a motion sensor is triggered. I do notice slight additional latency, but it is still acceptable.
- The REST API is hidden from the user and as such receives less attention than the JSR223 engine. Being the official Python scripting environment in OH, JSR223 also has a larger user base and it is easier to find previous information on the forum.
Given the pros and cons above, IMO, HABapp is a very good contender. I am migrating all my code over to HABapp. Surprisingly, the changes needed are very minimal. The largest change for me is the naming convention. I was mainly using Java naming convention, and PyCharm flaged a lot of warnings. As both HABapp and JSR223 continue to improve, here is my recommendation on how to approach rule writing:
- Push as much code into modules as possible. Besides encourage reusability, it also allows abstracting from the framework.
- Provide an abstract layer to avoid direct dependency on the framework. For example, for HABApp item, checking if a switch is on is done via
item.getState() == OnOffType.ON; for JSR223, it is
item.is_on(). To give your code more flexibility, you can have a core module checking the state for you such as
def is_in_on_state(item): .... The same thing applies to the other areas such as the event dispatcher, the setting of item states and so on.
Here is my original JSR code: openhab-rules/legacy-jython-code at master · yfaway/openhab-rules · GitHub.
And here is the migrated code (on going): zone-apis/zone_apis/aaa_modules at master · yfaway/zone-apis · GitHub.