I created (based on forum inspiration here and there) the following rule that works fine:
rule "Check lights"
when Item Lights received update
then
Lights.members.forEach[light |
// Only create a Timer if there isn’t one already
var isOn = false
if (light.type == “Dimmer”)
isOn = (light.state > 0)
else
isOn = (light.state == ON)
if ( isOn == true && lightTimers.get(light.name) == null )
{
logInfo(“xxx”, "START timer for "+ light.name)
lightTimers.put(light.name, createTimer(now.plusMinutes(60), [|
var isStillOn = false
if (light.type == “Dimmer”)
isStillOn = (light.state > 0)
else
isStillOn = (light.state == ON)
if (isStillOn) {
var msgTxt = light.name + " is ON for too long "
logInfo(“xxx”, msgTxt)
notifyMyAndroid(“ALARME LUMIERE”, msgTxt)
lightTimers.put(light.name, null) // remove the timer from the Hashmap
}
]))
} else {
if ( isOn == false && lightTimers.get(light.name) != null ) {
logInfo(“xxx”, "STOP timer for "+ light.name)
lightTimers.get(light.name).cancel
lightTimers.put(light.name, null) // remove the timer from the Hashmap
}
}
]
end
My problem is that I have a fix timer of 60 minutes for each light.
I would like to make it more accurate.
As I have quite a high number of light I wouldn’t like to hard code a logic for each light.
So my idea was to create a kind of control table with the light name as key and different allowed ON time depending on different criteria.
For example a table like
Column 1 : light name
Column 2 : Allowed ON time during the night
Column 3 : Allowed ON time during the day
My question is what would be the most elegant way to implement such a table (or any equivalent) in a rule?
It is really difficult to read code when it is not properly formatted.
I recommend:
To apply this Design Pattern you would create a Number Item for each Light named in such a way as to easily construct the Number Item’s name given its associated Light Item. Put these number Items into a Group and use the code example to get a reference to the Number Item associated with a given Light.
The only part that is not addressed by the design pattern above is how to bootstrap the Number Items. To do this create a System started rule that populates the Number Items with an initial value. If you are using persistence with restoreOnStartup you can eliminate this rule after it runs the first time.
An advantage with this approach is, should you choose to, you can put the Number Items on your sitemap with a Setpoint or Slider and adjust the times without editing your rules.
This addresses part of your problem. The second part of your problem is determining whether the light is allowed on at night and/or during the day.
You can solve this part of the problem the same way, with associated Items. But I would solve it a different way, with Groups.
Create a Group for each of the time periods you care about. in your example you would have a gNightLights group and a gDayLights group.
Add each light to the appropriate Group or Groups.
I recommend tracking your time of day using the Time of Day Design Pattern and make sure the value of TimeOfDay matches what you use in your Group names.
Now, before turning on a light you just need to:
if(light.groupNames.contains("g"+TimeOfDay.state.toString+"Lights")) {
// its OK to turn on the light
}
Thanks.
Sorry for the code Here it is again in case anyone interested
rule "Check lights"
when Item Lights received update
then
Lights.members.forEach[light |
// Only create a Timer if there isn't one already
var isOn = false
if (light.type == "Dimmer")
isOn = (light.state > 0)
else
isOn = (light.state == ON)
if ( isOn == true && lightTimers.get(light.name) == null )
{
logInfo("xxx", "START timer for "+ light.name)
lightTimers.put(light.name, createTimer(now.plusMinutes(60), [|
var isStillOn = false
if (light.type == "Dimmer")
isStillOn = (light.state > 0)
else
isStillOn = (light.state == ON)
if (isStillOn) {
var msgTxt = light.name + " is ON for too long"
logInfo("xxx", msgTxt)
notifyMyAndroid("ALARM", msgTxt)
lightTimers.put(light.name, null) // remove the timer from the Hashmap
}
]))
} else {
if ( isOn == false && lightTimers.get(light.name) != null ) {
logInfo("xxx", "STOP timer for "+ light.name)
lightTimers.get(light.name).cancel
lightTimers.put(light.name, null) // remove the timer from the Hashmap
}
}
]
end
The control of the duration looks like an elegant way, this will create quite a number of items. Maybe I will have to revise my naming convention
But my understanding of the solution is that I will then have only one duration allowed per light.
It might be sufficient but I was thinking more about different duration allowed depending on context.
I already have an astro binding that give me the period of the day and also some lightness sensors to control during the day if it is allowed or not to switch on lights. I may also combine it with the weather (but this is kind of the same info of the sensors one).
Thanks for the tips this is already giving quite some things to think and work on.