Help! Code clean up - Light Ramping, string concatenation, val or var, member of group

Hi Guys,

I need a little bit (a lot) of help with a rule i’m trying to write.

I’ve pulled rules from the following places and edited to suit, not i’m trying to combine them into 1 rule that does On/Off light ramping of Philips Hue and TimeOfDay dependent light timeouts. I also would like to try and use MemberOf so I don’t have to have a rule for each room

Progressive Dimmer Rules
Time Of Day Design Pattern
[SOLVED] Help with a light timer rule

Basically I want to have a minimal, easy to edit and (if I have to) re-use rule with:

  • Physical Sensor Motion event trigger a Virtual Item if a Motion Override Virtual Item is NOT active.
  • Motion Virtual Item will then trigger the light ramping up for a particular light(s).
  • Depending on Time of Day a Timeout value is set before turning off the light(s)
  • Subsequent Motion events will retrigger Motion virtual item to reset timer
  • on expiry of timeout and no motion, lights will ramp down

current rules file in full is around 200 lines for each room so trying to compress to hopefully speed up running of rules in general

Thanks in advance for your help and advice!

.items file

// PHYSICAL ITEMS AND GROUPS
Switch							GFKitchen_Motion						"Kitchen Motion Sensor"								<motion>				(GFKitchen, gMotion)																			["MotionDetector", "Switchable"]		{channel="zwave:device:xxxxxxx:node20:alarm_motion"}
Dimmer							GFKitchen_LightDimmer					"Kitchen Light Dimmer"								<light>					(GFKitchen, gLight, gDimmers, gKitchen)															["Lighting", "Switchable"]				{channel="hue:0220:xxxxxxxxx:14:brightness"}

Group:Dimmer:AVG				gDimmersKitchen							"Light"												<light>					(Home)																							["Lighting", "Dimmable"]
Group:Switch:OR(ON, OFF)		gMotion									"Motion Sensor"										<motion>				(Home)																							["MotionDetector", "Switchable"]


// VIRTUAL/STRING ITEMS
Group							gMotionTimerVirtualItems				"Group for Motion Timer VI"
String							timeoutTimeOfDay						"Current Time of Day [MAP:%s]"						<tod>
Switch							ViMotionTimer_KitchenLight				"VI Motion Timer Kitchen Light"						<light>					(gMotionTimerVirtualItems)																		["Lighting", "Switchable"]
String							TimeOfDay								"Current Time of Day [MAP:%s]"						<tod>

var Timer RampUpTimer = null
var Timer RampDownTimer = null
var Timer LightsTimer = null

val int timeoutmillis_rampup = 1 * 150 // 15000 divided by 100 dim levels
var int dimLevel_up = 50
val int timeoutmillis_rampdown = 1 * 1200 // 1200000 divided by 100 dim levels
var int dimLevel_down = 100

val int timeoutMinutesMorning = 30 // choose an appropriate value
val int timeoutMinutesDay = 90 // choose an appropriate value
val int timeoutMinutesAfternoon = 30 // choose an appropriate value
val int timeoutMinutesEvening = 60 // choose an appropriate value
val int timeoutMinutesNight = 60 // choose an appropriate value
val int timeoutMinutesBed = 15 // choose an appropriate value

var timeoutMinutesTimeofDay = ""

rule "Get time of day and update timeoutTimeOfDay"
when
    Item TimeOfDay changed 
then
    timeoutTimeOfDay.sendCommand("timeoutMinutes" + TimeOfDay)
    logInfo("Timeout updater", "Time of Day Timeout Updated")
end

// THIS IS THE MAIN BIT OF CODE I'M STRUGGLING WITH (I KNOW IT'S INCOMPLETE), I WANT TO UPDATE var timeoutMinutesTimeOfDay WITH val int timeoutMinutesMorning/Day/Afternoon/Evening etc FOR THE ACTUAL MOTION SO I DON'T HAVE TO HAVE AN "ELSE IF" STATMENT FOR EACH TIME OF DAY //

rule "Match Value to Time of Day timeout"
when
    Item timeoutTimeOfDay changed
then
    if (timeoutTimeOfDay == "timeoutMinutesMorning") {
        timeoutMinutesTimeOfDay === timeoutMinutesMorning
    }


// RAMP RATES //

rule "Slowly Dim Up"
when
    Item ViMotionTimer_KitchenLight changed to ON
