- Platform information:
- Hardware: MacOS
- OS: OsX
- Java Runtime Environment: Oracle JDK
- openHAB version: 2.5.8
Hi, I recently started my personal OpenHAB project, at the moment it’s running on raspberry PI with bunch of zwave switchers and sensors (Fibaro ones). So far I implemented just couple of very simple rules to switch off lights when no motion in the room.
However, I do have specific case in one of the bathroom, where motion sensor sometimes is unable to detect movement if somebody is taking a bath It was pretty annoying so I decided to experiment with more robust rules and switched to python.
My theory of the operation was:
- Assuming bathroom light is on
- If motion sensor report no movement (OFF command) then I’m starting timer to wait couple of seconds
- If that time is elapsed, I wanted to warn the person (if anyone is still at bath) the light is about to be switched off by pulsing the light (since I don’t have a dimmer, just switch actuator) - so he/she could simply wave a hand or just move to keep lights on
I got to the point where I’m able to pulse that lite once all the timers are done
- but struggling to keep having lights ON, if motion sensor reports ON (movement reported) during that pulsing period
- the result is imply light switch going OFF and need to get it ON manually
It seems that I probably overcomplicated couple of things (as I experimented with various concepts…), anyway help or pointers are appreciated
My configurations are (at the moment it’s just items without thing bindings as I wanted to experiment locally first)
my.items
Switch aKidsBath_Light_Switch "Kids Bathroom - Switch" <light> (gLights)
Switch aKidsBath_Light_Switch_Off_Warn (gSwitchOffWarn)//virtual switch to warn light will go off
Switch vKidsBath_Motion "Kids Bathroom - Motion" <motion> (gMotionSensors) {
Static="link"[
actuator = "aKidsBath_Light_Switch",
luminance = "vKidsBath_Luminance"
]
}
Number vKidsBath_Temperature "Kids Bathroom - Temperature [%.1f °C]" <temperature> (gTemperatureSensors)
Number vKidsBath_Luminance "Kids Bathroom - Luminance [%d lux]" (gLuminanceSensors)
Switch aKajaRoom_Light_Switch "Kaja Room - Switch" <light> (gLights)
Switch aKajaRoom_Light_Switch_Off_Warn (gSwitchOffWarn)
Switch vKajaRoom_Motion "Kaja Room - Motion" <motion> (gMotionSensors) {
Static="link"[
actuator = "aKajaRoom_Light_Switch",
luminance = "vKajaRoom_Luminance"
]
}
Number vKajaRoom_Temperature "KajaRoom - Temperature [%.1f °C]" <temperature> (gTemperatureSensors)
Number vKajaRoom_Luminance "KajaRoom - Luminance [%d lux]" (gLuminanceSensors)
Group gMotionSensors
Group gTemperatureSensors
Group gLuminanceSensors
Group gLights
Group gSwitchOffWarn
demo.sitemap
sitemap demo label="Sitemap Demo" {
Frame label="Kids Bath" icon="bath" {
Default item=aKidsBath_Light_Switch label="Kids Bathroom - Switch"
Default item=vKidsBath_Luminance label="Kids Bathroom - Luminance"
Default item=vKidsBath_Motion label="Kids Bathroom - Motion"
Default item=vKidsBath_Temperature label="Kids Bathroom - Temperature"
}
Frame label="Kaja Room" icon="room" {
Default item=aKajaRoom_Light_Switch label="Kaja Room - Switch"
Default item=vKajaRoom_Luminance label="Kaja Room - Luminance"
Default item=vKajaRoom_Motion label="Kaja Room - Motion"
Default item=vKajaRoom_Temperature label="Kaja Room - Temperature"
}
}
And the lights.py rules file
from core.rules import rule
from core.triggers import when
from core.log import log_traceback
from core.actions import ScriptExecution
from core.metadata import get_all_namespaces, get_key_value, get_metadata, get_value, set_key_value
from org.joda.time import DateTime
occupancyTimers = {}
offWarnTimers = {}
def get_name(itemName): return get_key_value(itemName, "Config", "name") or itemName
def is_changed_from_undef_or_null(event): return isinstance(event.oldItemState, UnDefType) or event.oldItemState == "NULL"
def get_actuator(itemName): return get_key_value(itemName, "Static", "actuator") or UNDEF
def clean_timer(timers, timerName):
if timerName in timers:
timers[timerName].cancel()
del timers[timerName]
return
@rule("Lights_NoMotion", description="If no movement, alert with lights and then switch off if still no movement", tags=["lights"])
@when("Member of gMotionSensors changed")
def motion_changed(event):
light_switch_name = get_actuator(event.itemName)
timerName = event.itemName
if event.itemState == ON:
if items[light_switch_name+"_Off_Warn"] == ON: # If switch off warning is active, stop it
motion_changed.log.debug("Drop Off Warn state")
clean_timer(offWarnTimers, light_switch_name)
events.postUpdate(light_switch_name+"_Off_Warn", "OFF")
events.sendCommand(light_switch_name, "ON")
if items[light_switch_name] == OFF:
motion_changed.log.debug("Switch {} = {}, Motion {} = {}. Do nothing".format(light_switch_name, items[light_switch_name], event.itemName, event.itemState))
clean_timer(occupancyTimers, timerName)
if event.itemState == OFF and items[light_switch_name] == ON:
motion_changed.log.debug("Motion {} is OFF and Switch {} is ON. Go with timers".format(event.itemName, light_switch_name))
if timerName not in occupancyTimers or occupancyTimers[timerName].hasTerminated():
motion_changed.log.debug("Scheduling timer for {}".format(timerName))
occupancyTimers[timerName] = ScriptExecution.createTimer(DateTime.now().plusSeconds(2), lambda aItemName=light_switch_name: events.sendCommand(aItemName+"_Off_Warn", "ON"))
else:
motion_changed.log.debug("Re-Scheduling timer for {}".format(timerName))
occupancyTimers[timerName].reschedule(DateTime.now().plusSeconds(2))
def pulse_warn(timeStarted, warnItemName):
switch_item_name = warnItemName.split("_Off_Warn", 1)[0]
events.sendCommand(switch_item_name, "ON" if items[switch_item_name] == OFF else "OFF")
if DateTime.now().isBefore(timeStarted.plusMillis(1000)):
offWarnTimers[warnItemName].reschedule(DateTime.now().plusMillis(200))
else:
offWarnTimers[warnItemName].cancel()
del offWarnTimers[warnItemName]
events.sendCommand(switch_item_name, "ON")
events.sendCommand(warnItemName, "OFF")
@rule("Light_pulsing", description="Light pulsing", tags=["lights"])
@when("Member of gSwitchOffWarn received command ON")
def pulse_light(event):
warn_item_name = event.itemName
if warn_item_name not in offWarnTimers:
timeStarted = DateTime.now()
offWarnTimers[warn_item_name] = ScriptExecution.createTimer(DateTime.now(), lambda ts=timeStarted, sw=warn_item_name: pulse_warn(timeStarted, sw))
@rule("End pulsing. Turn of lights", description="Lights off", tags=["lights"])
@when("Member of gSwitchOffWarn received command OFF")
def end_pulse(event):
switch_item_name = event.itemName.split("_Off_Warn", 1)[0]
events.sendCommand(switch_item_name, "OFF")
Thanks