Extended Motion Sensor Rule: any Suggestions?

My point exactly. Tedium is the anti-purpose of home automation

Sometimes you have to do some tedious work up front to enable savings in the long run.

Indeed. If I have some time I will look into it. I have other things on the go and no sensor to test with right now

I thought of a real regulator. Actually, it is not that hard to implement. Proportional–integral–derivative controller - Wikipedia

You theoretically could do that, im an engineer for process plants and that way you normally regulate temperatures, pressures, levels whatever.

You basically check every second or 2 or so and adjust your (light) output based on setpoint and current value.

In the most simple form, you just do (Setpoint in lux - current value in lux) x Factor P= output in %, limited to 0-100.

You then choose P experimentally (in this case) until it works alright. If its too big, it could start to swing.

You can make it better by using a more complex form. Im not sure if that is something which works good for lightning, would be fun for sure.

Basically it periodically readjusts the Brightness till it measures the point you want.

That way you dont have to calculate each part into your output yourself. It just fixes the brightness no matter what influences it or how the lamps behave.
Its the difference between controlling and regulating.
You need a closed loop feedback for that, what means that your output has to influence your input, like it does with a luminance sensor inside the room.
Measuring the influence of each lamp would be a dead end. Just use a regulator algorithm…

But personally i dont think i need that, it works fine with fixed values.

But hey, maybe i try it out if i find some time somewhere in the Future :smiley: you can try it if you want to, too :slight_smile: but back to topic.

Wow, really? It just gives me the before and after values?? Nice :sunglasses:

But of course! I hadn’t thought of that.

I will see about adding a level target setting and scene type.

One problem that always stumped me when I was thinking about this type of scene is how to handle switched lights. We wouldn’t want them turning on and off repeatedly. A delay after changing the light would prevent flickering, but it’s possible it would still try to turn on and off repeatedly at the end of the delay.

Look at Rules | openHAB and pay attention to which variables appear under which circumstances (e.g. those will not appear for a received command triggered Rule but receivedCommand will).

A change is a change for rule triggers. Depending on the binding in use, you may be able to apply a transformation to your raw input data to round it and eliminate some jitter, so that the Item changes less frequently.

Hey, Í implemented your suggestions.
but the NULL Problem with the Hashtables persists…

21:49:36.646 [WARN ] [eclipse.smarthome.model.script.MOTION] - HIER ANFANG                                                               
21:49:36.647 [WARN ] [eclipse.smarthome.model.script.MOTION] - Flur                                                                      
21:49:36.649 [ERROR] [untime.internal.engine.RuleEngineImpl] - Rule 'Motion': null

Code to that:

        // Cancel the timer if it exists
        logWarn("MOTION", "HIER ANFANG")
        logWarn("MOTION", raum_name)
        timers.get(raum_name)?.cancel
        timers.put(raum_name, null)
        logWarn("MOTION", "HIER ENDE")

Any hopes for Hashtables? Are they initialized wrong?

Full Code:
Rules:

import java.util.Hashtable
import org.eclipse.smarthome.model.script.ScriptServiceUtil

val Hashtable<String, Timer> timers = new Hashtable<String, Timer>()
val Hashtable<String, DateTime> last_update_time = new Hashtable<String, DateTime>()
val Hashtable<String, String> last_update_type = new Hashtable<String, String>()
val Hashtable<String, Number> last_update_brightness = new Hashtable<String, Number>()
val Hashtable<String, Number> last_update_temperature = new Hashtable<String, Number>()

val PAR_DEADTIME_MANUAL_SECONDS = 20

val Log_An = false
rule "Time of Day"
when
    System started or
    Time cron "0 0 10 * * ? *" or
    Time cron "0 0 13 * * ? *" or
    Time cron "0 0 16 * * ? *" or
    Time cron "0 0 22 * * ? *"
then
    val Zeit_morgens = now.withTime(10, 0, 0, 0)
    val Zeit_mittags = now.withTime(13, 0, 0, 0)
    val Zeit_nachmittags = now.withTime(16, 0, 0, 0)
    val Zeit_nachts = now.withTime(22, 0, 0, 0)

    var curr_TOD = "UNKNOWN"
    switch now {
        case now.isAfter(Zeit_morgens) && now.isBefore(Zeit_mittags): curr_TOD = "MORGENS"
        case now.isAfter(Zeit_mittags) && now.isBefore(Zeit_nachmittags): curr_TOD = "MITTAGS"
        case now.isAfter(Zeit_nachmittags) && now.isBefore(Zeit_nachts): curr_TOD = "NACHMITTAG"
        default: curr_TOD = "NACHTS"
    }

    if(Time_of_Day.state.toString != curr_TOD){
        logInfo("TOD", "Transitioning time of day to " + curr_TOD)
        Time_of_Day.postUpdate(curr_TOD)
    }
end

rule "Motion"
when
    Member of gMotion_Sensor_Bewegung changed or
    Member of gMotion_Sensor_Lux received update
