Rule Clean up

I am look for suggestions on cleaning and optimizing the rules i am using.

             	
var Timer aquariumfeedtimer

rule "Aquarium Feed Mode"

	when
			Item  Aquarium_Feedmode changed from OFF to ON 
			
	            	            	
	             	sendNotification("brianllong@gmail.com", "Aquarium - Feed Mode Turning Pumps OFF")
	             	sendCommand(Aquarium_Powerhead, OFF)
	            	sendCommand(Aquarium_Wavemaker, OFF)
	             	
	            	aquariumfeedtimer = createTimer(now.plusMinutes(5)) [|
	            		sendNotification("brianllong@gmail.com",  "Aquarium - Feed Mode Turning Pumps ON")
	            		sendCommand(Aquarium_Powerhead, ON)
	            		sendCommand(Aquarium_Wavemaker, ON)
	            		sendCommand(Aquarium_Feedmode, OFF)
	            		
	            		aquariumfeedtimer.cancel()	
			]	
	end	

         	
rule "Aquarium Temperature - Fan control ON"

	when
	        Item Aquarium_Sump_Temp changed or
	        Item Aquarium_Sump_Temp received update 
	        
	then                    
	        if (Aquarium_Sump_Temp.state > 78.1 && Aquarium_Cooling.state == OFF) {

            		logInfo("AquariumSumpTemp: ","Aquarium Temperature, turning on fan")
                	sendCommand(Aquarium_Cooling, ON)
                
        	} 
		else if (Aquarium_Sump_Temp.state < 77.7 && Aquarium_Cooling.state == ON) {
            	
            		logInfo("AquariumSumpTemp: ","Aquarium Temperature, turning off fan")
               		sendCommand(Aquarium_Cooling, OFF)
   		}
	        
end
	             	

rule "Aquarium Temperature - Secondary Heater control"

	when
	        Item Aquarium_Sump_Temp changed or
	        Item Aquarium_Sump_Temp received update
	then                    
	        if (Aquarium_Sump_Temp.state < 77.3 && Aquarium_Heater_2.state == OFF && Aquarium_Manualmode.state == OFF) {

            		logInfo("AquariumSumpTemp: ","Turning on Secondary Aquarium Heater")
                	sendCommandAquarium_Heater_2, ON)
                
	        } 
		else if (Aquarium_Sump_Temp.state > 77.8 && Aquarium_Heater_2.state == ON && Aquarium_Manualmode.state == OFF) {
            		logInfo("AquariumSumpTemp: ","Turning off Secondary Aquarium Heater")
	                sendCommand(Aquarium_Heater_2, OFF)
        	}
	end


rule "Aquarium Temperature - Primary Heater control"

	when
	        Item Aquarium_Sump_Temp changed or
	        Item Aquarium_Sump_Temp received update
	then
	        if (Aquarium_Sump_Temp.state < 78 && Aquarium_Heater_1.state == OFF && Aquarium_Manualmode.state == OFF){
	               		logInfo("AquariumSumpTemp: ","Aquarium Temperature under Low, turning on Primary Heater")
	                	sendCommand(Aquarium_Heater_1, ON)
		} 
		else if Aquarium_Sump_Temp.state > 78.5 && Aquarium_Manualmode.state == OFF ) {
            		logInfo("AquariumSumpTemp: ","Aquarium Temperature to High, turning off All Heater")
	                	sendCommand(Aquarium_Heater_1, OFF)
	                	sendCommand(Aquarium_Heater_2, OFF)
		} 
	end

rule "Aquarium Temperature - Loft Fan control OFF"

	when
	        Item Aquarium_Sump_Temp changed or
	        Item Aquarium_Sump_Temp received update
	then
		if ( Aquarium_Sump_Temp.state < 76 && FF_Loft_Fan.state == ON ) {
	               		logInfo("AquariumSumpTemp: ","Aquarium Temperature under 76, turning off fan")
	                	sendCommand(FF_Loft_Fan, OFF)
		} 
	end


