Need help with rule (Velux windows controlled from outside temp, alarm and Lumiance), now optimizing

I just changed the rule to use the temperature sensor in our living room insted.

This is what happened, (had to set lux to less than 0, because its dark outside now).

2018-08-17 22:08:38.764 [ome.event.ItemCommandEvent] - Item 'dummy1' received command OFF
2018-08-17 22:08:38.773 [vent.ItemStateChangedEvent] - dummy1 changed from ON to OFF
2018-08-17 22:08:43.184 [INFO ] [pse.smarthome.model.script.StuenTemp] - 25.00
2018-08-17 22:08:43.190 [INFO ] [g.eclipse.smarthome.model.script.Lux] - 0
2018-08-17 22:08:43.195 [INFO ] [eclipse.smarthome.model.script.Alarm] - OFF
2018-08-17 22:08:43.201 [INFO ] [eclipse.smarthome.model.script.debug] - First table clause
2018-08-17 22:08:43.208 [INFO ] [eclipse.smarthome.model.script.debug] - Choose VeluxAlleAaben100
2018-08-17 22:08:43.220 [INFO ] [ipse.smarthome.model.script.skylight] - Sending ON command to VeluxAlleAaben100 because Temp = 25.00  Lux = 0 and Alarm = OFF

2018-08-17 22:08:43.226 [ome.event.ItemCommandEvent] - Item 'VeluxAlleAaben100' received command ON
2018-08-17 22:08:47.303 [INFO ] [ding.velux.bridge.VeluxBridgeExecute] - execute() finished successfully.

This looks right… And while writing this message… This happened:

2018-08-17 22:11:05.473 [vent.ItemStateChangedEvent] - stue_Temperature changed from 25.00 to 24.90
2018-08-17 22:11:05.504 [INFO ] [pse.smarthome.model.script.StuenTemp] - 24.90
2018-08-17 22:11:05.510 [INFO ] [g.eclipse.smarthome.model.script.Lux] - 0
2018-08-17 22:11:05.514 [INFO ] [eclipse.smarthome.model.script.Alarm] - OFF
2018-08-17 22:11:05.522 [INFO ] [eclipse.smarthome.model.script.debug] - First table clause
2018-08-17 22:11:05.532 [INFO ] [eclipse.smarthome.model.script.debug] - Choose VeluxAlleAaben75
2018-08-17 22:11:05.548 [INFO ] [ipse.smarthome.model.script.skylight] - Sending ON command to VeluxAlleAaben75 because Temp = 24.90  Lux = 0 and Alarm = OFF
2018-08-17 22:11:05.553 [ome.event.ItemCommandEvent] - Item 'VeluxAlleAaben75' received command ON
2018-08-17 22:11:09.644 [INFO ] [ding.velux.bridge.VeluxBridgeExecute] - execute() finished successfully.

VeluxAlleAaben75… Due to temperature beeing below 25 degrees. This seems to be working just as it should…

So I´m pretty sure, using the Netamo value is NOT a good idea.

EDIT:
just to make sure… I changed the criteria of Lux to < 30. And then triggered the rule manually again… This happened:

2018-08-17 22:16:47.147 [ome.event.ItemCommandEvent] - Item 'dummy1' received command ON
2018-08-17 22:16:47.171 [vent.ItemStateChangedEvent] - dummy1 changed from OFF to ON
2018-08-17 22:16:49.338 [INFO ] [pse.smarthome.model.script.StuenTemp] - 24.70
2018-08-17 22:16:49.344 [INFO ] [g.eclipse.smarthome.model.script.Lux] - 0
2018-08-17 22:16:49.348 [INFO ] [eclipse.smarthome.model.script.Alarm] - OFF
2018-08-17 22:16:49.353 [INFO ] [eclipse.smarthome.model.script.debug] - Second table clause
2018-08-17 22:16:49.369 [INFO ] [ipse.smarthome.model.script.skylight] - Sending ON command to VeluxAlleVent because Temp = 24.70  Lux = 0 and Alarm = OFF
2018-08-17 22:16:49.374 [ome.event.ItemCommandEvent] - Item 'VeluxAlleVent' received command ON
2018-08-17 22:16:53.484 [INFO ] [ding.velux.bridge.VeluxBridgeExecute] - execute() finished successfully.

