Need advice on making my OH3 rules more flexible

Tags: #<Tag:0x00007f433707c598> #<Tag:0x00007f433707c4d0> #<Tag:0x00007f433707c408>
  • Platform information:
    • Hardware: synology NAS - docker
    • openHAB version: 3.0.1

Hi all,

I am new to OH, started with OH3 for mainly automating Swimming pool filtration and heating making use of solar energy. To optimise the usage of my solar production I want to heat my pool when I produce more energy than I consume.
I read electricity production or consumption with MQTT, and use Shelly devices to switch my pool pump and heat pump on or off, based on the solar production.
I defined all items and rules using the UI interface, and persistence is writing data to mariadb via jdbc.
As front end I have HabPanel
So far my rules are very simple and work as expected:

  • when solar production is above 1 kW I turn on the pool pump
  • when solar production is above 2 kW I turn on heat pump
  • when solar production is zero switch off pool pump and heat pump
    The first rule looks like this, others are similar:
  - id: "1"
      itemName: GenericMQTTThing_ElectricityCurrentlyReturned
      previousState: ""
    type: core.ItemStateChangeTrigger
  - inputs: {}
    id: "3"
      itemName: GenericMQTTThing_ElectricityCurrentlyReturned
      state: "1.0"
      operator: ">"
    type: core.ItemStateCondition
  - inputs: {}
    id: "2"
      itemName: ShellySwitchPoolPumpPower
      command: ON
    type: core.ItemCommandAction

The 2 pumps together use around 3 kW, heat pump requires working pool pump, so I split them in 2 rules, since pool pump must run a minimal amount of time per day, also when it is cloudy, heating is ideally only when there is enough solar energy production.

Now I would like to add a couple of improvements, can someone give me some recommendations on how to achieve this?

  1. I want to calculate the duration the switch was on during the day. In the persistence database and using the analyze button of the item I see each ON and OFF command and their timestamp, the function sumSince should give me that duration. I want to use this duration in the condition for switching the pump off: switch pump off if solar production is zero AND duration is less than 8 hours, or even better : if duration is less than a variable duration, which is set by the water temperature, e.g. if temperature is above 30°C then 12 hours, if between 25 and 30°C then 10 hours else 8 hours. Temperature is also available on one of my items from channel shelly:shelly1:ShellyThermometer:sensors#temperature1.

  2. I want to have a button or similar on my HabPanel to override the normal rules, to “boost” the heating. In the rules UI I see that I can make a rule to disable another rule, so if I disable my Switch Off rule the pump and heating remain on, until I select to go back to normal mode. What kind of item/widget do I need for this?

  3. I also would like to have some hysteresis like described in Use excess Photovoltaics Production intelligently (Building a time based “hysteresis”). Will that be possible in the UI based rule editor? Or do I need to switch to rules file of other languages?

Thanks in advance,

Hi Luc, welcome to the forums. Let’s work backwards through these questions.

Depending on exactly how you want to integrate this, you will find that hysteresis has been built-in to the profiles that you can apply to an item when you link it to a channel. Read up about profiles in the docs here. So, no you would not have to move from the strictly UI-based rule creation…for this part. But the most important thing to keep in mind that requiring slightly more advanced scripting (i.e., DSL, jython, javascript, etc.) does not mean you have to immediately jump to .rules files. You can use the run script option under the rules add actions to have your UI rule and text scripting. Because you can have multiple actions in a UI rule, you can even combine these it you really want to and have some simple scripting in addition to a basic item command action.

One of the keys to getting the most out of OH is understanding that items don’t have to be linked to a channel. In fact as your system grows more sophisticated you’ll probably find that these proxy items approach in number the linked items that you have. So if you want to be able to be able to turn some part of your system on or off that sure sounds like a switch item. Again depending on other details you might not even have to go so far as to give this switch it’s own rule that deactivates some secondary rule, you can just include it’s state in the But Only If conditions. “Run the heating rule, but only if heating override switch is off.”

Now you’ve run into the territory where you will have to start scripting (again, this can be done in the UI rules editor, this does not mean you have to go all the way to .rules files if you don’t want to). The simple rules creation UI doesn’t have a section for actions defined by services or bindings and the sumSince is one of the persistence extension functions.

I’m also not convinced that sumSince is going to give you the duration that you are expecting as it is not time-weighted it is simply base on the number of datapoints stored by the persistence rule. If your rule is just to store the value every minute, then you would get what you are looking for, but most persistence rules are every minute and on every change so you start to get summed values that not precisely the same as time ON. You’re probably better off using averageSince because that is time weighted. Then all you have to do is multiply the resultant average value by the appropriate conversion factor to get a fairly precise usage value.

Hi Justin,

Thanks for this clear and quick feedback.

Point 2 Is done now through a item “boost” of type switch.
Can I assume the 2 conditions in my rule are used with AND operator?

Point 1, calculation of total hours switch was on today, I added a rules file that is based on Measuring time of switch state, which stores pumptime in my persistence DB, the only issue I see is that the the value of pumptime is not always increasing, and does not give the expected result. In the database I created a query on table item0055 (my pump switch):

select dt, sum(dur_sec)/60 as min, sum(dur_sec)/60/60 as hr from (select date(time) as dt, time, value, timestampdiff(second,prev_time,time) as dur_sec from ( SELECT time, lag(time) over (order by time) as prev_time, value from item0055 WHERE 1 ) t1 where value=‘OFF’ /* and DATE(SYSDATE()) = date(time) */ ORDER BY time DESC) t2 GROUP by dt

Of course the start value was not correct as I created the rule in the afternoon, I will verify tomorrow after the midnight reset of value pumptime.

For point 3, the “hysteresis” I want to use, is time related. It is more about not switching off in case the ON status was only for a very short time. I guess this could be achieved either by using a timer, or verify the average value of energy production over the last x minutes.

Best regards,

This is a very awkward way of going about the problem. Sometimes in OH such awkward solutions are the best available option (and it’s possible that 5 years ago when that thread was active, that was the best option), but now all of that can be replaced with just a couple lines of script in whichever rule you need the using the averageSince function.

Because OnOff type in OH can be treated as 1 and 0 and averageSince is a time-weighted function, averageSince of a switch item returns the exact percentage of time over the interval of interest that the item has been in the ON state (if it were on the entire time the average would be 1, if off the entire time the average would be 0, if on for half the time the average would be .5, etc.).

For example the following js script:

var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.JSTester');
var PersistenceExtensions = Java.type("org.openhab.core.persistence.extensions.PersistenceExtensions");
var ZonedDateTime = Java.type("java.time.ZonedDateTime");"Switch_MasterBedroomFanLight_OnOff"),;

Logs a result of 0.07431679855178091. So my bedroom light has been on for approximately 7% of the last day. If I want that value in hours I just multiply by 24 (approximately 1.8 hours) or for minutes by 1440 (approximately 107 minutes).

One additional computation would be required if you want the amount of time since a fixed point in time, say midnight, just because your conversion factors are then dynamic (if you want the value in minutes, you have to know how many minutes since midnight).

If you’re using RulesDSL, you don’t even need all the extra imports, most of that is done for you, and just one line accomplishes the same thing:

logInfo("DSL Tester",Switch_MasterBedroomFanLight_OnOff.averageSince(now.minusDays(1)).toString)

Yes, I believe that’s correct.