No more OH 1.x bindings!

Tags: #<Tag:0x00007f617e06e500>

No, I’m not calling for the elimination of OH 1.x bindings. Don’t worry.

But, I’ve set myself a little challenge. I wanted to see how hard it would be to go all in on managing everything through the REST API. I am not advocating this but it’s been a good learning experience and I figured I would share my lessons learned.

No more config files! So far I’ve:

  • migrated all my Things to JSONDB a long time ago
  • migrated all my Rules to JSR223 as a first step to migrating them to NGRE
  • Sitemaps, Persistence, and Transformations are not yet possible to manage through the REST API

Therefore the last two things to migrate are Items and my Rules. I’m waiting on some more improvements to the NGRE plus I’m still learning this JSR223 stuff so I’m focusing on my Items.

First an aside. Note how I say I’m using the REST API, not necessarily PaperUI. A lot of the problems with PaperUI can be addressed by going straight to the REST API docs.

I’ve got so many MQTT Items, it’s too much work to migrate to MQTT 2.5!

If you only use PaperUI then yes, it is a real pain to click together a bunch of things. It can take several minutes to build just one Thing and if you have a dozen similar devices that will lead to hours of tedious clicking. But PaperUI isn’t the only option!

  1. Create and test an example Thing using PaperUI. You will only have to do this once so it’s not so bad.
  2. Use the get Thing by uid REST endpoint to pull the JSON for the Thing you just created. Copy that into Notepad++, VSCode, or your text editor of choice.
  3. Edit the JSON replacing the fields with the right data for a new Thing. For example, change the ID, topics, and that sort of stuff.
  4. Compare that JSON with the “Model Schema” shown in the Creates a new Thing and adds it to the registry REST end point. The JSON you pulled in step 2 will have a few additional fields you will want to remove.
  5. Once you are happy with the JSON, paste it into the new Thing end point and submit. You’ve now created a new Thing. Repeat for your remaining Things.

What about openHAB 1.x bindings!

This was the big issue holding me back from migrating my Item to the JSONDB. I will have to eliminate any OH 1.x bindings from my system. (see note below)

Luckily, I was only using four 1.x bindings:

  • MQTT for the event bus
  • Expire
  • Network UPS Tool
  • HTTP

I’m aware that replacements for some or all of these are done or in work, but I didn’t want to wait.

NOTE: I’m actually not 100% certain that’s entirely true. It appears that OH 1.x binding configs show up as Item metadata so it should be possible to set that metadata through the REST API. But the REST API is really primitive. I decided against trying it.

MQTT Event bus

The MQTT 2.5 binding doesn’t have the event bus built in. But luckily it is super easy to recreate the MQTT event bus with just about a dozen lines of Rules code and a Channel on the Broker Thing. See MQTT 2.5 Event Bus.

But that’s Rules DSL code and I’m moving off of that too so I created a JSR223 version and I made it generic so users of JSR223 Rules can just import the rule, set a variable in configuration.py and add Items you want to share to a Group. See https://github.com/openhab-scripters/openhab-helper-libraries/pull/257

This is actually one reason I’m migrating to JSR223 and eventually to NGRE. Rather than copy and paste from a topic on the forum here like above, which is required for Rules DSL, you can just drop the code into your config unchanged (JSR223) and eventually download and configure the Rule like you do with Bindings now (NGRE).

I updated my two openHAB instances with this code, configured my Group and Items and MQTT Things and was able to remove the MQTT1 binding. For my other MQTT Items, I used the steps described above to create most of my Things.

Expire

As I’ve explored the REST API I discovered that OH 1.x bindings config show up as Item metadata. I can access Item metadata from JSR223 Rules. So I decided to see if I could create a drop in replacement for the Expire binding with a JSR223 script. The answer is yes, yes I can. JSR223 Jython Replacement for Expire Binding. It has a couple of limitations (e.g. you have to reload the script every time you change any Item’s expire config) but it handles StringItems a little better.

You can just drop this script into the right folder on your config, uninstall Expire1 and you are good to go.

Network UPS Tool