I´m convinced… Don´t use Netamo temperature values in a rule.

No:

logInfo("NetamoTemp", NetamoUdendoersTemperature.state.toString)
logInfo("fTemp",fTemp.toString)

This will show if the value from Netamo is cast properly into the fTemp variable

Ahh ofcouse…
I was thinking, NetamoUdendoersTemperature or fTemp, it´s the same… But thats exactly what you wanted to make sure by logging fTemp and not NetamoUdendoersTemperature only…

However, I´m pretty sure its the same, and the problems with the rule using the Netamo item, is due to this not beeing a number only. (as stated above).
But to make sure, I´ll change the rule back to using the Netamo sensor. Then we´ll know for sure.

Here is the result.

2018-08-18 00:26:50.471 [ome.event.ItemCommandEvent] - Item 'dummy1' received command ON
2018-08-18 00:26:50.477 [vent.ItemStateChangedEvent] - dummy1 changed from OFF to ON

2018-08-18 00:26:53.925 [INFO ] [clipse.smarthome.model.script.Netamo] - 14.69999980926513671875 ℃
2018-08-18 00:26:53.932 [INFO ] [g.eclipse.smarthome.model.script.Lux] - 0
2018-08-18 00:26:53.937 [INFO ] [eclipse.smarthome.model.script.Alarm] - OFF
2018-08-18 00:26:53.941 [INFO ] [eclipse.smarthome.model.script.fTemp] - 14.69999980926513671875 ℃
2018-08-18 00:26:53.947 [INFO ] [eclipse.smarthome.model.script.debug] - Second table clause
2018-08-18 00:26:53.964 [INFO ] [ipse.smarthome.model.script.skylight] - Sending ON command to VeluxAlleVent because Temp = 14.69999980926513671875 ℃  Lux = 0 and Alarm = OFF
2018-08-18 00:26:53.970 [ome.event.ItemCommandEvent] - Item 'VeluxAlleVent' received command ON
2018-08-18 00:26:58.046 [INFO ] [ding.velux.bridge.VeluxBridgeExecute] - execute() finished successfully.

The fTemp Number also carries the Unit °C hence your problems:
This should work:
Note the use of : |"°C"

rule "Automatic control of all skylight windows"
when
    Item NetamoUdendoersTemperature changed or
    Item Node13_SensorLuminance changed or
    Item alarm_totalalarm changed or
    Item dummy1 changed
then
    // Exit the rule when there is nothing to do
    if(Override.state == ON) return;
    if(alarm_totalalarm.state instanceof Switch ) return;
    if(!(Node13_SensorLuminance.state instanceof Number)) return;
    if(!(NetamoUdendoersTemperature.state instanceof Number)) return;

    // Calculate which velux to send the ON command to
    val Number fTemp = NetamoUdendoersTemperature.state as Number
    val Number lux = Node13_SensorLuminance.state as Number
    val alarm = alarm_totalalarm.state
    var velux = VeluxAlleLuk

logInfo("NetamoTemp", NetamoUdendoersTemperature)
logInfo("Lux", Node13_SensorLuminance)
logInfo("Alarm", alarm_totalalarm)


    // Third table
    if(alarm == ON) {
        logInfo("debug", "Third table clause")
        velux = if(fTemp >= 22|"°C") VeluxAlleVent else VeluxAlleLuk
    }

    // Second table, we already know alarm isn't ON so we don't have to test it for OFF here
    else if(lux < 100){ 
        logInfo("debug", "Second table clause")
        velux = if(fTemp >= 22|"°C") VeluxAlleVent else VeluxAlleLuk
    }

    // First table, we know that alarm isn't ON and we know lux >= 100 so we don't have to test for it here
        else {
        logInfo("debug", "First table clause")
        switch fTemp {
            case fTemp >= 25|"°C": velux = VeluxAlleAaben100
            case fTemp >= 24|"°C": velux = VeluxAlleAaben75
            case fTemp >= 23|"°C": velux = VeluxAlleAaben50
            case fTemp >= 22|"°C": velux = VeluxAlleVent
            default: velux = VeluxAlleLuk
        }
        logInfo("debug", "Choose " + velux.name)
    }

    // Send the command
	logInfo("skylight", "Sending ON command to " + velux.name + " because Temp = " + NetamoUdendoersTemperature.state + "  Lux = " + Node13_SensorLuminance.state + " and Alarm = " + alarm_totalalarm.state)
    velux.sendCommand(ON)
