I’ve got a mini-split A/C system out in my workshop. It doesn’t have any smarts. There’s a remote with just the basic controls. I do have a heavy duty (40A) z-wave switch that is inline between the circuit breaker and the mini-split. Also have a separate z-wave temp, humidity, motion and light sensor in the shop.
Anyone have a rule that will fire off on a cron timer and function like a thermostat?
I’d like to define a rule that can fire off every 20 minutes and work through the following choices:
If the temp is above 72F and the switch is off then turn it on
If the temp is above 72F and the switch is on then do nothing
if the temp is below 72F and the switch is off then do nothing
if the temp is below 72F and the switch is on then turn it off
I’ve never set up a rule that has a nested conditional so I’m a bit unsure how to write that up. I could write up two separate rules and schedule them accordingly but I was hoping to figure out a way to have a single rule that will work through the logic.
HestiaPi has a whole thermostat coded in OH rules. That’s probably going to be a bit overkill though.
I do something similar for my dumb humidifiers though which might be a bit closer to what you need. See below.
Rule conditions are AND only. All the conditions must match for the rule to run. You’ll either need to split this into multiple rules or use a script action to convert it into one rule.
But instead of using a cron trigger, use changes to the current temperature and the temperature. That makes it more responsive.
Approaches you can use to implement this:
Use the hysteresis profile on the thermometer channel with a switch channel. Link the channel to a switch Item and set the hysteresis profile with something like 73 for the lower, 75 for the higher and invert to true. This switch will be ON when the AC should be on and off when it’s time to turn it off. The buffer zone (i.e. hysteresis) prevents flapping when the temp is bouncing above and below 75. You’ll have to hard code the thresholds though.
Take each of the conditions above and write them as a separate rule using the temperature as the trigger instead of cron. Each rule will be UI only so no coding required. You can use an item instead of hard coding the target temp. You will want to add hysteresis though for the off rules (i.e set to 73 or targetTemp-2 or the like).
Use Threshold Alert and Open Reminder [4.0.0.0;4.9.9.9]. This is the approach I use for my humidifiers. In this approach you will install the OHRT library (see link), and install the rule template from the marketplace. Add your thermometer item to a Group. Create a “Script” that will be called to actually turn on and off the AC. You can use Blockly. You’ll turn the AC on when isAlerting is true and off when it’s off. Instantiate the a rule based on the template with the following parameters (if not mentioned leave the parameter at the default).
triggering group: group created above
threshold state: 75
comparison operator: >=
hysteresis: 2
alert rule: script created above
end alert rule: script created above
The threshold alert rule will call your script when the temp reaches or exceeds 75 with isAlerting set to true. It will call it again with isAlerting set to false when it falls below 73.
You have a bunch of other options to play with as you need such as a do not disturb period, an amount of time the temp should be above 75 before you consider it to be alerting, etc.
To get the isAlerting flag in your script, use the “get from context” block in Blockly. In JS Scripting you can just use isAlerting directly. Rules DSL and simple UI rules are not supported and I don’t know how to get it in jRuby.
Code it yourself. Trigger a rule when the temperature changes. You’ve already ladies out the logic in your bullet points. Using Blockly create and if block and add else if blocks to it (click the cog icon and drag and drop) until you have four. Add a condition to each just as you outline above and send the command that’s appropriate. Again, I recommend hysteresis so use something lower than 75 to turn off.
I’ll never claim to be a master at python, but I can work up some effective code from time to time. Gonna set this script to fire off every 15 or 20 minutes. I’d rather not trigger it from temperature change events since that could (low possibilty but not zero) end up cycling the power too quickly.
At first I kept getting to the comparisons failed at the end else until I figured out the splitpwr.state is not a str but an openhab object. Converted that to a str and it seems to be working fine so far.
#!/usr/bin/python3
from openhab import OpenHAB
import logging
base_url = 'http://oh-svr:8080/rest'
openhab = OpenHAB(base_url)
shoptemp = openhab.get_item('paincave_temp_humidity_45_Sensor_temperature')
splitpwr = openhab.get_item('MiniSplit_Switch')
splitstate = str(splitpwr.state)
if (shoptemp.state >= 74) and (splitstate == 'OFF'):
splitpwr.command('ON')
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename="/var/log/openhab/events.log", filemode="a+",
format="%(asctime)-15s [%(levelname)-5s] %(message)s")
MSG = "PYTHON action - MiniSplit_Switch turned on - temp is high:" + str(shoptemp.state)
logging.info(MSG)
elif (shoptemp.state >= 74) and (splitstate == 'ON'):
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename="/var/log/openhab/events.log", filemode="a+",
format="%(asctime)-15s [%(levelname)-5s] %(message)s")
MSG = "PYTHON action - MiniSplit_Switch is already on due to high temp: " + str(shoptemp.state)
logging.info(MSG)
elif (shoptemp.state < 74) and (splitstate == 'OFF'):
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename="/var/log/openhab/events.log", filemode="a+",
format="%(asctime)-15s [%(levelname)-5s] %(message)s")
MSG = "PYTHON action - MiniSplit_Switch is already off due to low temp:" + str(shoptemp.state)
logging.info(MSG)
elif (shoptemp.state < 74) and (splitstate == 'ON'):
splitpwr.command('OFF')
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename="/var/log/openhab/events.log", filemode="a+",
format="%(asctime)-15s [%(levelname)-5s] %(message)s")
MSG = "PYTHON action - MiniSplit_Switch turned off due to low temp: " + str(shoptemp.state)
logging.info(MSG)
else:
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG, filename="/var/log/openhab/events.log", filemode="a+",
format="%(asctime)-15s [%(levelname)-5s] %(message)s")
MSG = "PYTHON NO-action - comparisons failed: " + str(shoptemp.state)
logging.info(MSG)
Wife requested a way to change the set point. So I added a knob cell on one page with an appropriate range that sets a variable which the python script now reads instead of a hard coded value. Getting better and better now.
That’s what the hysteresis is there for. It’s whole job is to prevent cycling the power too fast. It’s a big dance word but all it means is “turn on the AC at 75 but don’t turn it off until the temp drops below 73”. Between 73 and 75 no changes happen to the ac. If it’s on it stays on. If it’s off it remains off.
1 is usually enough in an AC situation but 2-3 is more typical.
This is how your python script converted, more or less, but it also sets up the cron schedule for you. Just install the JRuby scripting automation addon and create a file called paincave_minisplit.rb in conf/automation/ruby/
every 20.minutes do
shop_temp = paincave_temp_humidity_45_Sensor_temperature.state
threshold = paincave_temp_threshold.state || (74 | "°F")
if shop_temp >= threshold
if MiniSplit_Switch.ensure.on
logger.info "MiniSplit_Switch turned on - temp is high: #{shop_temp}"
else
logger.info "MiniSplit_Switch is already on due to high temp: #{shop_temp}"
end
elsif MiniSplit_Switch.ensure.off
logger.info "MiniSplit_Switch turned off due to low temp: #{shop_temp}"
else
logger.info "MiniSplit_Switch is already off due to low temp: #{shop_temp}"
end
end
and if you don’t need the logging, the rule is much simpler:
every 20.minutes do
shop_temp = paincave_temp_humidity_45_Sensor_temperature.state
threshold = paincave_temp_threshold.state || (74 | "°F")
MiniSplit_Switch.ensure << (shop_temp >= threshold)
end
If by any chance you want to react based on the change in temperature instead of doing it every 20 minutes, but you still don’t want to switch the compressor on/off too rapidly, here’s the rule
DEFAULT_THRESHOLD = 74 | "°F"
rule "Control MiniSplit" do
changed paincave_temp_humidity_45_Sensor_temperature,
to: proc { |to| to >= paincave_temp_threshold.state || DEFAULT_THRESHOLD },
for: 20.minutes,
attach: ON
changed paincave_temp_humidity_45_Sensor_temperature,
to: proc { |to| to < paincave_temp_threshold.state || DEFAULT_THRESHOLD },
for: 20.minutes,
attach: OFF
run do |event|
MiniSplit_Switch.ensure.command event.attachment
end
end
You can use two thresholds if you like: upper threshold for when to turn it on, and lower threshold for when to turn it off.
In JRuby you’d also just refer to it as isAlerting within the rule. Here’s a little script to demonstrate it:
# This creates a script (a rule without any triggers)
# It works in a UI based rule too
script id: "test1" do
logger.info "isAlerting: #{isAlerting}"
end
# Here we're running that script, passing the "isAlerting" context to it
rules.scripts["test1"].run(isAlerting: true)