This one I kind of cheated. If I ran OH installed I probably would have written a rule using the exec binding and parsed the result in a Rule to update my NUT Items. But I run in Docker so I created a configuration on https://github.com/rkoshak/sensorReporter to run the upsc and publish the result to an MQTT topic. Then I created an MQTT Generic Thing to subscribe to that topic and used the REGEX transformation to extract the fields I care about. For example, to get the charge I use REGEX:.*battery.charge: ([\d]{1,3}).* and to get the load I use REGEX:.*ups.load: (\d+).*.

It took me about 20 minutes to set up. No Rules required in my case.

HTTP

I only had one minor use case left where I was using the HTTP binding, polling Nightscout for my wife’s latest CGM readings. So I just moved that to a simple Rule and use the sendHttpGetRequest Action.

from core.rules import rule
from core.triggers import when
from core.actions import Transformation
from core.actions import HTTP

@rule("Poll Nightscout",
      description="Polls the Nightscout API for the latest reading JSON",
      tags=["nightscout"])
@when("Time cron 5 */1 * * * ? *")
def poll_ns(event):
    results = HTTP.sendHttpGetRequest(
        "http://fenrir.koshak.net/api/v1/entries/current.json")
    poll_ns.log.debug("Nightscout: {}".format(results))

    lr_time = "UNDEF"
    lr      = "UNDEF"
    trend   = "UNDEF"

    if results != "[ ]":
        lr_time = Transformation.transform("JSONPATH", "$[0].dateString",
                                           results)
        lr = Transformation.transform("JSONPATH", "[0].sgv", results)
        trend = Transformation.transform("JSONPATH", "[0].direction", results)

    events.postUpdate("NS_LastReading_Time", lr_time)
    events.postUpdate("NS_LastReading", lr)
    events.postUpdate("NS_Trend", trend)

Given what I learned from the Expire binding drop in configuration, I could probably come up with a drop in replacement for the HTTP binding as well, but I know there is an HTTP 2 binding in work and don’t think it would be worth the effort right now.

Lessons Learned so far

  • I’m really getting excited about the prospects of Rule libraries and Rule Templates. A lot of the examples and tutorials that are on this forum will become something you can just install and use, no coding required.

  • Since moving to JSR223 Rules which have a built in delay to prevent loading before Items and restoreOnStartup have done their job I’ve not experienced any startup errors. I can’t say that OH starts up any faster, but I expect moving to NGRE will improve the loading speed some.

  • Some bindings can easily be replaced by Rules, particularly in simple use cases.

  • This exercise has been a great learning opportunity. I don’t recommend taking the same path for practical reasons, but if you want to learn some new stuff with OH I highly recommend making similar challenges for yourself. Keep a backup and go break things!

4 Likes

As a stop-gap you could do a periodic reload every few minutes.

1 Like

I’m looking to do something similar. I have a nightscout site setup for my wife’s CGM readings. What do you have setup to do with the readings? It looks like it does a postUpdate to events with the basic info (time, reading, and trend). Is there a view on a dashboard where you see those event updates?

She uses xDrip on her Pixel 3XL with a Dexcom G6 as the collector which feeds into Nightscout directly. Then the OH Rule above polls Nightscout’s API for the most recent reading, parses the JSON returned, and updates a few Items with the values. In this case, the time of the last reading (NS_LastReading_Time), the last reading (NS_LastReading), and the trend (NS_Trend).

I’ve self hosted Nightscout on my LAN and we gain access to it through VPN.

I mainly coded this so I could incorporate the reading/trend with the automation (e.g. turn a light red if there is a low or trending double arrows down) but haven’t really done anything with them. When she wants to see the readings it’s on her watch or on her phone. When I need to see the readings I can bring up Nightscout directly or set up xDrip on my phone as a follower. I have these Items on my sitemap but I don’t actually use them for anything there. They are mainly there for testing purposes to verify they are being updated.

See NightScout openHAB Integration for more details on the Nightscout integration.

@rlkoshak You might be interested in :smile: :

you’re good at click baiting too :rofl:

Sorry for the OT :grimacing:
It’s a long post I will have a read this evening, anyway thanks for your effort and sharing!

Indeed. Thanks for bringing it to my attention! I’ll definitely follow that thread and test out the work in progress.