end
1 Like

There is good advice on that thread:

And it sure did work… :+1:

2018-08-18 00:39:52.568 [ome.event.ItemCommandEvent] - Item 'dummy1' received command OFF
2018-08-18 00:39:52.577 [vent.ItemStateChangedEvent] - dummy1 changed from ON to OFF

2018-08-18 00:39:54.676 [INFO ] [clipse.smarthome.model.script.Netamo] - 14.6000003814697265625 ℃
2018-08-18 00:39:54.680 [INFO ] [g.eclipse.smarthome.model.script.Lux] - 0
2018-08-18 00:39:54.684 [INFO ] [eclipse.smarthome.model.script.Alarm] - OFF
2018-08-18 00:39:54.687 [INFO ] [eclipse.smarthome.model.script.fTemp] - 14.6000003814697265625 ℃
2018-08-18 00:39:54.692 [INFO ] [eclipse.smarthome.model.script.debug] - Second table clause
2018-08-18 00:39:54.705 [INFO ] [ipse.smarthome.model.script.skylight] - Sending ON command to VeluxAlleLuk because Temp = 14.6000003814697265625 ℃  Lux = 0 and Alarm = OFF

2018-08-18 00:39:54.709 [ome.event.ItemCommandEvent] - Item 'VeluxAlleLuk' received command ON
2018-08-18 00:39:58.966 [INFO ] [ding.velux.bridge.VeluxBridgeExecute] - execute() finished successfully.

All windows closed (VeluxAlleLuk) due to outside temperature beeing below 22 degrees.
So I guess it´s safe to use Netamo anyway. One just have to remember to exclude this highly annoying |“°C” part.

Or you could do:

    val Number fTemp = (NetamoUdendoersTemperature.state as QuantityType<Number>).doubleValue

That should get rid of the unit in the number and your rule is as before without the |"°C"

13 days since I started this thread, and now you telling me :-:grin:

Anyway, it has been 13 hard days, but 13 highly interesting days as well. I have learned alot thanks to you, @rlkoshak and @Udo_Hartmann . Great thank you guys!
Now I´m ready for the next challenge, to run our in-house Nilan ventilation system all automatic from values of Humidity, Alarm, outside Temperature, inside temperature and… I can probably think of plenty more :rofl:

I think I´ll keep it as is for now… (probably untill tomorrow :slight_smile: ) Always nice to have alternative ways of doing things.

I´m reopening the thread again, as I need some advice/help to optimize the code…

Even though things has been working quite nice, there is a few disadvantages using the netamo outdoor sensor, cause it polls every 10 minutes. In this time a year, when the wind outside is abit cold, on a very sunny day, inside will get hot, window will open, and it will then cool down the inside very fast.
Within the 10 minutes poll, the heating will start to heat up the house, before the windows close again…

There are a few reasons for this cause… Mainly self-created…

  1. All 8 windows open at the same time. This leaves a very fast cooling , which is not optimal, when…
  2. The temprature poll periode is 10 minutes.
  3. Wind direction and wind speed has an hughe influence as well.

Some new options and thoughts:

  1. After a few new changes to my system, I can now controle each window individually 100%.

  2. I can make use of an inside temperature sensor insted. Infact I have individual temperature sensors in all rooms in the house. After thinking about it, I believe it would make more sense to use the inside temperatures to controle the windows, rather than the outside temperature. There is a small issue to this situation. The rooms inwhere the skylight windows are located, are open rooms, like kitchen, and kitchen-allroom (dinnerroom) and living room. Because they´re open, the individual temperatures is almost the same. But it depends on the sun direction, time of year, as well as outside temperature.
    In the livingroom there a two windows (beside the skylight) pointing NorthEast and doors SouthWest, which means livingroom gets quite hot when the sun is shining.
    Kitchen got NorthEast skylights as well as windows.
    Dinnerroom got NorthWest pointing skylights and doors.
    (Look at the floorplan below).

  3. I have installed openweathermap binding a couple of days ago. With this I should be able to make use of wind direction as well as wind speed. One note though, I think the wind direction is a bit unstable. But if it can get stable, I would assume this would be a great optimize using windspeed as well.