then
    // Raum bestimmen
    val raum_name = triggeringItem.name.split("_").get(1)
    val light_name = "gMotion_"+raum_name+"_Licht_Helligkeit"
    if(Log_An) logWarn("MOTION", raum_name)

 val motion_sensor = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Sensor_Bewegung")

    //wenn letzter Befehl von Manuell, dann nur wenn letzter Befehl älter als X Sekunden (Da der Sensor bis zu 15 Sekunden lang noch AN senden kann)
    //verhindert, dass das Licht nach dem Ausschalten direkt wieder an geht. Wenn Manuell und Sensor ist inaktiv, dann ist auch nichts zu tun.
    if(last_update_type.get(raum_name) === null || last_update_type.get(raum_name) == "MANU"){       
        if(motion_sensor.state ==OFF){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Bewegungsmelder aus und letzter Befehl manuell nicht OK")
            return;  
        }   

        if(last_update_time.get(raum_name) !== null && now.minusSeconds(PAR_DEADTIME_MANUAL_SECONDS).isBefore(last_update_time.get(raum_name))){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Totzeit nach manuell aus nicht OK")
            return;
        }
    }

    // Parameter
    val par_lux_threshold = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Lux")
    val par_timeout_seconds = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Timeout")

    val bright_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Brightness")
    val par_sp_brightness = if(bright_item === null) 0 else bright_item.state as Number
    val temp_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Temperature")
    val par_sp_temperature = if(temp_item === null) 60 else temp_item.state as Number

   
    val lux_sensor = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Sensor_Lux")
    val light_brightness = ScriptServiceUtil.getItemRegistry.getItem(light_name)

    // Motion sensor is ON
    if(motion_sensor.state == ON){
        if(Log_An) logWarn("MOTION", "Sensor Aktiv")
        // Cancel the timer if it exists
        logWarn("MOTION", "HIER ANFANG")
        logWarn("MOTION", raum_name)
        timers.get(raum_name)?.cancel
        timers.put(raum_name, null)
        logWarn("MOTION", "HIER ENDE")
        // Exit wenn Licht an
        if(light_brightness.state as Number >= 1) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Licht an nicht OK")
            return;
        }

        // check for UNDEF first
        val cur_lux = if(lux_sensor.state instanceof DecimalType) lux_sensor.state as Number else 1000.0
        val SP_lux = if(par_lux_threshold.state instanceof DecimalType) par_lux_threshold.state as Number else 0.0
        // Check if the room is already too bright
        if(cur_lux > SP_lux) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Helligkeit nicht OK")
            return;
        }

        // Check that the target brightness is high enough
        if(par_sp_brightness <= 0.1){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Sensor Sollhelligkeit > 0 nicht OK")
            return;
        }

        // Record the update
        last_update_time.put(raum_name, now)
        last_update_type.put(raum_name, "AUTO")

        // Command the light
        sendCommand(light_name, par_sp_brightness.toString)
        createTimer(now.plusMillis(400), [ | sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperature", par_sp_temperature.toString)])
        createTimer(now.plusMillis(800), [ | sendCommand(light_name, par_sp_brightness.toString)])
        createTimer(now.plusMillis(1200), [ | sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperature", par_sp_temperature.toString)])      
    }

    else {
        if(Log_An) logWarn("MOTION", "Sensor Inaktiv")

        if(timers.get(raum_name) !== null){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Timer noch nicht vorhanden nicht OK")
            return;
        }

        var par_timeout = if(par_timeout_seconds.state instanceof DecimalType) (par_timeout_seconds.state as Number).intValue else 30
        if(Log_An) logWarn("MOTION", "AKTION AUS TIMER AKTIVIERT")
        timers.put(raum_name, createTimer(now.plusSeconds(par_timeout), [ |
            last_update_time.put(raum_name, now)
            last_update_type.put(raum_name, "AUTO")
            sendCommand(light_name, "OFF") // you can send ON/OFF to Dimmer Items
            if(Log_An) logWarn("MOTION", "AKTION AUS")
        ]))
    }
end

//TODO: MOTION CANCEL

Items:

 Items:
//Global

String Time_of_Day "Tageszeit"

//Overall Groups

Group: Dimmer:AVG gMotion_Licht_Helligkeit

Group: Dimmer:AVG gMotion_Licht_Farbtemperatur

Group: Switch:OR(ON,OFF) gMotion_Sensor_Bewegung

Group: Number:AVG gMotion_Sensor_Lux

Group gMotion_SP_Lux "Bewegungsmelder Schwellwert Helligeit"

Group gMotion_SP_Timeout "Bewegungsmelder Timeouts"

Group gMotion_SP_Brightness "Bewegungsmelder Sollhelligkeit"

Group gMotion_SP_Temperature "Bewegungsmelder Farbtemperaturen"

//Flur

Group: Dimmer:AVG gMotion_Flur_Licht_Helligkeit (gMotion_Licht_Helligkeit)

Group: Dimmer:AVG gMotion_Flur_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)

Group: Switch:OR(ON,OFF) gMotion_Flur_Sensor_Bewegung (gMotion_Sensor_Bewegung)

Group: Number:AVG gMotion_Flur_Sensor_Lux (gMotion_Sensor_Lux)

Group Motion_Flur_SP_Brightness "Bewegungsmelder Flur Helligkeit" (gMotion_SP_Brightness)

Group Motion_Flur_SP_Temperature "Bewegungsmelder Flur Farbtemperatur" (gMotion_SP_Temperature)

Number Motion_Flur_SP_Lux "Schwellwert Helligkeit Flur (lx)" (gMotion_SP_Lux)

Number Motion_Flur_SP_Timeout "Timeout Flur (s)" (gMotion_SP_Timeout)

Dimmer Motion_Flur_MORGENS_Brightness "Helligkeit morgens" (Motion_Flur_SP_Brightness)

Dimmer Motion_Flur_MORGENS_Temperature "Farbtemperatur morgens" (Motion_Flur_SP_Temperature)

Dimmer Motion_Flur_MITTAGS_Brightness "Helligkeit mittags" (Motion_Flur_SP_Brightness)

Dimmer Motion_Flur_MITTAGS_Temperature "Farbtemperatur mittags" (Motion_Flur_SP_Temperature)

Dimmer Motion_Flur_NACHMITTAG_Brightness "Helligkeit nachmittags" (Motion_Flur_SP_Brightness)

Dimmer Motion_Flur_NACHMITTAG_Temperature "Farbtemperatur nachmittags" (Motion_Flur_SP_Temperature)

Dimmer Motion_Flur_NACHTS_Brightness "Helligkeit nachts" (Motion_Flur_SP_Brightness)

Dimmer Motion_Flur_NACHTS_Temperature "Farbtemperatur nachts" (Motion_Flur_SP_Temperature)

//Küche

Group: Dimmer:AVG gMotion_Kueche_Licht_Helligkeit (gMotion_Licht_Helligkeit)

Group: Dimmer:AVG gMotion_Kueche_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)

Group: Switch:OR(ON,OFF) gMotion_Kueche_Sensor_Bewegung (gMotion_Sensor_Bewegung)

Group: Number:AVG gMotion_Kueche_Sensor_Lux (gMotion_Sensor_Lux)

Group Motion_Kueche_SP_Brightness "Bewegungsmelder Küche Helligkeit" (gMotion_SP_Brightness)

Group Motion_Kueche_SP_Temperature "Bewegungsmelder Küche Farbtemperatur" (gMotion_SP_Temperature)

Number Motion_Kueche_SP_Lux "Schwellwert Helligkeit Küche (lx)" (gMotion_SP_Lux)

Number Motion_Kueche_SP_Timeout "Timeout Küche (s)" (gMotion_SP_Timeout)

Dimmer Motion_Kueche_MORGENS_Brightness "Helligkeit morgens" (Motion_Kueche_SP_Brightness)

Dimmer Motion_Kueche_MORGENS_Temperature "Farbtemperatur morgens" (Motion_Kueche_SP_Temperature)

Dimmer Motion_Kueche_MITTAGS_Brightness "Helligkeit mittags" (Motion_Kueche_SP_Brightness)

Dimmer Motion_Kueche_MITTAGS_Temperature "Farbtemperatur mittags" (Motion_Kueche_SP_Temperature)

Dimmer Motion_Kueche_NACHMITTAG_Brightness "Helligkeit nachmittags" (Motion_Kueche_SP_Brightness)

Dimmer Motion_Kueche_NACHMITTAG_Temperature "Farbtemperatur nachmittags" (Motion_Kueche_SP_Temperature)

Dimmer Motion_Kueche_NACHTS_Brightness "Helligkeit nachts" (Motion_Kueche_SP_Brightness)

Dimmer Motion_Kueche_NACHTS_Temperature "Farbtemperatur nachts" (Motion_Kueche_SP_Temperature)

//Bett

Group: Dimmer:AVG gMotion_Bett_Licht_Helligkeit (gMotion_Licht_Helligkeit)

Group: Dimmer:AVG gMotion_Bett_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)

