Hi,
I know the title isn’t very helpful, but I know what I want to achieve, I am obviously just not capable of putting it into code.
I have a switch item “swSUNISUP”
Switch swSUNISUP "Sun is Up"
It want this to toggle OFF, when the sun is down or its dark outside.
It’s change in state triggers lights - these rules work.
Problem:
I have a illuminance sensor, telling me how dark it is in the living room.
If a certain elevation is surpassed by the sun, or a certain illuminance is reached, the swSUNISUP should switch to either ON or OFF.
My rule works and swSUNISUP changes to OFF, when limits are reached.
Unfortunately the lights in the living room switch on (what I want) which means the illuminance in the living room rises which again triggers the rule and swSUNISUP changes to ON and the lights switch off again.
How can I solve this ?
Here is my rule
rule "HUE - SET swSUNISUP"
when
Item Elevation changed or
Item MYWALLPANEL_LIGHT changed
then
// RUN ONLY IF SUN IS ALREADY UP
if (swSUNISUP.state != OFF)
{
if ((Elevation.state <= ELEVATION_LIMIT) || MYWALLPANEL_LIGHT.averageSince(now.minusMinutes(10), "influxdb") <= 12)
{
swSUNISUP.sendCommand(OFF)
logInfo("hue.rules","SET swSUNISUP OFF (LIMIT: "+ELEVATION_LIMIT+" / "+5*ELEVATION_LIMIT+"; CURRENT ELEVATION: "+Elevation.state+")")
}
}
// RUN ONLY IF SUN IS DOWN
else if (swSUNISUP.state != ON)
{
if ((Elevation.state > ELEVATION_LIMIT) && MYWALLPANEL_LIGHT.averageSince(now.minusMinutes(10), "influxdb") >= 20)
{
swSUNISUP.sendCommand(ON)
gHUE_BEDROOM.sendCommand(OFF)
gHUE_OFFICE.sendCommand(OFF)
gHUE_KITCHEN.sendCommand(OFF)
gHUE_LV_SIDELAMPS.sendCommand(OFF)
gHUE_AMBIENT.sendCommand(OFF)
gHUE_LV_TV.sendCommand(OFF)
gHUE_LV_LIGHTBAR.sendCommand(OFF)
gHUE_LIGHTSTRIPS.sendCommand(OFF)
logInfo("hue.rules","SET swSUNISUP ON (LIMIT: "+ELEVATION_LIMIT+" / "+5*ELEVATION_LIMIT+" ; CURRENT ELEVATION: "+Elevation.state+")")
}
}
end
Thanks
FYI: I am good in overthinking things, so don’t surprised if my rule is overly complicated
I got something like this, but 4 states (morning, day, evening, night) and use a state machine to prevent your issue. Keep the state in an item or cache. And now use the state AND your sensor for a change of state. So if it is night and the light sensor is more than a value, change the state to morning. If a minute later it’s a bit darker it won’t change again, because the state has become morning and a different condition applies. In my case, it waits for a lot of light to change the state to day…
The actual script is a bit more complicated. Since I use the result for a lot of things it has backup conditions using the astro binding and time. If you’re interested, I added the code.
//##settings##
var scriptName="zon_op_onder";//scriptname is used in logging
var debugMode=true;//log debug as info (easier than changing loglevel in karaf)
var treshold=5000;//treshold for sunset/sunrise (above/below this value)
var tresholdDay=treshold*10;//treshold for day
var tresholdNight=treshold/5;//treshold for night
//init
console.info(scriptName+"script started");
var now = time.ZonedDateTime.now();
var noon = now.withHour(12).withMinute(0);
var light=Number.parseInt(items.getItem("luchtkwaliteit_light2").state);
console.log(now);
var sunUpStart=time.toZDT(zdt(items.getItem("Sun_Daylight_Start").state)).minusMinutes(60);
var sunUp=time.toZDT(zdt(items.getItem("Sun_Daylight_Start").state));
var sunUpEnd=time.toZDT(zdt(items.getItem("Sun_Daylight_Start").state)).plusMinutes(60);
var sunDownStart=time.toZDT(zdt(items.getItem("Sun_Daylight_End").state)).minusMinutes(60);
var sunDown=time.toZDT(zdt(items.getItem("Sun_Daylight_End").state));
var sunDownEnd=time.toZDT(zdt(items.getItem("Sun_Daylight_End").state));
var dayMode=getAddItem("Sun","Daymode");
var mode=dayMode.state;
//create cache items
if (!isAvailable(this.lastSunRise)){
//init cache var
this.lastSunRise=-1;
this.lastSunSet=-1;
//reset detection
mode=1;
}
debug("light="+light+" set="+lastSunSet+" rise="+lastSunRise+" daymode="+mode);
//detect sunrise/day/sunset/night. To prevent flipping of states it uses a 'simple state machine' around the mode that can only advance
var oldMode=mode;
if (mode==1 && light>treshold && now.isAfter(sunUpStart) && now.isBefore(sunUp)){
//night, between rise time and light above treshold. So sunrise
lastSunRise=now.dayOfYear();
mode=2;
console.info("sunrise registered");
} else if (mode==1 && now.isAfter(sunUp) && lastSunRise!=now.dayOfYear()){
//night, safeguard. It should be morning. Don't detect on same day, else when sun is down at 23:00 it will premature start the next day
lastSunRise=now.dayOfYear();
mode=2;
console.info("sunrise registered (time!)");
} else if (mode==2 && light>tresholdDay && now.isAfter(sunUp) && now.isBefore(sunUpEnd)){
//morning, light above treshold. So day
mode=3;
console.info("day registered");
} else if (mode==2 && now.isAfter(sunUpEnd)){
//morning, safeguard. It should be day
mode=3;
console.info("day registered (time!)");
} else if (mode==3 && light<treshold && now.isAfter(sunDownStart) && now.isBefore(sunDown)){
//day, sunset not registered, and light below treshold. So sunset
lastSunSet=now.dayOfYear();
console.info("sunset registered");
mode=4;
} else if (mode==3 && now.isAfter(sunDown)){
//day, safeguard. Sunset should have started
lastSunSet=now.dayOfYear();
console.info("sunset registered (time!)");
mode=4;
} else if (mode==4 && light<tresholdNight && now.isAfter(sunDown) && now.isBefore(sunDownEnd)){
//evening, light below treshold. Night starts
mode=1;
console.info("night registered");
} else if (mode==4 && now.isAfter(sunDownEnd) ){
//evening, safeguard. Should be night
mode=1;
console.info("night registered (time!)");
}
//adjust state when changed
if (mode!=dayMode.state){
dayMode.sendCommand(mode);
}
debug("light="+light+" set="+lastSunSet+" rise="+lastSunRise+" daymode="+mode);
//done
console.info(scriptName+" done in "+ (-now.getMillisFromNow())+" millisec");
I think you’re muddying things up by making an item called “sun is up” be affected by illuminance too. This makes your code logic convoluted and harder to understand.
I would suggest that an item called “sun is up” should be purely about the sun’s position. Separate the illumination into another item.
Then you can apply a boolean logic using the two as well as the current state of the light to come to your final desired state.
In my own rules, instead of using a “sun is up” item, I simply use Sun_Elevation and in my code I would check Sun_Elevation.state > 0 to indicate that the sun is up and vice versa.
I can use it in a rule that needs to trigger at dawn or dusk, I can check for Sun_Elevation between -5 and 5 for example.
@jimtng has what I consider the correct answer. Because of the lights the amount of illuminace in the room is independent from the position of the sun. So use the elevation or angle Channels of the Astro Thing to track whether the sun is up or not.
If you have any logic that needs to know about both the sun position and the illuminance in the room, you can check both Items instead of trying to combine the two into one.
For example, in your case the rule that turns on the light can trigger on the Elevation and the light sensor. Then based on both decide when to turn on/off the light.
But ultimately, based on my experience, trying to control lights with a light sensor in the room where the lights are located is is complicated, error prone and ultimately an exercise in futility. Virtual Solar Light Sensor [4.0.0.0;4.9.9.9] is easier and more reliable, if you can’t put a light sensor outside.
Even though it’s an XY Problem in this case, there are ways you can disable a rule.
Check when an Item was last updated and if it’s too soon ignore the event and do nothing in the rule.
Set a timestamp when the rule runs and do nothing if it’s too soon.
Set a timer and as long as the timer exists do nothing in the rule.
After the rule runs, disable the rule (not available in Rules DSL). In another rule, at a fixed time or based on some event reenable the rule.
The list above is a little vague because the details about the specific problem will drive the solution.
Thanks folks for your input.
An illumination sensor, measuring the outside light would definitely be more reasonable. Problem is though, living in a city, it is never really dark outside
I’ll tinker a little more, working with your ideas.
Even in a city, it’s going to be dark enough that you need to turn on the lights. Otherwise you wouldn’t need the lights in the first place. It’s just a matter of finding the ambient light level at which you need to turn on the lights. Your value will be significantly higher than mine on the outskirts of a city at 7100 ft elevation. But the value will still be the same for you, whether it’s dark because the sun has gone down or because it became cloudy. You just need to find that value.
Thanks folks,
I never noticed (or rather looked into) Astro Binding’s channels.
I’ve implemented DAYLIGHT as a trigger and I’ll see how well this works out.
You can also post updates to the relevant Items using the developer sidebar, API explorer, karaf console, or my favorite through the -Scratchpad- script. This is a great way to test out time based stuff or rare events without needing to wait around. If you don’t have a -Scratchpad- Script, you can create it through the developer sidebar.
The only thing I had to take into consideration is the fact that the sun phase has a state “NOON”.
The item switches from “DAYLIGHT” to “NOON” back to “DAYLIGHT” which of course, caused my lights to come on at “NOON”
But that was an easy fix.