// Creates an item that stores the last update time of this item

rule "Records last Aquarim Sump Temp update time"

	when
		Item Aquarium_Sump_Temp received update
	then
		postUpdate(Aquarium_Sump_Temp_LastUpdate, new DateTimeType())
	end

rule "Records last Turtle Aquarium Water Temp update time"

	when
		Item Turtle_Aquarium_Water_Temp received update
	then
 		postUpdate(Turtle_Aquarium_Water_Temp_LastUpdate, new DateTimeType())
	end





var Timer GF_Kitchen_Motion_Timer = null
var Timer GF_Living_Room_Motion_Timer = null


rule "GF_Kitchen_Lights - Automation"
    when   
            Item GF_Kitchen_Motion changed from OFF to ON or
			Item remoteSensors_Kitchen_capability_occupancy changed from OFF to ON or
			Item ecobeetest changed
    then   
    	if (on_when_dark.state == ON  || GF_Kitchen_Luminance.state <= 15) {
            if(on_when_sleepstate.state == OFF) {
	            if(GF_Kitchen_Lights.state == 0) {
	            	if (GF_Kitchen_Motion_Timer == null){
		            	sendCommand(GF_Kitchen_Lights, 60)
		            	sendNotification("brianllong@gmail.com", "Kitchen - Motion Detected")
		            	logInfo("Kitchen", "Motion Detected")
		            	GF_Kitchen_Motion_Timer = createTimer(now.plusMinutes(15)) [|
		            		sendCommand(GF_Kitchen_Lights, OFF)
		            		GF_Kitchen_Motion_Timer.cancel()
		            		sendNotification("brianllong@gmail.com", "Kitchen- Motion Time out")
		            		logInfo("Kitchen", "Motion Time out")
		            	]
		            	
	            	} 
	            }else { 
            		GF_Kitchen_Motion_Timer.reschedule(now.plusMinutes(15))
            		sendNotification("brianllong@gmail.com", "Kitchen- Rescheduling Timer")
            		logInfo("Kitchen", "Rescheduling Timer")
            	}   
            }
 		}
 		
    end 
    
    rule "GF_Kitchen_Lights - Automation"
    when   
            Item GF_Kitchen_Lights received update OFF
            
    then 
    
    GF_Kitchen_Motion_Timer.cancel()
    
    end
    
 



rule "Bedroom Temp control"
when
    Item FF_MasterBedroom_Thermostat_TargetTemperature changed or
    Item FF_MasterBedroom_Thermostat_ThermostatMode changed or
    Item FF_MasterBedroom_Thermostat_CurrentTemp changed or
    Item FF_MasterBedroom_Thermostat_CurrentTemp received update 
then
        var Number setpoint = FF_MasterBedroom_Thermostat_TargetTemperature.state as DecimalType
        var Number hysteresis = 1 

        // get the current temperature in the Bedroom
       // var Number tempIn = MasterBedroomThermostatCurrentTemp.state as DecimalType
       	var Number tempIn = remoteSensors_Bedroom_capability_temperature.state as DecimalType
        
        if (FF_MasterBedroom_Thermostat_ThermostatMode.state =="OFF"){
        	if (FF_MasterBedroom_Thermostat_Control.state == ON)
                FF_MasterBedroom_Thermostat_Control.sendCommand(OFF);
        }
        
        if (tempIn < (setpoint - hysteresis) && FF_MasterBedroom_Thermostat_ThermostatMode.state =="HEAT") {
    	    // turn on the heat
            if (FF_MasterBedroom_Thermostat_Control.state == OFF)
                FF_MasterBedroom_Thermostat_Control.sendCommand(ON);
        } else if (tempIn >= setpoint  && FF_MasterBedroom_Thermostat_ThermostatMode.state =="HEAT") {
            // setpoint has been reached so switch off the heat
            if (FF_MasterBedroom_Thermostat_Control.state == ON)
                FF_MasterBedroom_Thermostat_Control.sendCommand(OFF);
        }
        
        if (tempIn > (setpoint + hysteresis) && FF_MasterBedroom_Thermostat_ThermostatMode.state =="COOL") {
    	    // turn on the heatpump
            if (FF_MasterBedroom_Thermostat_Control.state == OFF)
                FF_MasterBedroom_Thermostat_Control.sendCommand(ON);
        } else if (setpoint >= tempIn && FF_MasterBedroom_Thermostat_ThermostatMode.state =="COOL") {
            // setpoint has been reached so switch off the heat
            if (FF_MasterBedroom_Thermostat_Control.state == ON )
                FF_MasterBedroom_Thermostat_Control.sendCommand(OFF);
        }
        
    