Group: Switch:OR(ON,OFF) gMotion_Bett_Sensor_Bewegung (gMotion_Sensor_Bewegung)

Group: Number:AVG gMotion_Bett_Sensor_Lux (gMotion_Sensor_Lux)

Group Motion_Bett_SP_Brightness "Bewegungsmelder Bett Helligkeit" (gMotion_SP_Brightness)

Group Motion_Bett_SP_Temperature "Bewegungsmelder Bett Farbtemperatur" (gMotion_SP_Temperature)

Number Motion_Bett_SP_Lux "Schwellwert Helligkeit Bett (lx)" (gMotion_SP_Lux)

Number Motion_Bett_SP_Timeout "Timeout Bett (s)" (gMotion_SP_Timeout)

Dimmer Motion_Bett_MORGENS_Brightness "Helligkeit morgens" (Motion_Bett_SP_Brightness)

Dimmer Motion_Bett_MORGENS_Temperature "Farbtemperatur morgens" (Motion_Bett_SP_Temperature)

Dimmer Motion_Bett_MITTAGS_Brightness "Helligkeit mittags" (Motion_Bett_SP_Brightness)

Dimmer Motion_Bett_MITTAGS_Temperature "Farbtemperatur mittags" (Motion_Bett_SP_Temperature)

Dimmer Motion_Bett_NACHMITTAG_Brightness "Helligkeit nachmittags" (Motion_Bett_SP_Brightness)

Dimmer Motion_Bett_NACHMITTAG_Temperature "Farbtemperatur nachmittags" (Motion_Bett_SP_Temperature)

Dimmer Motion_Bett_NACHTS_Brightness "Helligkeit nachts" (Motion_Bett_SP_Brightness)

Dimmer Motion_Bett_NACHTS_Temperature "Farbtemperatur nachts" (Motion_Bett_SP_Temperature)

Any ideas? :confused: sooooo close…


If you only have on off switches, it doesnt make any sense to regulate, you could only use it for turning it on (off does not work, because you wont notice it if it gets darker)

I’d open it up to see what’s going on

var blah = timers.get(raum_name)
if (blah !== null) {
   logInfo("MOTION", "something in hashtable")
   blah.cancel
   logInfo("MOTION", "trying to PUT null")
   timers.put(raum_name, null)
} else {
   logInfo("MOTION", "nothing in hashtable")
}

I don’t think you’re allowed to put null in a hashtable (unlike a hashmap).
You may need to .remove() instead

You are completely right. Hashtable doesn’t allow null keys or values. My Java is getting really rusty. HashMap does allow one key to be null and it allows null values.

Here is an all-in-one solution that I think meets all of your requirements OOTB, but it can also be customized…

This solution requires the use of the new rule engine, scripted automation, Jython, and the helper libraries. I have incorporated individual room luminance and it looks to be ready to commit.

Ok, thanks for your help! I will try that.

Looks nice, i will bookmark that. Im not sure i want to upgrade my running automation system for now.

Things missing i think would be:

-lux sensor should only be used for turning on, not turning off in my case, as it is inside the room.

-better than only checking for >98% as manual action would be any state change of that group/lamp, so i can dim lights or change color without turning off automatically, until the light is turned off manually. That way i can adjust lamps however i want without manually changing the mode first, and not only via switches but also through alexa or app or ui. A Timeout before turning back to autlmatic mode would be needed, as my detectors are slow and are on for at least 15 econds after ladt movement, so lights dont turn right back on if i want to turn them off manually.
What do you think?

The new and old rule engines can be used at the same time, so upgrading is currently optional. There are many benefits to the new rule engine and there is a section of the helper library repository for community contributed scripts and libraries, like the one I referred to, that users can make use of with some minor configuration.

This is the part of the code (and documentation) that I mentioned I have yet to commit.

In the last couple years, the only manual adjustments that we needed were to keep the lights bright, like for reading a book, which the light_action function handles. You could customize the light_action function to not change a dimmer or color light if it has a value different than any of the predefined values in any of the modes. Let me know if you’d like me to code this… should only take a few minutes. I don’t see any way to handle this for switches though.

Keep in mind that you can manually adjust your lights and they will not change back to the predefined settings until either a Mode change or a lux level change where the current and previous lux values span a low_lux_trigger. Please provide some specific scenarios that are you imagining where this would be an issue.