then
    if ((RampUpTimer === null) && (GFKitchen_LightDimmer != 100)) {
        RampUpTimer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
         GFKitchen_LightDimmer.sendCommand(dimLevel_up)
            if (dimLevel_up == 100) {
                RampUpTimer = null // cancel timer
            } else {
                RampDownTimer = null
                dimLevel_up = dimLevel_up + 1
                RampUpTimer.reschedule(now.plusMillis(timeoutmillis_rampup)) // reschedule timer is 1 * 150 mills
            }
        ])
    }
end

rule "Slowly Dim Down"
when
    Item ViMotionTimer_KitchenLight changed to OFF
then
    if (RampDownTimer === null) {
        RampDownTimer = createTimer(now.plusSeconds(0), [ |   //Starts immediately
            GFKitchen_LightDimmer.sendCommand(dimLevel_down)
            if ((dimLevel_down == 0) || (ViMotionTimer_KitchenLight === ON)) {
                RampDownTimer = null // cancel RampDownTimer
            } else {
                dimLevel_down = dimLevel_down - 1
                RampDownTimer.reschedule(now.plusMillis(timeoutmillis_rampdown)) // reschedule RampDownTimer is 1 * 1200 mills
            }
        ])
    }
end

// MOTION EVENT TO TRIGGER VIRTUAL ITEM AFTER CHECKING MOTION OVER RIDE STATUS, WILL CHANGE TO MEMBER OF WHEN I FIGURE OUT HOW TO DO THAT //

rule "ViMotionTimer_KitchenLight ON"
when
	Item GFKitchen_Motion  received update ON
then 
 	logInfo("VI_Motion_Override", "Received Motion Event, Checking Over-Ride Status...")
{  
	if (VI_Motion_Override.state === ON) { 
    	logInfo("VI_Motion_Override", "Lighting Motion Detection Over-Ride Active, nothing happens")
	}
	else {
			if (VI_Motion_Override.state === OFF)
			logInfo("VI_Motion_Override", "Lighting Motion Detection Over-Ride Disabled, Sending Command to Timer Item") 
			ViMotionTimer_KitchenLight.sendCommand(ON)
	}
}
end

// WHAT I WANT TO DO - CHECK TimeOfDay AND TIMEOUT FOR val int timeoutMinutes"TimeOfDay" BEFORE SENDING OFF COMMAND TO VIRTUAL ITEM //
// UNSURE OF THIS CODE PART WAY THROUGH EDITING //

rule "Motion Timer in the Kitchen"
when Item ViMotionTimer_KitchenLight received update ON
then
	logInfo("LightsTimer", "Checking Time Of Day to determine occupancy timer to start..")
    	logInfo("LightsTimer", "Time of Day is " + TimeOfDay)
    if((LightsTimer === null) && (TimeOfDay.state == "Morning")) {
    logInfo("LightsTimer", TimeOfDay + "Kitchen Light Timer Created")
        LightsTimer = createTimer(now.plusMinutes(timeoutMinutesMorning), [|
            ViMotionTimer_KitchenLight.sendCommand(OFF)
            LightsTimer = null
        ])
    }
    else {
    		if(TimeOfDay.state == "Morning") {
        		LightsTimer.reschedule(now.plusMinutes(timeoutMinutesMorning))
			logInfo("Kitchen Light Timer", "Kitchen Light Timer  Reset")
    }
}

// BELOW WORKS FINE// 

    if((LightsTimer === null) && (TimeOfDay.state == "Day")) {
	logInfo("Kitchen Light Timer", "Kitchen Light Timer Created")
        LightsTimer = createTimer(now.plusMinutes(timeoutMinutesDay), [|
            ViMotionTimer_KitchenLight.sendCommand(OFF)
            LightsTimer = null
        ])
    }
    else {
    		if(TimeOfDay.state == "Day") {
        		LightsTimer.reschedule(now.plusMinutes(timeoutMinutesDay))
			logInfo("Kitchen Light Timer", "Kitchen Light Timer Reset ")
    }
}

 // CODE REPEATS FOR EVENING, NIGHT AND BED - REMOVED FOR POST LENGTH //

end

Here is a example that does what you are describing and much more…

1 Like

Looks like my learning of RulesDSL is going to take a break while I learn Python!

Thank you for the link, love the explanations in the github docs

1 Like

This will simplify the installation…