*SOLVED* Preventing ventilation from "jojo'ing" between levels

Hello all,
I’m using a rule to set the ventilation at different levels according to the humiddity in the bathroom.
The only problem i’m facing is that i don’t know how to prevent it from switching between high and medium contineusly when it is at the tipping point.
The rule i have now is:

rule "Automatic ventilation"
when
 Item Multi_Shower_Humidity changed
then
//Define threshold for fan activation as the maximum higher value of bathroom absolute humidity
var double dTreshholdSetHigh = 3.8
var double dTreshholdSetMed = 3.6
var double dTreshholdSetLow = 3.4

//take humidity and temperature bathroom
var Number nShowerHum = Multi_Shower_Humidity.state as DecimalType
var Number nShowerTemp = Multi_Shower_Temperature.state as DecimalType
var Double dShowerHum = nShowerHum.doubleValue()
var Double dShowerTemp = nShowerTemp.doubleValue()
logInfo("rules", "Variable type and Value d2Hum: " + dShowerHum.getClass().getName() + " " + dShowerHum)
logInfo("rules", "Variable type and Value d2Temp: " + dShowerTemp.getClass().getName() + " " + dShowerTemp)

var Double dShowerAbsHum = (6.112 * ((17.67 * dShowerTemp)/(dShowerTemp + 243.5)) * dShowerHum * 2.1674 ) / (273.15 + dShowerTemp)
logInfo("rules", "Calculated absolute humidity 2: " + dShowerAbsHum)

//Get the hour to see if automatic ventilation should override the manual setting
var Number hour = now.getHourOfDay

//compare the difference between humity levels and decide if the fan should be activated
if ((Switch_Fan_Living_Manual.state == ON) && ((hour >= 22) || (hour <= 7)))
{
    logInfo ("rules", "Ventilation in night mode")
}
else
{
    if (Switch_Fan_Living_Manual.state == ON)
    {
        Switch_Fan_Living_Manual.sendCommand(OFF)
        logInfo ("rules", "Ventilation set to automatic")
    } else {
        logInfo ("rules", "Manual override already turned off")
    }
    if (((dShowerAbsHum) > dTreshholdSetMed) && ((dShowerAbsHum) < dTreshholdSetHigh))
    {
        if (Dimmer_House_Fan.state == 45)
        {
        logInfo("rules", "Ventilation already at Medium speed")
        } else {        
            logInfo("rules", "Automatic switching ventilation to Medium")
            Dimmer_House_Fan.sendCommand(45)
        }
    }        
    else if ((dShowerAbsHum) > dTreshholdSetHigh)
    {
    if (Dimmer_House_Fan.state == 75)
        {
            logInfo("rules", "Ventilation already at High speed")
        } else {
            logInfo("rules", "Automatic switching ventilation to High")
        Dimmer_House_Fan.sendCommand(75)
        }
    }
    else if ((dShowerAbsHum) < dTreshholdSetLow)
    {
        if (Dimmer_House_Fan.state == 15)
        {
            logInfo("rules", "Ventilation already at Low Speed")
        } else {
            logInfo("rules", "Automatic switching ventilation to Low")
            Dimmer_House_Fan.sendCommand(15)
        }
    }
}
end

the rule is based on the rule of somebody else’s work.
i know i can add a timer to wait, but that should only fire when the fan goes lower (from high to medium but not vice-versa).
Any help would be appreciated!

By using a higher value when changing to the higher mode and using a lower value on the say back .

Something like:

if (Dimmer_House_Fan.state == 75)
{
if (dShowerAbsHum<dTreshholdSetHigh-1)
{
Dimmer_House_Fan.sendCommand(45)
}
}
else if (Dimmer_House_Fan.state == 45)
{
if (dShowerAbsHum>dTreshholdSetHigh)
{
Dimmer_House_Fan.sendCommand(75)
}
else if (dShowerAbsHum<dTreshholdSetMedium-1)
{
Dimmer_House_Fan.sendCommand(15)
}
}
else if (Dimmer_House_Fan.state == 15)
{
if (dShowerAbsHum>dTreshholdSetMedium)
{
Dimmer_House_Fan.sendCommand(45)
}
}

You play around with the value to subtract from the threshold in order to get the desired behaviour.

Sorry for the bad indenting, typing on my smartphone!