end



var Timer Presence_timer = null

rule "Presence_AutoAway - Control"
	when
	        Item Presence_Master received update 
	        	        
	then
			                               
	             
	             
	            if (Presence_Auto_Away.state == ON && Presence_Master.state == OFF) {
	             	sendNotification("brianllong@gmail.com", "Presences - Starting Away Timer")
	            	Presence_timer = createTimer(now.plusMinutes(5)) [|
	            		sendNotification("brianllong@gmail.com", "Presences - Changing to Away")
						ecobeeResumeProgram("317488702664", true)
	             	 	//sendCommand(SamsungPower , ON)
	            		sendCommand (glights, OFF)
						sendCommand (gtvpower, OFF)
	            		Presence_timer.cancel()
						//Presence_timer = null
				]	
	             	 
	             	}
	             	
	              
	              else
	            	 
           		if (Presence_Auto_Away.state == ON && Presence_Master.state == ON) {
           			if (Presence_timer != null) {
           				Presence_timer.cancel()
           				
           				sendNotification("brianllong@gmail.com", "Presences - Cancelled Away Timer")
           			
           			}
      
		      		 } 
end


rule "Presence_Master - Control"
	when
	        Item Presence_Brian_Iphone_Macaddr received update or
	        Item Presence_Jen_Iphone_Macaddr received update  or
	        Item Presence_Ecobee_Master received update 	        
	then
			                               
	             if (Presence_Brian_Iphone_Macaddr.state == OFF && Presence_Jen_Iphone_Macaddr.state == OFF && Presence_Ecobee_Master.state == OFF) {
	             	sendCommand(Presence_Master , OFF)}
	              
	              else
	            	  if (Presence_Master.state == OFF) {sendCommand(Presence_Master , ON)} 
end



rule elevation
    when 
    Item astro_sun_local_position_elevation changed
    then
    	if(astro_sun_local_position_elevation.state >  0){
    		if(on_when_dark.state!=OFF){
    		//	logInfo("houseControl", "Sun is crossing the horizon, switching to daylight mode")
    			on_when_dark.sendCommand(OFF)
    		}
    	} else {
    		if(on_when_dark.state!=ON) {
    		//	logInfo("houseControl", "Sun is crossing the horizon, switching to night mode")
    			on_when_dark.sendCommand(ON)
    		}
    	}
    end
    
rule "sleepstate"
	when
	Item on_when_sleepstate received update ON
	then
		sendCommand (glights, OFF)
		sendCommand (gtvpower, OFF)
		
end

rule "Reset Sleepstate"
	when
	        Time cron "0 0 4 * * ?"
	then
	    sendCommand(on_when_sleepstate, OFF )
	end




rule "Resume Program 9PM for sleep "
    when   
            Time cron "0 5 21 * * ?"
    then   
            ecobeeResumeProgram("317433702664", true)
            logInfo("Cron Ecobee","EcoBee Resuming Program")
    end

Wow there are a lot of rules here.

