Hi everyone,
I would like to set up a rule for my outside lights. I tried to copy, paste and build something based on the advise I found in the forum but I guess I am still too much of a noob to get things right …
My set up:
- Dimmable light controlled as KNX dimmer thing
- Motion sensor as a contact thing (via KNX group address)
- Sun and brightness data via weather station or alternatively astro binding
- OpenHAB 2.5
This is my objective:
- The light should go on to a 25% dimm value in the morning at 6:45 if it is dark at that time and go off after sunrise. Same in the evening but from sunset to 11:30 p.m.
- When the motion sensor is activated during the day it should send an alarm note. When it is dark it should dimm the light up to a 100 percent and then go back to the previous state: Either 25% or 0% or a manually set value.
- It would be great to be able to override the automatic setting by pressing the light switch, i.e. if the switch was pressed the light will stay on until switched off regardless of motion sensor acitivity
What I did so far:
- I created (copy pasted and tried to modify) rules I found in other posts
- I tried to implement the Design Pattern “Time of Day” by @rlkoshak
This is my motion sensor rule - with slow dimming back to the previous state. It works one but I guess the problems start when the motion sensor is activated twice within the three minutes of full brightness. Then the previous state is set to 100% and the light simply stays on.
var Timer OU_Vorgarten_Timer = null
var int percent = 0
var Timer fade_Timer = null
var mem_OU_Podest_Light
rule "BWM Vordach mit Dimmer Memory und Fade"
when Item OU_Vordach_Motion changed to OPEN then
{ if (OU_Podest_Light.state === null) { mem_OU_Podest_Light = 0 } else {mem_OU_Podest_Light = OU_Podest_Light.state}
OU_Podest_Light.sendCommand(100)
if (OU_Vorgarten_Timer === null)
{
OU_Vorgarten_Timer = createTimer(now.plusMinutes(3))
[ |
{
if (OU_Podest_Light.state instanceof DecimalType)
{
percent = ((OU_Podest_Light.state as DecimalType)/5).intValue * 5 //round to 5
fade_Timer = createTimer(now.plusMillis(400)) [|
OU_Podest_Light.sendCommand(percent)
if (percent > mem_OU_Podest_Light) {
percent = percent - 10
fade_Timer.reschedule(now.plusMillis(500))
}
]
}
}
OU_Vorgarten_Timer = null ]
}
else { OU_Vorgarten_Timer.reschedule(now.plusMinutes(3))
}
}
end
I found forum threads with persistance for dimmer value storage but I didn’t get these solutions to work. I guess one workaround could be to forget about the previous state and go back to either 25% or 0% based on the time of day. Then the remaining challenge would be to override the whole rule when the light is triggered by the switch.
For time/ brightness based activation I set up this rule:
import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.joda.time.DateTime
var int percent = 0
var Timer fade_Timer = null
rule "Morgenlicht im Vorgarten AN"
when
Time cron "0 45 6 ? * MON-FRI *"
then
if (now.isBefore((astro_Sonnenaufgang.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli))
{
OU_Podest_Light.sendCommand(ON)
OU_Carport_Light.sendCommand(ON)
OU_FrontYard_Light.sendCommand(50)
}
end
rule "Morgenlicht im Vorgarten AUS"
when
Channel "astro:sun:home:rise#event" triggered END
then
OU_Podest_Light.sendCommand(0)
OU_Carport_Light.sendCommand(OFF)
OU_FrontYard_Light.sendCommand(OFF)
end
rule "Abendlicht im Vorgarten AN"
when
Channel 'astro:sun:home:civilDusk#event' triggered END
then
if (OU_Podest_Light.state instanceof DecimalType) {
percent = ((OU_Podest_Light.state as DecimalType)/5).intValue * 5 //round to 5
fade_Timer = createTimer(now.plusMillis(500)) [|
OU_Podest_Light.sendCommand(percent)
if (percent < 40) {
percent = percent + 5
fade_Timer.reschedule(now.plusMillis(500))
}
]
}
end
rule "Abendlicht im Vorgarten AUS"
when
Time cron "0 30 23 ? * MON-FRI *"
then
if (OU_Podest_Light.state instanceof DecimalType) {
percent = ((OU_Podest_Light.state as DecimalType)/5).intValue * 5 //round to 5
fade_Timer = createTimer(now.plusMillis(500)) [|
OU_Podest_Light.sendCommand(percent)
if (percent > 0) {
percent = percent - 5
fade_Timer.reschedule(now.plusMillis(500))
}
]
}
end
And finally this is the Time of day rule from the Design Pattern. I have not implemented it in my rules because I receive this error:
2020-01-08 17:55:28.882 [WARN ] [rest.core.item.EnrichedItemDTOMapper] - Failed transforming the state ‘NULL’ on item ‘vTimeOfDay’ with pattern ‘MAP(weather.map):%s’: An error occurred while opening file.
val logName = "Time Of Day"
rule "Calculate time of day state"
when
System started or // run at system start in case the time changed when OH was offline
Channel 'astro:sun:home:rise#event' triggered START or
Channel 'astro:sun:home:set#event' triggered START or
Channel 'astro:sun:minus90:set#event' triggered START or
Time cron "0 1 0 * * ? *" or // one minute after midnight so give Astro time to calculate the new day's times
Time cron "0 0 6 * * ? *" or
Time cron "0 0 23 * * ? *"
then
logInfo(logName, "Calculating time of day...")
// Calculate the times for the static tods and populate the associated Items
// Update when changing static times
// Jump to tomorrow and subtract to avoid problems at the change over to/from DST
val morning_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(18)
vMorning_Time.postUpdate(morning_start.toString)
val night_start = now.withTimeAtStartOfDay.plusDays(1).minusHours(1)
vNight_Time.postUpdate(night_start.toString)
val bed_start = now.withTimeAtStartOfDay
vBed_Time.postUpdate(bed_start.toString)
// Convert the Astro Items to Joda DateTime
val day_start = new DateTime(vSunrise_Time.state.toString)
val evening_start = new DateTime(vSunset_Time.state.toString)
val afternoon_start = new DateTime(vEvening_Time.state.toString)
// Calculate the current time of day
var curr = "UNKNOWN"
switch now {
case now.isAfter(morning_start) && now.isBefore(day_start): curr = "MORNING"
case now.isAfter(day_start) && now.isBefore(afternoon_start): curr = "DAY"
case now.isAfter(afternoon_start) && now.isBefore(evening_start): curr = "AFTERNOON"
case now.isAfter(evening_start) && now.isBefore(night_start): curr = "EVENING"
case now.isAfter(night_start): curr = "NIGHT"
case now.isAfter(bed_start) && now.isBefore(morning_start): curr = "BED"
}
// Publish the current state
logInfo(logName, "Die aktuelle Tageszeit ist: " + curr)
vTimeOfDay.sendCommand(curr)
end
This is the item for time of day:
String vTimeOfDay "Aktuelle Tageszeit: [MAP(weather.map):%s]" <tod> (Bewegungsmelder)
DateTime vMorning_Time "Morgen [%1$tH:%1$tM]" <sunrise>
DateTime vSunrise_Time "Tag [%1$tH:%1$tM]" <sun> { channel="astro:sun:home:rise#start" }
DateTime vAfternoon_Time "Nachmittag [ %1$tH:%1$tM]" <sunset> { channel="astro:sun:minus90:set#start" }
DateTime vSunset_Time "Abend [%1$tH:%1$tM]" <sunset> { channel="astro:sun:home:set#start" }
DateTime vNight_Time "Nacht [%1$tH:%1$tM]" <moon>
DateTime vBed_Time "Schlaf [%1$tH:%1$tM]" <bedroom_blue>
I guess the experienced users will spot a lot of mistakes. Please let me know how to fix them.
Thank you and best regards, Max