I don’t understand what you mean here. Are your motion sensors only ON with motion for 15s!? If you can’t adjust this, which I think you can, then you can set an OFF timer so that the OFF action will be delayed, or it will be cancelled if motion is detected again before the timer expires.

BTW, the Philips Hue Motion Sensors (and others) use Zigbee and are compatible with the Zigbee binding.

If I understand correctly, the manual/auto thing is similar to something I do in my rules.
Automated presence detection lighting, with timeouts, etc.
If someone comes along and intervenes with a manual switch - they don’t want that automatic action, thankyou.
So, a “manual off” would need to prohibit the motion triggered auto on - for a period. The user knows best.

My solution has a “Manual mode” Item for each lighting zone, I can detect manual events (I only have on/off so its easier) and set that. “Manual mode” prevents the usual auto-on AND auto-off from taking effect.
“Manual mode itself” expires after a time in the hours range, the effect of that is to allow auto to resume control and also prevent lights left on all night.

The same can be done with area triggers (including the timer), but it sounded to me like the requirement was for the manual override to be automatically detected :face_with_raised_eyebrow:.

Yes, that is what I’m talking about. My rules detect user intervention of fingers on switches. The actual mechanism for me is “unexpected” (from openHABs viewpoint) state changes. The user knows what they want, the auto should be blocked for a while. User doesn’t do anything special, just uses the wallswitch.

Thats right, If i set dome lights manually e.g. color scenes, i want it to stay there until i turn everything off.
The Problem with 100% is, that i have many lights and if i choose to have every lamp in the open living room/kitchen to 80% because i have visitors or so (easily with alexa or dimmer switches or the hue app, which is nicer to set color scenes) i dont want it to turn off after 30 seconds like normally in the kitchen. And i dont want 100 percent on every lamp. That is way too bright. Even in the bedroom 100 percent is way too much for reading, i only use it if i have to sort laundry or so. If i Change something, anything, colors, whatever, i do not want it to turn off after 30s,i do not want to take my phone and set a manual scene, and i want it to behave automaticslly after turning it off. In my opinion, its the easiest way for the user like that,
And i dont have to set it to manual by myself or check all switches etc.

For now, i will just go with my rule i think (if i ever get it to work…), maybe i will have some time in s few months to have a look into the new rule engine.

The hue sensor turns on for at least 15s, and stays on until 15s after the last movement.

Maybe i could change that ober zigbee directly, and thats a step i will take in the future. Porting the motion sensors off the philips hue bridge is the first step. The 15s are not that bad :slight_smile:

And thanks for all your support so far! Im really looking forward to this discussion.

I haven’t looked at your code closely yet, but in my much simpler system (I’ve only switches, no dimmers) I handle this with manual trigger detection and an override flag. If the light is changed manually, that light get’s excluded from all automations until the next time of day period (though that could be adjusted to some other event). In my Rules DSL version the override flag is an Item using Associated Items DP. In my JSR223 version I use metadata.

@openhabber, see [Deprecated] Design Pattern: Motion Sensor Timer for an example. With JSR223 I’ve submitted a module that should make managing these timers a bit simpler as well. See Timer Manager by rkoshak · Pull Request #233 · openhab-scripters/openhab-helper-libraries · GitHub.

In the OP you asked for something you just need to configure rather than needing to code from scratch. JSR223 is pretty much your only option for that right now which is why we are all pushing that as an approach.

I know you and Scott have seen this, I’m just posting this example for future readers.

from core.rules import rule
from core.triggers import when
from time import sleep
from core.metadata import get_key_value, set_metadata
from core.actions import PersistenceExtensions
from org.joda.time import DateTime

@rule("Cloudy Lights",
      description="Turns ON or OFF some lights when it is cloudy during the day",
      tags=["lights"])
@when("Item vIsCloudy changed")
@when("Item vTimeOfDay changed")
def cloudy_lights(event):
    if (items["vTimeOfDay"] != StringType("DAY") or
        isinstance(items["vIsCloudy"], UnDefType)):
        return

    if event.itemName == "vTimeOfDay":
        sleep(0.5)

    cloudy_lights.log.info("It is {} and cloudy changed: {}"
                           .format(items["vTimeOfDay"], items["vIsCloudy"]))

    for light in [light for light in ir.getItem("gLights_ON_WEATHER").members if get_key_value(light.name, "Flags", "override") != ON]:
#   for light in filter(lambda light: get_key_value(light.name, "Flags", "override") != "ON", ir.getItem("gLights_ON_WEATHER").members):
        if items[light.name] != items["vIsCloudy"]:
            events.sendCommand(light, items["vIsCloudy"])

@rule("Lights Override",
      description=("Sets the Override flag when a light is manually changed "
                   "during the day"),
      tags=["lights"])
@when("Member of gLights_ON_WEATHER changed")
def override_lights(event):
    sleep(0.5) # Give pesistence a chance to catch up

    # Wait a minute before reacting after vTimeOfDay changes, ignore all other
    # times of day.
    if (items["vTimeOfDay"] != StringType("DAY") or
        (PersistenceExtensions.lastUpdate(ir.getItem("vTimeOfDay"), "mapdb")
            .isAfter(DateTime.now().minusSeconds(10)))):
        return

    if (not PersistenceExtensions.lastUpdate(ir.getItem("vIsCloudy"), "mapdb")
            .isAfter(DateTime.now().minusSeconds(5))):
        override_lights.log.info("Manual light trigger detected, overriding the"
                                 " light for auto control for {}."
                                 .format(event.itemName)))
        set_metadata(event.itemName, "Flags", { "override" : "ON" },
                     overwrite=False)

@rule("Reset Override",
      description="Change override flag when time of day changes",
      tags=["lights"])
@when("Item vTimeOfDay changed")
def reset_overrides(event):
    for light in ir.getItem("gLights_ON_WEATHER").members:
        set_metadata(light.name, "Flags", { "override" : "OFF" },
                     overwrite=False)

The Rules DSL version is a combination of Design Pattern: State Machine Driven Groups and Design Pattern: Manual Trigger Detection.

Hey everyone,

it seems to work now like i wanted, hurraay :smiley:

im giving you all code if somebody is interested. If you have some more suggestions, feel free =)