Some basic suggestions:

  • It is redundant to trigger a rule on changed an received update. If you use received update the rule will trigger when the value changes too. Normally I would just use changed because if the temperature hasn’t actually changed you probably just want to keep doing what you were doing. However, since this automation has life or death implications I would recommend just using received update. That way if for some reason things get out of sync it won’t stay out of sync for as long.

  • Consider a single Temperature rule and combine all of the rules that trigger on Aquarium_Sump_Temp into one rule. This will centralize all your temp control logic and make it easier to see and understand what devices get turned on and when. This can be complicated logic so if you can get it all to fit on one screen it is easier to deal with. It also avoids unintended and unexpected interactions between the rules. Right now all of these rules will be running at the same time in an unpredictable order. If you forget that and set one device ON in one rule another may turn it OFF.

Then I’d move the actual setting and logging of the new state to a lambda to simplify your conditions.

NOTE: It is a good habit to use ItemName.sendCommand as opposed to sendCommand() as the former is much better able to handle conversions of data types.


val Functions$Function3 applyState = [SwitchItem sw, State newState, String name |
    if(sw.state != newState){
        logInfo("AquariumSumpTemp", "Acquarium Temperature, turning " + newState.toString.toLower + " the " + name)
        sw.sendCommand(newState)
]

rule "Aquarium Temperature"
when
    Item Aquarium_Sump_Temp received update
then
    // Mark the time of the update
    postUpdate(Aquarium_Sump_Temp_LastUpdate, new DateTimeType())

    // Fan
    if (Aquarium_Sump_Temp.state > 78.1) applyState .apply(Aquarium_Cooling, ON, "fan")
    else if(Aquarium_Sump_Temp.state < 77.7) applyState.apply(Aquarium_Cooling, OFF, "fan") 

    // Secondary Heater
    if (Aquarium_Sump_Temp.state < 77.3 && Aquarium_Manualmode.state == OFF) applyState.apply(Aquarium_Heater_2, ON, "Secondary Aquarium Heater")
    else if (Aquarium_Sump_Temp.state > 77.8 Aquarium_Manualmode.state == OFF) applyState.apply(Aquarium_Heater_2,OFF, "Secondary Aquarium Heater")

    // Primary Heater
    if (Aquarium_Sump_Temp.state < 78 Aquarium_Manualmode.state == OFF) applyState.apply(Aquarium_Heater_1, ON, "Primary Heater")
    else if (Aquarium_Sump_Temp.state > 78.5 && Aquarium_Manualmode.state == OFF ) {
        applyState.apply(
        logInfo("AquariumSumpTemp: ","Aquarium Temperature to High, turning off All Heater")
        Aquarium_Heater_1.sendCommand(OFF)
        Aquarium_Heater_2.sendCommandOFF)
    }

    // Loft Fan
    if ( Aquarium_Sump_Temp.state < 76) applyState.apply(FF_Loft_Fan, OFF, "loft fan")
end

That is as far as I got but I’m sure you can apply similar things to the rest of your rules. Also, look at the Design Patterns thread for additional Ideas.

2 Likes

Rich thank you again for the help. I haven’t dove into lambda yet but i can see how it simplify the rule

my only problem i cant seem to figure out is the LogInfo

logInfo(“AquariumSumpTemp”, "Acquarium Temperature, turning " + newState.toString.toLower + " the " + name)
sw.sendCommand(newState)

i believe something is wrong with the newState.toString.toLower but i can seem to find a solution. if i remove it it works well but if i leave it it hangs and provides

[ERROR] [.script.engine.ScriptExecutionThread] - Rule ‘Aquarium Temperature Control’: The name ‘.toString’ cannot be resolved to an item or type.

I just typed this stuff into the forum. It isn’t surprising there is a bug here and there.

If it logs just fine without the toString and.toLower, then just keep them out. That is really just a nice bit of formatting for the logs which really don’t matter a hill of beans functionally.

but it doesnt log with newstate at all

i was able to figure most out of it just the log state part

Do you get errors or just no log line?

Is the if conditional actually evaluating to true or are you not seeing the log statement because it is always evaluating to false?

If you just logInfo(“Aquarium”, newState) as the first line of the lambda what do you see in the logs?

I notice that if statement is missing a closing “}”. Did you add that in?