Floorplan with redmarks for rooms and green mark each skylights:

Now I wonder how I could optimze this. I know it will probably end up with a very very complex rule way beyond my knwoledge, and would require alot of fiddling with values and sensors. But I believe, with some help, it should be possible :slight_smile: Question is, where to start.
One thing I know I need for sure, thats a hysterises for the temperature when I change to use the inside sensors. The room (IHC) sensors changes very quickly and often goes x.90 - x.80 - x.90 etc. So there is a desperate need of somekind of hysterieses which needs to be build into the rule, even as it is today.
But I wonder if it would make sense to split the rule into one rule for each room?
Any other suggestions, thoughts etc are highly welcome… This project is probably going to take some time, I think.

I’d say not “instead” but in addition. Why not control the windows opening based on the temperature differential? For example, if the inside temp is 2 degrees warmer than the outside temperature and the inside temp is above your inside target temp open the window. Then if the inside temp, which presumably get’s polled more frequently than every ten minutes, falls below the inside target temp close the window. If it’s supported, you could even vary how far the window opens based on the temperature differential so, for example, if the differential is half a degree only open the window a little but if the differential is three degrees open the window all the way.

If you do this I’m not certain you need to deal with the wind speed/direction directly because the fact that the room cools to the target temp is what you really care about. However, you might want to limit how open the windows go if the wind speed is above a certain speed.

I do something along these lines for controlling the house fan. I only have central forced air heating (one heater for the whole house) and no air conditioning. In the summer the temp in the basement is much cooler than the temp in the main foor or top floor. So I can turn on the heater’s fan to bring that cold air up to the rest of the house and cool eveything down about 5 degrees F.

All my temp sensors are members of Group:Number:Temperature:AVG gIndoorTemps.
All my temp sensors are also members of Group:Number:Temperature:MAX gMaxTemp.
The sensors in the basement and the main floor are members of Group:Number:Temperature:MIN LowerFloorsTemps.
The sensors on the top floor and the main floor are members of Group:Number:Temperature:MAX UpperFloorsTemps.

rule "Turn on the fan when necessary"
when
        Member of gIndoorTemps received update
then
    // TODO, treat each temp sensor as it's own thermostat and control the fan and heat
    // based on min and max thresholds for each

    // Wait at least five minutes before changing the fan state after the last change
    if(vNest_Fan_LastChange.state != NULL && now.isBefore(new DateTime(vNest_Fan_LastChange.state.toString))) return;

    // Get the target and upper and lower temps
    val target = aNest_TargetTemp.state as Number
    val lower = LowerFloorsTemps.state as Number
    val upper = UpperFloorsTemps.state as Number

    // Determine if the fan should be on or off: upper is higher than lower and the target and it is warm outside
    // 1 degree as a buffer for hysteresis
    val diff = upper - lower
    var String fanState = "Stay"
    if(diff >= 0 && upper > target && vWeather_Temp.state > 70) fanState = "ON"
    else if(upper < target - 1) fanState = "OFF"

    // Change the fan state
    if(fanState != "Stay" && aNest_Fan.state.toString != fanState) {
        logInfo(logName, "Setting the house fan to " + fanState)
        aNest_Fan.sendCommand(fanState)
        vNest_Fan_LastChange.postUpdate(new DateTimeType)
    }
end

Thus, if the temperature outside is lower than 70 degrees F I assume it’s late fall to early spring and we don’t want the house fan bringing that cold air up. But if it is warm outside and the upper floors are warmer than the lower floors and the upper temp is warmer than the target we turn on the house fan.

Your logic will be a little more complex because you need to do this for each individual window, but it will be more of the same. You want to check that the inside is warmer than the target and the outside temps. If it is open the windows for the space that temp sensor covers. When the inside temp falls below the target temp, close the window.

I wouldn’t. The logic is the same for each room for the most part. It’d be better to build it all as one Rule. But start by building it for just one room. Then expand the Rule to support multiple rooms. Coding is an iterative process. No one writes a Rule in one sitting. Gradually build it up.

Ahh. I never actually had the thought of use both oppotunities…

This is one of the new changes in the KLF200 binding and the latest firmware for the KLF200 I installed a few days ago. I can now control each window from 0% - 100% without using specific scenes.