Motion.rules

import java.util.Hashtable
import org.eclipse.smarthome.model.script.ScriptServiceUtil

val Hashtable<String, Timer> timers = new Hashtable<String, Timer>()
val Hashtable<String, DateTime> last_update_time = new Hashtable<String, DateTime>()
val Hashtable<String, String> last_update_type = new Hashtable<String, String>()

val PAR_DEADTIME_MANUAL_SECONDS = 20

val Log_An = false
rule "Time of Day"
when
    System started or
    Time cron "0 0 10 * * ? *" or
    Time cron "0 0 13 * * ? *" or
    Time cron "0 0 16 * * ? *" or
    Time cron "0 0 22 * * ? *"
then
    val Zeit_morgens = now.withTime(10, 0, 0, 0)
    val Zeit_mittags = now.withTime(13, 0, 0, 0)
    val Zeit_nachmittags = now.withTime(16, 0, 0, 0)
    val Zeit_nachts = now.withTime(22, 0, 0, 0)

    var curr_TOD = "UNKNOWN"
    switch now {
        case now.isAfter(Zeit_morgens) && now.isBefore(Zeit_mittags): curr_TOD = "MORGENS"
        case now.isAfter(Zeit_mittags) && now.isBefore(Zeit_nachmittags): curr_TOD = "MITTAGS"
        case now.isAfter(Zeit_nachmittags) && now.isBefore(Zeit_nachts): curr_TOD = "NACHMITTAG"
        default: curr_TOD = "NACHTS"
    }

    if(Time_of_Day.state.toString != curr_TOD){
        logInfo("TOD", "Transitioning time of day to " + curr_TOD)
        Time_of_Day.postUpdate(curr_TOD)
    }
end

rule "Motion"
when
    Member of gMotion_Sensor_Bewegung changed or
    Member of gMotion_Sensor_Lux received update