[ERROR] [.script.engine.ScriptExecutionThread] - Rule ‘Aquarium Temperature Control’: The name ‘.toString’ cannot be resolved to an item or type.

it appears to kick an error anytime i use newstate in loginfo.

val Functions$Function3 applyState = [SwitchItem sw, State newState, String name |
    if(sw.state != newState){
    	 
        //logInfo("AquariumSumpTemp", "Aquarium Temperature, turning " + newState.toString + " the " + name)
       // logInfo("AquariumSumpTemp", newState.toString)
        sw.sendCommand(newState)
    
        }
]

var Timer aquariumfeedtimer

rule "Aquarium Feed Mode"

	when
			Item  Aquarium_Feedmode changed from OFF to ON 
			
	            	            	
	             	sendNotification("brianllong@gmail.com", "Aquarium - Feed Mode Turning Pumps OFF")
	             	sendCommand(Aquarium_Powerhead, OFF)
	            	sendCommand(Aquarium_Wavemaker, OFF)
	             	
	            	aquariumfeedtimer = createTimer(now.plusMinutes(5)) [|
	            		sendNotification("brianllong@gmail.com",  "Aquarium - Feed Mode Turning Pumps ON")
	            		sendCommand(Aquarium_Powerhead, ON)
	            		sendCommand(Aquarium_Wavemaker, ON)
	            		sendCommand(Aquarium_Feedmode, OFF)
	            		
	            		aquariumfeedtimer.cancel()	
			]	
	end	
     	 



rule "Aquarium Temperature Control"

when
    Item Aquarium_Sump_Temp received update
then
    // Mark the time of the update
	postUpdate(Aquarium_Sump_Temp_LastUpdate, new DateTimeType())

    // Fan
	if (Aquarium_Sump_Temp.state > 78.1) applyState.apply(Aquarium_Cooling, ON, "fan")
	else if(Aquarium_Sump_Temp.state < 77.7) applyState.apply(Aquarium_Cooling, OFF, "fan") 
   
   // Secondary Heater
 	if (Aquarium_Sump_Temp.state < 77.3 && Aquarium_Manualmode.state == OFF && Aquarium_Heater_2.state != ON ) applyState.apply(Aquarium_Heater_2, ON, "Secondary Aquarium Heater")
	else if(Aquarium_Sump_Temp.state > 77.8 && Aquarium_Manualmode.state == OFF && Aquarium_Heater_2.state != OFF) applyState.apply(Aquarium_Heater_2, OFF, "Secondary Aquarium Heater")

     // Primary Heater
	if (Aquarium_Sump_Temp.state < 77.5 && Aquarium_Manualmode.state == OFF && Aquarium_Heater_1.state != ON) applyState.apply(Aquarium_Heater_1, ON, "Primary Aquarium Heater")
	else if(Aquarium_Sump_Temp.state >= 78 && Aquarium_Manualmode.state == OFF && Aquarium_Heater_1.state != OFF) applyState.apply(Aquarium_Heater_1, OFF, "Primary Aquarium Heater")
    
    // Loft Fan
    if (Aquarium_Sump_Temp.state > 79.1) applyState.apply(FF_Loft_Fan, ON, "loft fan")
	else if ( Aquarium_Sump_Temp.state < 76) applyState.apply(FF_Loft_Fan, OFF, "loft fan")
     
    
end

Try changing

[SwitchItem sw, State newState, String name

to

[SwitchItem sw, OnOffType newState, String name

For explanation for the curious, I forgot that State is an Interface, not a Class and therefore there is no toString method. At least that is my going theory. By switching to the more concrete OnOffType I can now access methods from the parent Object class (i.e. toString).