Opus’s suggestion is called hysteresis and is the standard approach to solving this sort of problem. At a high level you are creating a “dead range” where no change takes place between the high and the low. So if the humidity is high and drops below your threshold, it must drop a full percent (or whatever works best) below the threshold before the vent turns OFF. But if the vent is OFF and the humidity hits the threshold it turns the vent ON, leaving a tiny range between threshold-1 and threshold where no action is taken.

The range needs to be large enough that it covers the bouncing above and below the threshold.

1 Like

Thanks for the input! I’ll change the rule accordingly.
I’ll just need to figure out the threshold before switching down. The 1 in the suggestion is that a procentual value? Or do I need to use for example -0.2?

Use what ever value makes sense based on the jitteryness of the sensor. Usually 1% (since this is a humidity sensor 1 = 1% humidity) is a safe value, but it all depends on the behavior of that specific sensor.

Thanks alot!
Got it working great now. Set the value to 0.2 because it’s based on absolute humidity as a decimal value rather than relative humidity as a percentual value. The complete code I’ve pasted below in case someone else would like to use it.

rule "Automatic ventilation"
when
 Item Multi_Shower_Humidity changed
then
//Define threshold for fan activation as the maximum higher value of bathroom absolute humidity
var double dTreshholdSetMax = 5.0
var double dTreshholdSetHigh = 4.6
var double dTreshholdSetMed = 4.2
var double dTreshholdSetLow = 3.9

//take humidity and temperature bathroom
var Number nShowerHum = Multi_Shower_Humidity.state as DecimalType
var Number nShowerTemp = Multi_Shower_Temperature.state as DecimalType
var Double dShowerHum = nShowerHum.doubleValue()
var Double dShowerTemp = nShowerTemp.doubleValue()
logInfo("rules", "Variable type and Value d2Hum: " + dShowerHum.getClass().getName() + " " + dShowerHum)
logInfo("rules", "Variable type and Value d2Temp: " + dShowerTemp.getClass().getName() + " " + dShowerTemp)

var Double dShowerAbsHum = (6.112 * ((17.67 * dShowerTemp)/(dShowerTemp + 243.5)) * dShowerHum * 2.1674 ) / (273.15 + dShowerTemp)
logInfo("rules", "Calculated absolute humidity 2: " + dShowerAbsHum)

//Get the hour to see if automatic ventilation should override the manual setting
var Number hour = now.getHourOfDay

//compare the difference between humity levels and decide if the fan should be activated
if ((Switch_Fan_Living_Manual.state == ON) && ((hour >= 22) || (hour <= 7)))
{
    logInfo ("rules", "Ventilation in night mode")
}
else
{
    if (Switch_Fan_Living_Manual.state == ON)
    {
        Switch_Fan_Living_Manual.sendCommand(OFF)
        logInfo ("rules", "Ventilation set to automatic")
    } else {
        // logInfo used for checking the current state.
        logInfo ("rules", "Manual override already turned off")
        if (Dimmer_House_Fan.state == 95)
        {
            if ((dShowerAbsHum) < dTreshholdSetHigh -0.2)
            {
                logInfo("rules", "Setting ventilation to High")
                Dimmer_House_Fan.sendCommand(75)
            }
        }
        else if (Dimmer_House_Fan.state == 75)
        {
	        if ((dShowerAbsHum) > dTreshholdSetMax)
            {
                logInfo("rules", "Setting ventilation to Max")
                Dimmer_House_Fan.sendCommand(95)
            }
            else if ((dShowerAbsHum) < dTreshholdSetHigh -0.2)
	        {
                logInfo("rules", "Setting ventilation to Medium")
		        Dimmer_House_Fan.sendCommand(45)
	        }
        }
        else if (Dimmer_House_Fan.state == 45)
        {
            if ((dShowerAbsHum) > dTreshholdSetHigh)
            {
                logInfo("rules", "Setting ventilation to High")
                Dimmer_House_Fan.sendCommand(75)
            }
            else if ((dShowerAbsHum) < dTreshholdSetLow -0.2)
            {
                logInfo("rules", "Setting ventilation to Low")
                Dimmer_House_Fan.sendCommand(20)
            }
        } 
        else if (Dimmer_House_Fan.state == 20)
        {
            if ((dShowerAbsHum) > dTreshholdSetMed)
    	    {
                logInfo("rules", "Setting ventilation to Medium")
    		    Dimmer_House_Fan.sendCommand(45)
    	    }
        }
    }
}
end

1 Like