then
    // Raum bestimmen
    val raum_name = triggeringItem.name.split("_").get(1)
    val light_name = "gMotion_"+raum_name+"_Licht_Helligkeit"
    if(Log_An) logWarn("MOTION", raum_name)

 val motion_sensor = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Sensor_Bewegung")

    //wenn letzter Befehl von Manuell, dann nur wenn letzter Befehl älter als X Sekunden (Da der Sensor bis zu 15 Sekunden lang noch AN senden kann)
    //verhindert, dass das Licht nach dem Ausschalten direkt wieder an geht. Wenn Manuell und Sensor ist inaktiv, dann ist auch nichts zu tun.
    if(last_update_type.get(raum_name) === null || last_update_type.get(raum_name) == "MANU"){       
        if(motion_sensor.state ==OFF){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Bewegungsmelder aus und letzter Befehl manuell nicht OK")
            return;  
        }   

        if(last_update_time.get(raum_name) !== null && now.minusSeconds(PAR_DEADTIME_MANUAL_SECONDS).isBefore(last_update_time.get(raum_name))){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Totzeit nach manuell aus nicht OK")
            return;
        }
    }

    // Parameter
    val par_lux_threshold = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Lux")
    val par_timeout_seconds = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Timeout")

    val bright_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Helligkeit")
    val par_sp_Helligkeit = if(bright_item === null) 0 else bright_item.state as Number
    val temp_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Farbtemperatur")
    val par_sp_Farbtemperatur = if(temp_item === null) 60 else temp_item.state as Number

   
    val lux_sensor = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Sensor_Lux")
    val light_Helligkeit = ScriptServiceUtil.getItemRegistry.getItem(light_name)

    // Motion sensor is ON
    if(motion_sensor.state == ON){
        if(Log_An) logWarn("MOTION", "Sensor Aktiv")
        // Cancel the timer if it exists
        logWarn("MOTION", raum_name)
        if (timers.get(raum_name) !== null){
            timers.get(raum_name)?.cancel()
            timers.remove(raum_name)
        }
        // Exit wenn Licht an
        if(light_Helligkeit.state as Number >= 1) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Licht an nicht OK")
            return;
        }

        // check for UNDEF first
        val cur_lux = if(lux_sensor.state instanceof DecimalType) lux_sensor.state as Number else 1000.0
        val SP_lux = if(par_lux_threshold.state instanceof DecimalType) par_lux_threshold.state as Number else 0.0
        // Check if the room is already too bright
        if(cur_lux > SP_lux) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Helligkeit nicht OK")
            return;
        }

        // Check that the target Helligkeit is high enough
        if(par_sp_Helligkeit <= 0.1){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Sensor Sollhelligkeit > 0 nicht OK")
            return;
        }

        // Record the update
        last_update_time.put(raum_name, now)
        last_update_type.put(raum_name, "AUTO")

        // Command the light
        sendCommand(light_name, par_sp_Helligkeit.toString)
        createTimer(now.plusMillis(1000), [ | sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperatur", par_sp_Farbtemperatur.toString)])
        //sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperatur", par_sp_Farbtemperatur.toString)
        //createTimer(now.plusMillis(1000), [ | sendCommand(light_name, par_sp_Helligkeit.toString)]) 
        //createTimer(now.plusMillis(1500), [ | sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperatur", par_sp_Farbtemperatur.toString)])
        //createTimer(now.plusMillis(2000), [ | sendCommand(light_name, par_sp_Helligkeit.toString)]) 
    }

    else {
        if(Log_An) logWarn("MOTION", "Sensor Inaktiv")

        if(timers.get(raum_name) !== null){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Timer noch nicht vorhanden nicht OK")
            return;
        }

        var par_timeout = if(par_timeout_seconds.state instanceof DecimalType) (par_timeout_seconds.state as Number).intValue else 30
        if(Log_An) logWarn("MOTION", "AKTION AUS TIMER AKTIVIERT")
        timers.put(raum_name, createTimer(now.plusSeconds(par_timeout), [ |
            last_update_time.put(raum_name, now)
            last_update_type.put(raum_name, "AUTO")
            sendCommand(light_name, "OFF") // you can send ON/OFF to Dimmer Items
            if(Log_An) logWarn("MOTION", "AKTION AUS")
        ]))
    }
end


rule "Motion Cancel" //bei manuellem Eingriff
when
    Member of gMotion_Licht_Helligkeit changed
    or Member of gMotion_Licht_Farbtemperatur changed
then

//Raum bestimmen
val raum_name = triggeringItem.name.split("_").get(1)
if (Log_An) {logWarn("MOTIONCANCEL", raum_name)}
val new_State = triggeringItem.state as Number
val diff = (new_State) - (previousState as Number)
if(diff < 0.1 && diff>-0.1 && new_State != 0.0) {
    if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG Mindestaenderung Helligkeit nicht OK")}
    return;
}

//nur wenn letzter Befehl von Automatik
if (last_update_type.get(raum_name) === null || last_update_type.get(raum_name).contains("MANU")){
    if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG letzte Aenderung von Automatik nicht OK")}
    return;
}

//nur wenn letzter Befehl älter als 5 Sekunden
if (last_update_time.get(raum_name) !== null && now.minusSeconds(5).isBefore(last_update_time.get(raum_name))) {
    if (Log_An) {logWarn("MOTIONCANCEL","BEDINGUNG letzter Befehl alt genug nicht OK")}
    return;
}

//Aktion
//Timer stoppen, wenn aktiv
if (timers.get(raum_name) !== null){
    timers.get(raum_name)?.cancel()
    timers.remove(raum_name)
}
last_update_time.put(raum_name,now)
last_update_type.put(raum_name,"MANU")

if (Log_An) {logWarn("MOTIONCANCEL","MOTION UNTERBROCHEN")}

end

Motion.items

//Global
String Time_of_Day "Tageszeit"

//Overall Groups
Group: Dimmer:AVG gMotion_Licht_Helligkeit
Group: Dimmer:AVG gMotion_Licht_Farbtemperatur
Group: Switch:OR(ON,OFF) gMotion_Sensor_Bewegung
Group: Number:AVG gMotion_Sensor_Lux

//Flur
Group: Dimmer:AVG gMotion_Flur_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Flur_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Flur_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Flur_Sensor_Lux (gMotion_Sensor_Lux)

Number Motion_Flur_SP_Lux "Schwellwert Helligkeit Flur (lx)" (gMotion_SP_Lux)
Number Motion_Flur_SP_Timeout "Timeout Flur (s)" (gMotion_SP_Timeout)

Dimmer Motion_Flur_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Flur_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Flur_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Flur_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Flur_NACHMITTAG_Helligkeit "Helligkeit nachmittags"
Dimmer Motion_Flur_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Flur_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Flur_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Küche
Group: Dimmer:AVG gMotion_Kueche_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Kueche_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Kueche_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Kueche_Sensor_Lux (gMotion_Sensor_Lux)

Number Motion_Kueche_SP_Lux "Schwellwert Helligkeit Küche (lx)" (gMotion_SP_Lux)
Number Motion_Kueche_SP_Timeout "Timeout Küche (s)" (gMotion_SP_Timeout)

Dimmer Motion_Kueche_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Kueche_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Kueche_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Kueche_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Kueche_NACHMITTAG_Helligkeit "Helligkeit nachmittags"
Dimmer Motion_Kueche_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Kueche_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Kueche_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Bett
Group: Dimmer:AVG gMotion_Bett_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Bett_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Bett_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Bett_Sensor_Lux (gMotion_Sensor_Lux)

Number Motion_Bett_SP_Lux "Schwellwert Helligkeit Bett (lx)" (gMotion_SP_Lux)
Number Motion_Bett_SP_Timeout "Timeout Bett (s)" (gMotion_SP_Timeout)

Dimmer Motion_Bett_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Bett_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Bett_MITTAGS_Helligkeit "Helligkeit mittags" 
Dimmer Motion_Bett_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Bett_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Bett_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags" 
Dimmer Motion_Bett_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Bett_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Schlafzimmer
Group: Dimmer:AVG gMotion_Schlafzimmer_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Schlafzimmer_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Schlafzimmer_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Schlafzimmer_Sensor_Lux (gMotion_Sensor_Lux)
Group Motion_Schlafzimmer_SP_Helligkeit "Bewegungsmelder Schlafzimmer Helligkeit" (gMotion_SP_Helligkeit)
Group Motion_Schlafzimmer_SP_Farbtemperatur "Bewegungsmelder Schlafzimmer Farbtemperatur" (gMotion_SP_Farbtemperatur)

Number Motion_Schlafzimmer_SP_Lux "Schwellwert Helligkeit Schlafzimmer (lx)" (gMotion_SP_Lux)
Number Motion_Schlafzimmer_SP_Timeout "Timeout Schlafzimmer (s)" (gMotion_SP_Timeout)

Dimmer Motion_Schlafzimmer_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Schlafzimmer_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Schlafzimmer_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Schlafzimmer_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Schlafzimmer_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Schlafzimmer_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Schlafzimmer_NACHTS_Helligkeit "Helligkeit nachts" 
Dimmer Motion_Schlafzimmer_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Dekoration
Group: Dimmer:AVG gMotion_Dekoration_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Dekoration_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Dekoration_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Dekoration_Sensor_Lux (gMotion_Sensor_Lux)
Group Motion_Dekoration_SP_Helligkeit "Bewegungsmelder Dekoration Helligkeit" (gMotion_SP_Helligkeit)
Group Motion_Dekoration_SP_Farbtemperatur "Bewegungsmelder Dekoration Farbtemperatur" (gMotion_SP_Farbtemperatur)

Number Motion_Dekoration_SP_Lux "Schwellwert Helligkeit Dekoration (lx)" (gMotion_SP_Lux)
Number Motion_Dekoration_SP_Timeout "Timeout Dekoration (s)" (gMotion_SP_Timeout)

Dimmer Motion_Dekoration_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Dekoration_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Dekoration_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Dekoration_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Dekoration_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Dekoration_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Dekoration_NACHTS_Helligkeit "Helligkeit nachts" 
Dimmer Motion_Dekoration_NACHTS_Farbtemperatur "Farbtemperatur nachts"

For anyone interested:

my rule did not work as intended, because the hue binding is not very reliable with states. States did change to random values because they were reported while the lamp was dimming up, and like 2 Minutes later the right value was reported and the rule thought is was a manual change, which stopped the motion sensor from working.

I simplified many, many things, and it nearly works like it does before. Difference is, the override of the motion sensors does not happen automatically on change, because it does not work with hue. But i have the option to disable it per room in the sitemap, and a global setting, if the mode should switch to Automatic on lights off.
If i press my dimmer switches, they also change the mode to Manual.

Here are the updated versions:
items:

//Global
String Time_of_Day "Tageszeit [%s]"
Switch cMotion_Auto_Switch_if_Off "Bew. Meld. automatisch an bei Licht aus"

//Overall Groups
Group: Dimmer:AVG gMotion_Licht_Helligkeit
Group: Dimmer:AVG gMotion_Licht_Farbtemperatur
Group: Switch:OR(ON,OFF) gMotion_Sensor_Bewegung
Group: Number:AVG gMotion_Sensor_Lux
Group: Switch:OR(ON,OFF) gMotion_Mode //On=AUTO

//Flur
Group: Dimmer:AVG gMotion_Flur_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Flur_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Flur_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Flur_Sensor_Lux (gMotion_Sensor_Lux)

Switch gMotion_Flur_Mode (gMotion_Mode)

Number Motion_Flur_SP_Lux "Schwellwert Helligkeit Flur (lx)" (gMotion_SP_Lux)
Number Motion_Flur_SP_Timeout "Timeout Flur (s)" (gMotion_SP_Timeout)

Dimmer Motion_Flur_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Flur_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Flur_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Flur_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Flur_NACHMITTAG_Helligkeit "Helligkeit nachmittags"
Dimmer Motion_Flur_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Flur_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Flur_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Küche
Group: Dimmer:AVG gMotion_Kueche_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Kueche_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Kueche_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Kueche_Sensor_Lux (gMotion_Sensor_Lux)

Switch gMotion_Kueche_Mode (gMotion_Mode)

Number Motion_Kueche_SP_Lux "Schwellwert Helligkeit Küche (lx)" (gMotion_SP_Lux)
Number Motion_Kueche_SP_Timeout "Timeout Küche (s)" (gMotion_SP_Timeout)

Dimmer Motion_Kueche_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Kueche_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Kueche_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Kueche_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Kueche_NACHMITTAG_Helligkeit "Helligkeit nachmittags"
Dimmer Motion_Kueche_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Kueche_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Kueche_NACHTS_Farbtemperatur "Farbtemperatur nachts"


//Zusammenfassung ganzes Schlafzimmer
Group: Switch:OR(ON,OFF) gMotion_SchlafzimmerGesamt_Mode

//Bett
Group: Dimmer:AVG gMotion_Bett_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Bett_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Bett_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Bett_Sensor_Lux (gMotion_Sensor_Lux)

Switch gMotion_Bett_Mode (gMotion_Mode,gMotion_SchlafzimmerGesamt_Mode)

Number Motion_Bett_SP_Lux "Schwellwert Helligkeit Bett (lx)" (gMotion_SP_Lux)
Number Motion_Bett_SP_Timeout "Timeout Bett (s)" (gMotion_SP_Timeout)

Dimmer Motion_Bett_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Bett_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Bett_MITTAGS_Helligkeit "Helligkeit mittags" 
Dimmer Motion_Bett_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Bett_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Bett_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags" 
Dimmer Motion_Bett_NACHTS_Helligkeit "Helligkeit nachts"
Dimmer Motion_Bett_NACHTS_Farbtemperatur "Farbtemperatur nachts"



//Schlafzimmer
Group: Dimmer:AVG gMotion_Schlafzimmer_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Schlafzimmer_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Schlafzimmer_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Schlafzimmer_Sensor_Lux (gMotion_Sensor_Lux)

Switch gMotion_Schlafzimmer_Mode (gMotion_Mode,gMotion_SchlafzimmerGesamt_Mode)

Number Motion_Schlafzimmer_SP_Lux "Schwellwert Helligkeit Schlafzimmer (lx)" (gMotion_SP_Lux)
Number Motion_Schlafzimmer_SP_Timeout "Timeout Schlafzimmer (s)" (gMotion_SP_Timeout)

Dimmer Motion_Schlafzimmer_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Schlafzimmer_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Schlafzimmer_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Schlafzimmer_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Schlafzimmer_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Schlafzimmer_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Schlafzimmer_NACHTS_Helligkeit "Helligkeit nachts" 
Dimmer Motion_Schlafzimmer_NACHTS_Farbtemperatur "Farbtemperatur nachts"

//Dekoration
Group: Dimmer:AVG gMotion_Dekoration_Licht_Helligkeit (gMotion_Licht_Helligkeit)
Group: Dimmer:AVG gMotion_Dekoration_Licht_Farbtemperatur (gMotion_Licht_Farbtemperatur)
Group: Switch:OR(ON,OFF) gMotion_Dekoration_Sensor_Bewegung (gMotion_Sensor_Bewegung)
Group: Number:AVG gMotion_Dekoration_Sensor_Lux (gMotion_Sensor_Lux)

Switch gMotion_Dekoration_Mode (gMotion_Mode)

Number Motion_Dekoration_SP_Lux "Schwellwert Helligkeit Dekoration (lx)" (gMotion_SP_Lux)
Number Motion_Dekoration_SP_Timeout "Timeout Dekoration (s)" (gMotion_SP_Timeout)

Dimmer Motion_Dekoration_MORGENS_Helligkeit "Helligkeit morgens"
Dimmer Motion_Dekoration_MORGENS_Farbtemperatur "Farbtemperatur morgens"
Dimmer Motion_Dekoration_MITTAGS_Helligkeit "Helligkeit mittags"
Dimmer Motion_Dekoration_MITTAGS_Farbtemperatur "Farbtemperatur mittags"
Dimmer Motion_Dekoration_NACHMITTAG_Helligkeit "Helligkeit nachmittags" 
Dimmer Motion_Dekoration_NACHMITTAG_Farbtemperatur "Farbtemperatur nachmittags"
Dimmer Motion_Dekoration_NACHTS_Helligkeit "Helligkeit nachts" 
Dimmer Motion_Dekoration_NACHTS_Farbtemperatur "Farbtemperatur nachts"

rules:

import java.util.Hashtable
import org.eclipse.smarthome.model.script.ScriptServiceUtil

val Hashtable<String, Timer> timers = new Hashtable<String, Timer>()

val Log_An = true

rule "Time of Day"
when
    System started or
    Time cron "0 0 10 * * ? *" or
    Time cron "0 0 13 * * ? *" or
    Time cron "0 0 16 * * ? *" or
    Time cron "0 0 22 * * ? *"
then
    val Zeit_morgens = now.withTime(10, 0, 0, 0)
    val Zeit_mittags = now.withTime(13, 0, 0, 0)
    val Zeit_nachmittags = now.withTime(16, 0, 0, 0)
    val Zeit_nachts = now.withTime(22, 0, 0, 0)

    var curr_TOD = "UNKNOWN"
    switch now {
        case now.isAfter(Zeit_morgens) && now.isBefore(Zeit_mittags): curr_TOD = "MORGENS"
        case now.isAfter(Zeit_mittags) && now.isBefore(Zeit_nachmittags): curr_TOD = "MITTAGS"
        case now.isAfter(Zeit_nachmittags) && now.isBefore(Zeit_nachts): curr_TOD = "NACHMITTAG"
        default: curr_TOD = "NACHTS"
    }

    if(Time_of_Day.state.toString != curr_TOD){
        logInfo("TOD", "Transitioning time of day to " + curr_TOD)
        Time_of_Day.postUpdate(curr_TOD)
    }
end

rule "Motion"
when
    Member of gMotion_Sensor_Bewegung changed
then
    // Raum bestimmen
    val raum_name = triggeringItem.name.split("_").get(1)
    if(Log_An) logWarn("MOTION", raum_name)

    val current_Mode = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Mode")    
   
    // Motion sensor changed to ON
    if(triggeringItem.state == ON){

        // Parameter
        val par_lux_threshold = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Lux")
        val bright_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Helligkeit")
        val par_sp_Helligkeit = if(bright_item === null) 0 else bright_item.state as Number
        val temp_item = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_"+Time_of_Day.state.toString+"_Farbtemperatur")
        val par_sp_Farbtemperatur = if(temp_item === null) 60 else temp_item.state as Number

        if(Log_An) logWarn("MOTION", "Sensor Aktiv")
        // Cancel the timer if it exists
        logWarn("MOTION", raum_name)
        if (timers.get(raum_name) !== null){
            timers.get(raum_name)?.cancel()
            timers.remove(raum_name)
        }
        // Exit wenn Licht an
        val light_Helligkeit = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Licht_Helligkeit")
        if(light_Helligkeit.state as Number >= 0.1) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Licht an nicht OK")
            return;
        }

        //Licht ist aus, wir wechseln zur Automatik wenn das Licht aus ist.
        if (current_Mode.state == OFF){
            //nur wenn aktiv 
            if (cMotion_Auto_Switch_if_Off.state == OFF) return;
            sendCommand("gMotion_"+raum_name+"_Mode","ON")
        }

        val lux_sensor = ScriptServiceUtil.getItemRegistry.getItem("gMotion_"+raum_name+"_Sensor_Lux")
        val cur_lux = if(lux_sensor.state instanceof DecimalType) lux_sensor.state as Number else 1000.0
        val SP_lux = if(par_lux_threshold.state instanceof DecimalType) par_lux_threshold.state as Number else 0.0
        // Check if the room is already too bright
        if(cur_lux > SP_lux) {
            if(Log_An) logWarn("MOTION", "BEDINGUNG Helligkeit nicht OK")
            return;
        }

        // Check that the target Helligkeit is high enough
        if(par_sp_Helligkeit <= 0.1){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Sensor Sollhelligkeit > 0 nicht OK")
            return;
        }

        // Command the light
        createTimer(now.plusMillis(100), [ | 
		Thread::sleep(100)
        sendCommand("gMotion_"+raum_name+"_Licht_Helligkeit", par_sp_Helligkeit.toString)])

        createTimer(now.plusMillis(1000), [ | 
		Thread::sleep(100)
        sendCommand("gMotion_"+raum_name+"_Licht_Farbtemperatur", par_sp_Farbtemperatur.toString)])

    }

    else {
        if(Log_An) logWarn("MOTION", "Sensor Inaktiv")

        if(timers.get(raum_name) !== null){
            if(Log_An) logWarn("MOTION", "BEDINGUNG Timer noch nicht vorhanden nicht OK")
            return;
        }

        //wenn Modus Manuell, dann return
        if(current_Mode.state == OFF) return;

        //Parameter
        val par_timeout_seconds = ScriptServiceUtil.getItemRegistry.getItem("Motion_"+raum_name+"_SP_Timeout")
        var par_timeout = if(par_timeout_seconds.state instanceof DecimalType) (par_timeout_seconds.state as Number).intValue else 30
        if(Log_An) logWarn("MOTION", "AKTION AUS TIMER AKTIVIERT")
        timers.put(raum_name, createTimer(now.plusSeconds(par_timeout), [ |
			Thread::sleep(100)
            sendCommand("gMotion_"+raum_name+"_Licht_Helligkeit", "OFF") 
			Thread::sleep(500)
            sendCommand("gMotion_"+raum_name+"_Licht_Helligkeit", "OFF") 
            if(Log_An) logWarn("MOTION", "AKTION AUS")
        ]))
    }
end


rule "Motion Mode" //bei Moduswechsel zu Manual Timer löschen
when
    Member of gMotion_Mode changed
then

//Raum bestimmen
val raum_name = triggeringItem.name.split("_").get(1)
if (Log_An) {logWarn("MOTIONMODE", raum_name)}

//Mode auf AUTO gewechselt
if (triggeringItem.state == OFF && timers.get(raum_name) !== null){
        if (Log_An) {logWarn("MOTIONMODE","Manueller Modus gewählt, Timer wird gelöscht")}
        timers.get(raum_name)?.cancel()
        timers.remove(raum_name)
}
end```