Need help with illumination sensor rule

I have an illumination sensor that I use to control when lights come on and switch off. I’m using it in quite a basic way, which is where my downfall is likely to be. Not being great at coding, I’m at a lose as to how to solve an unforeseen issue with my present code.

The basics of the issue is that because I run the below rule every time the illumination sensor reports a change I get my lights switching on and off seemingly randomly. The reason being that when it starts to get dark in the evening the light level dips and switches on the lights, but also brights up again slightly and therefore switches the lights off once again.

What I think I need is a way to buffer when I switch the lights on or off. So I’m looking for suggestions or ideas how I can solve this issue.

rule "Lights"
when
        Item Porch_ST815_Lux_Level changed
then
	if(now.getHourOfDay < 9 || Time_Of_Day.state == "MORNING") return;
	if(Porch_ST815_Lux_Level.state > 200) return;
	if(Porch_ST815_Lux_Level.state > 150) {
		gLiving_Room_Lights.sendCommand(OFF)
                logInfo("org.openhab", "Living Room: Lights Off. TV Status is unknown. Lux Level @ " + Porch_ST815_Lux_Level.state)
	} else if(Porch_ST815_Lux_Level.state > 130 && Living_Room_TV_Power.state == ON) {
		Living_Room_Floor_Lamp_Dimmer.sendCommand(55)
		Living_Room_Table_Lamp_Dimmer.sendCommand(55)
                LivingRoom_Twig_Lights_Switch.sendCommand(ON)
                logInfo("org.openhab", "Living Room: Lights On. TV Status is On. Lux Level @ " + Porch_ST815_Lux_Level.state)
	} else if(Porch_ST815_Lux_Level.state > 115 && Living_Room_TV_Power.state == ON) {
		Living_Room_Floor_Lamp_Dimmer.sendCommand(60)
		Living_Room_Table_Lamp_Dimmer.sendCommand(60)
                logInfo("org.openhab", "Living Room: Lights On. TV Status is On. Lux Level @ " + Porch_ST815_Lux_Level.state)
	} else if(Porch_ST815_Lux_Level.state > 100 && Living_Room_TV_Power.state == ON) {
                Living_Room_Floor_Lamp_Dimmer.sendCommand(65)
                Living_Room_Table_Lamp_Dimmer.sendCommand(65)
                Kitchen_Bloom_Lamp_Dimmer.sendCommand(100)
                logInfo("org.openhab", "Living Room: Lights On. TV Status is On. Lux Level @ " + Porch_ST815_Lux_Level.state)
	} else if(Porch_ST815_Lux_Level.state < 100 && Living_Room_TV_Power.state == ON) {
                Living_Room_Floor_Lamp_Dimmer.sendCommand(70)
                Living_Room_Table_Lamp_Dimmer.sendCommand(100)
                logInfo("org.openhab", "Living Room: Lights On. TV Status is On. Lux Level @ " + Porch_ST815_Lux_Level.state)
        } else if(Porch_ST815_Lux_Level.state < 100 && Living_Room_TV_Power.state == OFF) {
                Living_Room_Floor_Lamp_Dimmer.sendCommand(65)
                Living_Room_Table_Lamp_Dimmer.sendCommand(65)
                Kitchen_Bloom_Lamp_Dimmer.sendCommand(100)
                logInfo("org.openhab", "Living Room: Lights On but the TV is Off. Lux Level @ " + Porch_ST815_Lux_Level.state)
        }
end

I think you have to use hysteresis to omit bouncing up and down. Your version:

< 200 && > 150 -> OFF
<=150 && > 130 -> ON (with distinct level)

so, if the light reaches 150, it will switch on immediately, but if only the slightest part over 150, it will switch off. Tthat is true for all borders. Instead, you should define some sort of window where nothing happens, like this:

< 200 && > 150 -> OFF
<=140 && > 130 -> ON (with distinct level)
<=120 && > 110 -> ON (with other distinct level)
this way, there will be a part where nothing happens.

Another thing is, it would be better to check wether the light level is already reached. like this:

rule "Lights"
when
    Item Porch_ST815_Lux_Level changed
then
    if(now.getHourOfDay < 9 || Time_Of_Day.state == "MORNING") return;

    var Number nFloor
    var Number nTable
    var Number nBloom
    var Switch nTwig
    val Number nLevel = Porch_ST815_Lux_Level.state as Number // to save some space ;)

    if(nLevel > 200) return;

    logInfo("lights", "Living Room: TV Status is {}. Lux Level @ {}",Living_Room_TV_Power.state ,nLevel) 
    if(nLevel > 150) {
        nFloor = 0
        nTable = 0
        nBloom = 0
        nTwig = OFF
    } if(nLevel < 140 && nLevel > 130 && Living_Room_TV_Power.state == ON) {
        nFloor = 55
        nTable = 55
        nTwig = ON
    } if(nLevel < 125 && nLevel > 115 && Living_Room_TV_Power.state == ON) {
        nFloor = 60
        nTable = 60
    } if(nLevel < 110 && nLevel > 100 && Living_Room_TV_Power.state == ON) {
        nFloor = 65
        nTable = 65
        nBloom = 100
    } if(nLevel < 95) { 
        if(Living_Room_TV_Power.state == ON) {
            nFloor = 70
            nTable = 100
        } else {
            nFloor = 65
            nTable = 65
            nBloom = 100
        }
    }
    logInfo("lights","Living Room: Lights " + if(nFloor > 0) "ON" else "OFF")
    if(nFloor instanceof Number)
        if(nFloor != (Living_Room_Floor_Lamp_Dimmer.state as Number))
            Living_Room_Floor_Lamp_Dimmer.sendCommand(nFloor)
    if(nTable instanceof Number)
        if(nTable != (Living_Room_Table_Lamp_Dimmer.state as Number))
            Living_Room_Table_Lamp_Dimmer.sendCommand(nTable)
    if(nBloom instanceof Number)
        if(nBloom != (Kitchen_Bloom_Lamp_Dimmer..state as Number))
            Kitchen_Bloom_Lamp_Dimmer..sendCommand(nBloom)
    if(nTwig == ON || nTwig == OFF)
        if(nTwig != LivingRoom_Twig_Lights_Switch.state)
            LivingRoom_Twig_Lights_Switch.sendCommand(nTwig)
end

By using vars, there is only one sendCommand per Item in the rule. The additional if clause is because sometimes not all lights get fired. The var status stays null as long as no value is set. this is tested by instanceof Number

2 Likes

Thanks for the reply. I’m always grateful to someone who looks at my code and shows me a better way to do things.

I’ll see if your suggested changes help.

Regards,

Garry