About the differential - Sometimes in summer time it get very hot here in Denmark. So the temperature outside will be way above the needed inside temperature. Normally, if we had a airconditioner, this would leave all windows closed. But because we havn´t (yet), and there is no sun screen on the windows, there could still be a need of opening windows, just to get som fresh wind inside. I guess this suits best using an override then, or?

I´ll have to study your code closer, I think I get the idea, but it´s a bit confusing regard the hystereises, which is highly required in my situation when changing to use the inside sensores.

Perhaps. Perhaps you just need different behavior in the summer so you just need an if(it’s summer) do this else do that.

Hysteresis isn’t hard. It’s just a buffer, let’s say one degree, between when you turn something ON and turn something OFF. In the code above it’s implemented by subtracting 1 from the target in the else if.

1.    val diff = upper - lower
2.     var String fanState = "Stay"
3.     if(diff >= 0 && upper > target && vWeather_Temp.state > 70) fanState = "ON"
4.     else if(upper < target - 1) fanState = "OFF"

This is the core of the logic including the hysteresis.

  1. Calculate the temperature differential
  2. Default the new fan state to “Stay” meaning we won’t change the fan. If it’s already on we leave it on. If it’s already off we leave it off.
  3. Should the fan be ON? Only if there is a positive differential (i.e. it’s warmer upstairs than down stairs), AND it’s warmer upstairs than the target temp AND it’s warm outside.
  4. Should the fan be OFF? Only if the temperature is one degree lower than the target temp. This is the hysteresis.

This leaves a one degree buffer between when the fan turns ON and the fan turns OFF.

Hmm, well I guess that could be an option as well…

This is why I desperate need a hystereises when using my inside temperature sensors:

2019-04-25 18:29:56.528 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.10 to 24.20
2019-04-25 18:31:19.843 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:31:25.185 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:31:36.286 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:31:52.870 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:32:48.249 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:33:49.058 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:33:54.702 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:34:16.826 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:34:27.938 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:35:06.566 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:35:17.754 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:35:23.230 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:35:28.754 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30
2019-04-25 18:35:34.232 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.30 to 24.20
2019-04-25 18:35:39.864 [vent.ItemStateChangedEvent] - koekken_Temperature changed from 24.20 to 24.30

Notice the changes in this short time periode… Without a hystereises, the windows will never stop moving :slight_smile:

EVERYONE needs hysteresis. I don’t understand why you are still trying to prove this.

But like I demonstrate above, it’s not hard. There is nothing special about it. You just have three conditions.

  1. Open the window
  2. Do nothing
  3. Close the window

2 is the hysteresis.

I can make it more explicit in my code above.

val diff = upper - lower
val String fanState = "ERROR"

if(diff >= 0 && upper > target && vWeather_Temp.state > 70) fanState = "ON"
else if(upper < target && upper >= target - 1) fanState = "Stay" // hysteresis
else if (upper < target - 1) fanState = "OFF"

Coding++

Brillant statement Rich. Love it.

1 Like

In your first code above you´ce got this target. What exactly is that?
I dont see the aNest_TargetTemp item anywhere else in the code?

Second… the != what does it means? (different from equal?).

I think I understand the hystereises… But I suspect I should have a hystereises on both sides of the target, or? (if target is 23 degress, and hystereis should be 0.3 then I assume the hystereise should between 27.7 and 23.3 or?

! means NOT so != means not equal to.

Then you only understand it partly. You define the hysteresis yourself as you like.
So I’d you only want to turn on the heating if the temperature is below 18 degrees and only turn it off if it is above 23 degrees, that is also a definition that includes hysteresis.

I didn’t provide the full list of Items. Given that we are calling .state on it one can assume that it’s an Item. Because we are casting the state to a Number we can assume that it is either a Dimmer Item or a Number Item. Given the name of the Item is “TargetTemp” I assumed it would be clear that this is the Item that represents the target temperature I want to keep the house to.

Where you put the “do nothing range” is up to you. You can put it on the “high” side, the “low” side, or split it between the two. I put it on the low side (target - 1).

Just a quick side note…
Is it possible to reuse val from another rule (another rule file)? (I´m trying to start off from my main rule, but there are val´s and var´s inside. So I wonder if I could reuse these for Alarm and Lux sensors).