As this is a recurring question, I’m sharing my ruleset how I’ve setup automated shading using rollershutters and blinds.
Note it’s a full-blown setup that you will likely not need all the parts of. So take this as a starting point and remove and adapt the parts specific to your needs.
Sorry for all the German variable names. Some rainy day, maybe …
The code is definitely not ‘elegant’ and more repetitive and verbose than it would need to be efficient, but I prefer to have it this way as this isn’t on programming but on learning, adapting and to ease spotting errors.
Let me know the places where you need further explanation so I can enhance this documentation over time.
-
There’s a number of rollershutters and some venetian blinds (Raffstore or Jalousien in German) in my house.The latter allow for setting the lamella tilt angle, and all of my rollershutters and blinds are capable of driving to a particular percentage.
A hint to anyone using Fibaro FGRM actuators to operate their venetian blinds: deploy the 2.4M4 milestone or newer to get lamella tilt control to work.
The morning (eastern) side is exposed to sunlight in the morning hours from sunrise until about 12:45, and sun starts shining into the [after]noon (mostly southern) side windows at 10:15 until around 18:30 (6:30 PM).
There’s an outside multi sensor on each side of the house (ensure it’s water proof!) to track luminance and temperature. Placement has a large impact on measurements, that why there’s different thresholds they’re compared against. -
The fundamental idea behind this automation is that while the zombie rate among nerds is said to be high, you usually don’t want darkness but just protection from the heat. So I just shade as little as possible.
This is why I’ve built two zones (morning and noon/afternoon sides of the house) that are controlled independent from each other as the sun is moving around the house. There’s some overlap, but most of the time, one of the two sides is open. I’m also actually driving my shutters to around 35% only. This will block most direct sunrays but will allow for some light to enter. The ‘high’ protection level is to drive them to 75% which still allows for some lightray pass the spacing between lamellas.
For venetian blinds, I’ve implemented a two-stage shading algorithm: up to a lower luminance threshold, the blinds will be lowered but lamellas will be set to open. When the upper threshold is reached, they, too, will be closed.
You can and must adapt all of these parameters to your specific housing situation.
Yes, it’s far from being perfect, you need to change the code as not even all of the thresholds are changeable via items …
You should experiment with the core ‘shade?’ evaluation function to include those aspects that you feel to be most important to you. I’ve experimented with using temperature and cloudiness forecasts from the weather binding (unreliable), a UV value my sensor delivers (found that to always be 0, so decided I don’t need to check it, but if you happen to live in the Australian Outback … well ), various luminance levels and other stuff.
-
Shading is based on luminance (sunlight intensity) and temperature measured by the sensors.
The core evaluation function actually is this. Easy to understand for Germans I guess.var boolean Schutzbedarf_morgens = (Sonnenschutz.state == Modus_Ein) || ((now.millis > Verschattung_Anfang_morgens) && (now.millis < Verschattung_Ende_morgens) && ((hell_genug_morgens && zu_warm_morgens) || zu_hell_morgens))
Shading happens based on the moving average of the values the sensors are delivering. To flatten out peaks, configure them to deliver values often enough to fit into the time window or increase the window size. Remember to enable “everyMinute” persistence on these items so there’s at least one up to date value when averageSince() is calculated.
Both of these procedures are to compensate for peaks (and errors) in measurements to avoid constant UPs and DOWNs on cloudy days.
-
Sonnenschutzschaltung
is a global switch to enable/disable shading automatism.
Nachtschaltung
is a global switch enabled during nighttime only.
Tageslicht
is a global switch that is ON whenever there’s daylight. This is updated based on astro binding events.
Aussentemperatur_Hysterese_Sonnenschutz
is a variable to compensate for higher temperatures if you expose a sensor to direct sunlight instead of measuring the temperature in the shadows. You can’t have both, correct luminance and (shadow) temperature, in a single sensor.
Code update as of 07/20/19
items:Number Lux_Terrasse_morgens "Durchschnitt Ostseite aussen [%.0f lux]" <sun> (Sonnenschutz)
Number Lux_Terrasse_mittags "Durchschnitt Südseite aussen [%.0f lux]" <sun> (Sonnenschutz)
Number Lux_Wohnen_mittags "Durchschnitt Südseite innen [%.0f lux]" <sun> (Sonnenschutz)
Number Lux_Grenzwert_Sonnenschutz_morgens_niedrig "Schwellwert unten morgens [%d lux]" <sun> (Sonnenschutz,Einstellungen)
Number Lux_Grenzwert_Sonnenschutz_morgens_hoch "Schwellwert oben morgens [%d lux]" <sun> (Sonnenschutz,Einstellungen)
Number Lux_Grenzwert_Sonnenschutz_mittags_niedrig "Schwellwert unten mittags [%d lux]" <sun> (Sonnenschutz,Einstellungen)
Number Lux_Grenzwert_Sonnenschutz_mittags_hoch "Schwellwert oben mittags [%d lux]" <sun> (Sonnenschutz,Einstellungen)
Number UV_Grenzwert_Sonnenschutz "UV Schwellwert Sonnenschutz [UV index %.0f]" <sun> (Sonnenschutz,Einstellungen)
Number EWT_Zuheizung "EWT heizt unterhalb [%.1f °C]" <heating> (Lueftung,Einstellungen)
Number EWT_Kuehlung "EWT kühlt oberhalb [%.1f °C]" <climate> (Lueftung,Einstellungen)
Number Aussentemperatur_Grenzwert_Sonnenschutz "Schwellwert Sonnenschutz aussen [%.1f °C]" <temperature> (Sonnenschutz,Einstellungen)
Number Innentemperatur_Grenzwert_Sonnenschutz "Schwellwert Sonnenschutz innen [%.1f °C]" <temperature> (Sonnenschutz,Einstellungen)
Number Aussentemperatur_Hysterese_Sonnenschutz "Hysterese Sonnenschutz aussen [%.1f °C]" <temperature> (Sonnenschutz,Einstellungen)
Number Innentemperatur_Hysterese_Sonnenschutz "Hysterese Sonnenschutz innen [%.1f °C]" <temperature> (Sonnenschutz,Einstellungen)
Switch Sonnenschutz_Bianca "Sonnenschutz Bianca [MAP(yesno.map): %s]" <daylight> (EG_Bianca,Einstellungen)
Switch Sonnenschutzschaltung "Sonnenschutzschaltung [MAP(yesno.map): %s]" <blinds> (Einstellungen)
Number Sonnenschutz "Sonnenschutz [MAP(shading.map): %s]" <blinds>
rules:
val Number Rolladen_vollstaendig_geschlossen = 99
val Number Lamellen_vollstaendig_geschlossen = 99
val Number Rolladen_lichtdurchlaessig = 70 // war 45
val Number Lamellen_lichtdurchlaessig = 45 // war 29
val Number Rolladen_lichtundurchlaessig = 86
val Number Lamellen_lichtundurchlaessig = 55 // war 40
val Number Rolladen_offen = 0
val Number Lamellen_offen = 0
val Number Bewoelkung_Grenzwert = 30.0
val Number Modus_Auto = 1
val Number Modus_Ein = 2
val Number Modus_Hoch = 3
val Number Modus_Aus = 0
val Number Lux_Rueckwaertsfenster = 10 // Rueckwaertsfenster in Minuten fuer gleitenden Durchschnitt
val Number Aktionsfenster = 10 // keine mehrfache Aenderung innerhalb dieser Zeitspanne in Minuten
val long Verschattung_Anfang_morgens_statisch = (7 * 3600) * 1000 // Start 7:00
val long Verschattung_Ende_morgens_statisch = (13 * 3600) * 1000 // Ende 13:00
val long Verschattung_Anfang_mittags_statisch = (10 * 3600 + 15 * 60) * 1000 // Start 10:15
val long Verschattung_Ende_mittags_statisch = (18 * 3600 + 30 * 60) * 1000 // Ende 18:30
val Number Lux_Grenzwert_Sonnenschutz_morgens_niedrig_statisch = 7500.0
val Number Lux_Grenzwert_Sonnenschutz_morgens_hoch_statisch = 20000.0
val Number Lux_Grenzwert_Sonnenschutz_mittags_niedrig_statisch = 800.0
val Number Lux_Grenzwert_Sonnenschutz_mittags_hoch_statisch = 2500.0
val Number Aussentemperatur_Grenzwert_Sonnenschutz_statisch = 21.0
val Number Innentemperatur_Grenzwert_Sonnenschutz_statisch = 21.0
val Number Aussentemperatur_Hysterese_Sonnenschutz_statisch = 2.0
val Number Innentemperatur_Hysterese_Sonnenschutz_statisch = 2.0
// ACHTUNG Absolutwert muss daher taeglich neu via Cron-getriggerte rule initialisiert werden !
var long Verschattung_Anfang_morgens
var long Verschattung_Ende_morgens
var long Verschattung_Anfang_mittags
var long Verschattung_Ende_mittags
var boolean SB_alt_morgens = false
var boolean SB_alt_hoch_morgens = false
var boolean SB_alt_mittags = false
var boolean SB_alt_hoch_mittags = false
var boolean SB_Aenderung_mittags = true
var boolean SB_Aenderung_morgens = true
var boolean SB_Reset = true
var Number letzte_Aenderung_morgens = Verschattung_Anfang_morgens
var Number letzte_Aenderung_mittags = Verschattung_Anfang_mittags
val Functions$Function3 <RollershutterItem,ContactItem,NumberItem,Boolean> check_close_shutter = [ shutter, door, percentage |
if (door.state != OPEN) {
logDebug("rules", shutter.label + "(" + shutter.name + ") wird auf " + percentage + " gefahren, shutter = " + shutter)
var Number p = percentage
shutter.sendCommand(p)
} else
logDebug("rules", shutter.label + " wird nicht geschlossen, da " + door.label + " geöffnet ist.")
logDebug("rules", shutter.label + "(" + shutter.name + ") erledigt")
true
]
val Functions$Function4 <RollershutterItem,ContactItem,ContactItem,NumberItem,Boolean> check_close_blinds = [ blinds, door1, door2, percentage |
if (door1.state != OPEN && door2.state != OPEN) {
logDebug("rules", blinds.label + "(" + blinds.name + ") wird auf " + percentage + " gefahren, blinds = " + blinds)
var Number p = percentage
blinds.sendCommand(p)
} else
logDebug("rules", blinds.label + " wird nicht geschlossen, da " + door1.label + " oder " + door2.label + " noch geöffnet ist.")
logDebug("rules", blinds.label + "(" + blinds.name + ") erledigt")
true
]
rule "Sonnenschutz Init virtual Items"
when
System started
or
Item Nachtschaltung received command OFF
or
Item Sonnenschutzschaltung received command
then
Lux_Grenzwert_Sonnenschutz_morgens_niedrig.postUpdate(Lux_Grenzwert_Sonnenschutz_morgens_niedrig_statisch)
Lux_Grenzwert_Sonnenschutz_morgens_hoch.postUpdate(Lux_Grenzwert_Sonnenschutz_morgens_hoch_statisch)
Lux_Grenzwert_Sonnenschutz_mittags_niedrig.postUpdate(Lux_Grenzwert_Sonnenschutz_mittags_niedrig_statisch)
Lux_Grenzwert_Sonnenschutz_mittags_hoch.postUpdate(Lux_Grenzwert_Sonnenschutz_mittags_hoch_statisch)
Aussentemperatur_Grenzwert_Sonnenschutz.postUpdate(Aussentemperatur_Grenzwert_Sonnenschutz_statisch)
Aussentemperatur_Hysterese_Sonnenschutz.postUpdate(Aussentemperatur_Hysterese_Sonnenschutz_statisch)
Innentemperatur_Grenzwert_Sonnenschutz.postUpdate(Innentemperatur_Grenzwert_Sonnenschutz_statisch)
Innentemperatur_Hysterese_Sonnenschutz.postUpdate(Innentemperatur_Hysterese_Sonnenschutz_statisch)
Verschattung_Anfang_morgens = (now.withTimeAtStartOfDay).millis + Verschattung_Anfang_morgens_statisch
Verschattung_Ende_morgens = (now.withTimeAtStartOfDay).millis + Verschattung_Ende_morgens_statisch
Verschattung_Anfang_mittags = (now.withTimeAtStartOfDay).millis + Verschattung_Anfang_mittags_statisch
Verschattung_Ende_mittags = (now.withTimeAtStartOfDay).millis + Verschattung_Ende_mittags_statisch
SB_Aenderung_mittags = true
SB_Aenderung_morgens = true
SB_Reset = true
letzte_Aenderung_morgens = Verschattung_Anfang_morgens
letzte_Aenderung_mittags = Verschattung_Anfang_mittags
logInfo("rules", "Sonnenschutz Initialisierung: SB_Reset = " + SB_Reset)
Sonnenschutz.postUpdate(Sonnenschutz.state)
end
rule "Sonnenschutz Tuer geoeffnet"
when
Item WohnraumTueren changed
then
logDebug("rules", "Sonnenschutzcheck: Anzahl offener Türen hat sich auf " + WohnraumTueren.state + " geändert.")
SB_Reset = true
end
rule "Sonnenschutzcheck"
when
Time cron "0 1/2 7-18 ? * MON-SUN"
or
Item Sonnenschutzschaltung changed to ON
then
if (Sonnenschutzschaltung.state != ON)
return;
var Number a = (Soll_Temp_Wohnen.state as Number) - (Aussentemperatur_Hysterese_Sonnenschutz.state as Number)
var Number i = (Soll_Temp_Wohnen.state as Number) - (Innentemperatur_Hysterese_Sonnenschutz.state as Number)
logDebug("rules", "Sonnenschutzcheck: Soll_Temp_Wohnen = " + Soll_Temp_Wohnen.state + "; Hysterese innen/aussen = " + Innentemperatur_Hysterese_Sonnenschutz.state + "/" + Aussentemperatur_Hysterese_Sonnenschutz.state + "; aussen = " + a + "; innen = " + i)
Aussentemperatur_Grenzwert_Sonnenschutz.postUpdate(a)
Innentemperatur_Grenzwert_Sonnenschutz.postUpdate(i)
if ((Sonnenschutzschaltung.state == ON) && (Nachtschaltung.state != ON) && (Szene.state <= 2)) {
Sonnenschutz.postUpdate(Sonnenschutz.state)
}
end
rule "Sonnenschutz implementieren"
when
Item Sonnenschutz received update
then
var Number Temp_morgens = (TempAussen.state as Number)
var Number Temp_mittags = (EG_Wohnen_Auge_Temp.state as Number)
var Number Lux_morgens = Garten_Auge_Lux.averageSince(now.minusMinutes(Lux_Rueckwaertsfenster))
var Number Lux_mittags = EG_Wohnen_Auge_Lux.averageSince(now.minusMinutes(Lux_Rueckwaertsfenster))
// Lux_Wohnen_mittags.postUpdate(Lux_mittags_niedrig)
logDebug("rules", "Sonnenschutz: Sonnenschutz.state = " + Sonnenschutz.state)
if (Sonnenschutz.state == Modus_Aus || Szene.state == 101)
return;
logDebug("rules", "Sonnenschutz: Durchschnittshelligkeit morgens/mittags = " + Lux_morgens + "/" + Lux_mittags)
var boolean hell_genug_morgens = (Lux_morgens > (Lux_Grenzwert_Sonnenschutz_morgens_niedrig.state as Number) && aktuell_Bewoelkung.state >= Bewoelkung_Grenzwert) || (Lux_morgens > (Lux_Grenzwert_Sonnenschutz_morgens_niedrig.state as Number))
var boolean zu_hell_morgens = Lux_morgens > (Lux_Grenzwert_Sonnenschutz_morgens_hoch.state as Number)
var boolean hell_genug_mittags = (Lux_mittags > (Lux_Grenzwert_Sonnenschutz_mittags_niedrig.state as Number) && aktuell_Bewoelkung.state >= Bewoelkung_Grenzwert) || hell_genug_morgens
// Halb-Verschattung reduziert Innenhelligkeit, darum stark verschatten, wenn trotzdem (SB_alt_mittags) der Grenzwert erreicht
var boolean zu_hell_mittags = Lux_mittags > (Lux_Grenzwert_Sonnenschutz_mittags_hoch.state as Number) || (hell_genug_mittags && SB_alt_mittags)
var boolean zu_warm_morgens = (Temp_morgens > (Aussentemperatur_Grenzwert_Sonnenschutz.state as Number) || Temp_max.state > Aussentemperatur_Grenzwert_Sonnenschutz.state)
&& (Lux_morgens > (Lux_Grenzwert_Sonnenschutz_morgens_niedrig.state as Number))
var boolean zu_warm_mittags = (Temp_mittags > (Aussentemperatur_Grenzwert_Sonnenschutz.state as Number) || Temp_max.state > Aussentemperatur_Grenzwert_Sonnenschutz.state)
&& (Lux_mittags > (Lux_Grenzwert_Sonnenschutz_mittags_niedrig.state as Number))
logDebug("rules", "Sonnenschutz: hell genug morgens/mittags = " + hell_genug_morgens + "/" + hell_genug_mittags + "; zu hell morgens/mittags = " + zu_hell_morgens + "/" + zu_hell_mittags + "; zu warm = " + zu_warm_morgens + "/" + zu_warm_mittags)
// logDebug("rules", "Sonnenschutz debug 1b: Zeitraum morgens von-bis[nach Beginn-vor Ende] = " + now.millis + " / " + Verschattung_Anfang_morgens + "-" + Verschattung_Ende_morgens + "[" + (now.millis > Verschattung_Anfang_morgens) + "-" + (now.millis < Verschattung_Ende_morgens) + "]")
// logDebug("rules", "Sonnenschutz debug 1c: Zeitraum mittags von-bis[nach Beginn-vor Ende] = " + now.millis + " / " + Verschattung_Anfang_mittags + "-" + Verschattung_Ende_mittags + "[" + (now.millis > Verschattung_Anfang_mittags) + "-" + (now.millis < Verschattung_Ende_mittags) + "]")
logDebug("rules", "Sonnenschutz: SB_Reset = " + SB_Reset + "; (Sonnenschutz == Modus_Ein) = " + (Sonnenschutz.state == Modus_Ein) + "; (Sonnenschutz == Modus_Hoch) = " + (Sonnenschutz.state == Modus_Hoch))
var boolean Schutzbedarf_morgens = (Sonnenschutz.state == Modus_Ein) || ((now.millis > Verschattung_Anfang_morgens) && (now.millis < Verschattung_Ende_morgens) && ((hell_genug_morgens && zu_warm_morgens) || zu_hell_morgens))
var boolean Schutzbedarf_mittags = (Sonnenschutz.state == Modus_Ein) || ((now.millis > Verschattung_Anfang_mittags) && (now.millis < Verschattung_Ende_mittags) && ((hell_genug_mittags && zu_warm_mittags) || zu_hell_mittags))
var boolean Schutzbedarf_hoch_morgens = (Sonnenschutz.state == Modus_Hoch) || (Schutzbedarf_morgens && zu_hell_morgens && zu_warm_morgens)
var boolean Schutzbedarf_hoch_mittags = (Sonnenschutz.state == Modus_Hoch) || (Schutzbedarf_mittags && zu_hell_mittags && zu_warm_mittags)
logDebug("rules", "Sonnenschutz: Schutzbedarf morgens[hoch]/mittags[hoch] = " + Schutzbedarf_morgens + "[" + Schutzbedarf_hoch_morgens + "]/" + Schutzbedarf_mittags + "[" + Schutzbedarf_hoch_mittags + "]")
SB_Aenderung_morgens = (SB_Reset || SB_alt_hoch_morgens != Schutzbedarf_hoch_morgens || SB_alt_morgens != Schutzbedarf_morgens)
SB_Aenderung_mittags = (SB_Reset || SB_alt_hoch_mittags != Schutzbedarf_hoch_mittags || SB_alt_mittags != Schutzbedarf_mittags)
logDebug("rules", "Sonnenschutz: Schutzbedarf Alt-Speicher morgens[hoch][Aenderung]/mittags[hoch][Aenderung] = " + SB_alt_morgens + "[" + SB_alt_hoch_morgens + "][" + SB_Aenderung_morgens + "]/" + SB_alt_mittags + "[" + SB_alt_hoch_mittags + "][" + SB_Aenderung_mittags + "]")
logDebug("rules", "Sonnenschutz Morgen-Check: Schaltung = " + Sonnenschutzschaltung.state + "; Lichtstärke (" + Lux_Durchschnitt_Nachlauf + "-min-Durchschnitt/Grenzwert[hoch]) = " + Lux_morgens + "/" + Lux_Grenzwert_Sonnenschutz_morgens_niedrig.state + "[" + Lux_Grenzwert_Sonnenschutz_morgens_hoch.state + "] lux; Bewölkung (aktuell/Grenzwert) = " + aktuell_Bewoelkung.state + "/" + Bewoelkung_Grenzwert + " %; Temperatur(Sensor/max. heute/Grenzwert) = " + Temp_morgens + "/" + Temp_max.state + "/" + Aussentemperatur_Grenzwert_Sonnenschutz.state + " °C; Schutzbedarf morgens (aktuell[hoch]/alt[hoch]/Änderung) = " + Schutzbedarf_morgens + "[" + Schutzbedarf_hoch_morgens + "]/" + SB_alt_morgens + "[" + SB_alt_hoch_morgens + "]/" + SB_Aenderung_morgens)
var Number c = now.millis - Aktionsfenster * 60 * 1000
var Number closure = if (Schutzbedarf_hoch_morgens) Rolladen_lichtundurchlaessig else Rolladen_lichtdurchlaessig
var Number lamellas = if (Schutzbedarf_hoch_morgens) Lamellen_lichtundurchlaessig else Lamellen_lichtdurchlaessig
// logDebug("rules", "Sonnenschutz debug 3a: SB_Reset = " + SB_Reset +"; SB_Aenderung_morgens = " + SB_Aenderung_morgens)
// logDebug("rules", "Sonnenschutz debug 3b: now > Anfang_morgens = " + if (now.millis > Verschattung_Anfang_morgens) "true" else "false")
// logDebug("rules", "Sonnenschutz debug 3c: now < Ende_morgens = " + if (now.millis < Verschattung_Ende_morgens) "true" else "false")
// logDebug("rules", "Sonnenschutz debug 3d: c = " + c + " > letzte_Aenderung_morgens = " + letzte_Aenderung_morgens + " = " + if (c > letzte_Aenderung_morgens) "true" else "false")
if ((SB_Reset || SB_Aenderung_morgens) && now.millis < Verschattung_Ende_morgens && c > letzte_Aenderung_morgens) {
if (Schutzbedarf_morgens) {
logInfo("rules", "Sonnenschutz: Verschatte vormittags beschienene Fensterflächen ...")
check_close_shutter.apply(EG_Kueche_Rolladen_Tuer,EG_Kueche_Tuer_Kontakt,closure)
check_close_shutter.apply(EG_Kueche_Rolladen_Fenster,EG_Kueche_Fenster_Kontakt,closure)
check_close_shutter.apply(EG_Essen_Rolladen,EG_Essen_Fenster_Kontakt,closure)
check_close_blinds.apply(EG_Wohnen_Jalousie_links,EG_Wohnen_Tuer_li1_Kontakt,EG_Wohnen_Tuer_li2_Kontakt,Rolladen_vollstaendig_geschlossen)
check_close_blinds.apply(EG_Wohnen_Jalousie_Mitte,EG_Wohnen_Tuer_Mitte_li_Kontakt,EG_Wohnen_Tuer_Mitte_re_Kontakt,Rolladen_vollstaendig_geschlossen)
check_close_blinds.apply(EG_Wohnen_Jalousie_links_Lamellen,EG_Wohnen_Tuer_li1_Kontakt,EG_Wohnen_Tuer_li2_Kontakt,lamellas)
check_close_blinds.apply(EG_Wohnen_Jalousie_Mitte_Lamellen,EG_Wohnen_Tuer_Mitte_li_Kontakt,EG_Wohnen_Tuer_Mitte_re_Kontakt,lamellas)
} else {
logInfo("rules", "Sonnenschutz: keine Verschattung nötig, öffne vormittags beschienene Fensterflächen ...")
EG_Kueche_Rolladen_Tuer.sendCommand(Rolladen_offen)
EG_Kueche_Rolladen_Fenster.sendCommand(Rolladen_offen)
EG_Essen_Rolladen.sendCommand(Rolladen_offen)
EG_Wohnen_Jalousie_links.sendCommand(Rolladen_offen)
EG_Wohnen_Jalousie_Mitte.sendCommand(Rolladen_offen)
logDebug("rules", "Sonnenschutz: Rolläden/Jalousien vormittags fertig heraufgefahren.")
}
} else
logDebug("rules", "Sonnenschutz: keine Anpassung der Verschattung auf den vormittags beschienenen Fensterflächen nötig.")
logDebug("rules", "Sonnenschutz Mittags-Check : Schaltung = " + Sonnenschutzschaltung.state + "; Lichtstärke (" + Lux_Durchschnitt_Nachlauf + "-min-Durchschnitt/Grenzwert[hoch]) = " + Lux_mittags + "/" + Lux_Grenzwert_Sonnenschutz_mittags_niedrig.state + "[" + Lux_Grenzwert_Sonnenschutz_mittags_hoch.state + "] lux; Bewölkung (aktuell/Grenzwert) = " + aktuell_Bewoelkung.state + "/" + Bewoelkung_Grenzwert + " %; Temperatur(Sensor/max. heute/Grenzwert) = " + Temp_mittags + "/" + Temp_max.state + "/" + Aussentemperatur_Grenzwert_Sonnenschutz.state + " °C; Schutzbedarf mittags (aktuell[hoch]/alt[hoch]/Änderung) = " + Schutzbedarf_mittags + "[" + Schutzbedarf_hoch_mittags + "]/" + SB_alt_mittags + "[" + SB_alt_hoch_mittags + "]/" + SB_Aenderung_mittags)
closure = if (Schutzbedarf_hoch_mittags) Rolladen_lichtundurchlaessig else Rolladen_lichtdurchlaessig
lamellas = if (Schutzbedarf_hoch_mittags) Lamellen_lichtundurchlaessig else Lamellen_lichtdurchlaessig
// logDebug("rules", "Sonnenschutz debug 3a: SB_Reset = " + SB_Reset +"; SB_Aenderung_mittags = " + SB_Aenderung_mittags)
// logDebug("rules", "Sonnenschutz debug 3b: now > Anfang_mittags = " + if (now.millis > Verschattung_Anfang_mittags) "true" else "false")
// logDebug("rules", "Sonnenschutz debug 3c: now < Ende_mittags = " + if (now.millis < Verschattung_Ende_mittags) "true" else "false")
// logDebug("rules", "Sonnenschutz debug 3d: c = " + c + " > letzte_Aenderung_mittags = " + letzte_Aenderung_mittags + " = " + if (c > letzte_Aenderung_mittags) "true" else "false")
if ((SB_Reset || SB_Aenderung_mittags) && now.millis > Verschattung_Anfang_mittags && now.millis < Verschattung_Ende_mittags && c > letzte_Aenderung_mittags) {
if (Schutzbedarf_mittags) {
logDebug("rules", "Sonnenschutz: Verschatte (nach)mittags beschienene Fensterflächen ...")
check_close_blinds.apply(EG_Wohnen_Jalousie_rechts,EG_Wohnen_Tuer_re1_Kontakt,EG_Wohnen_Tuer_re2_Kontakt,Rolladen_vollstaendig_geschlossen)
check_close_blinds.apply(EG_Wohnen_Jalousie_rechts_Lamellen,EG_Wohnen_Tuer_re1_Kontakt,EG_Wohnen_Tuer_re2_Kontakt,lamellas)
if (Sonnenschutz_Bianca.state == ON)
check_close_shutter.apply(EG_Bianca_Rolladen,EG_Bianca_Tuer_Kontakt,closure)
check_close_shutter.apply(EG_Wohnen_Rolladen,EG_Wohnen_Tuer_alt_Kontakt,closure)
} else {
logDebug("rules", "Sonnenschutz: keine Verschattung nötig, öffne (nach)mittags beschienene Fensterflächen ...")
EG_Wohnen_Jalousie_rechts.sendCommand(Rolladen_offen)
if (Sonnenschutz_Bianca.state == ON)
EG_Bianca_Rolladen.sendCommand(Rolladen_offen)
EG_Wohnen_Rolladen.sendCommand(Rolladen_offen)
logDebug("rules", "Sonnenschutz: nachmittags fertig heraufgefahren.")
}
} else
logDebug("rules", "Sonnenschutz: keine Anpassung der Verschattung auf den nachmittags beschienenen Fensterflächen nötig.")
if (SB_Aenderung_morgens) {
SB_Aenderung_morgens = false
letzte_Aenderung_morgens = now.millis
}
if (SB_Aenderung_mittags) {
SB_Aenderung_mittags = false
letzte_Aenderung_mittags = now.millis
}
SB_alt_morgens = Schutzbedarf_morgens
SB_alt_hoch_morgens = Schutzbedarf_hoch_morgens
SB_alt_mittags = Schutzbedarf_mittags
SB_alt_hoch_mittags = Schutzbedarf_hoch_mittags
SB_Reset = false
if (now.isAfter(Verschattung_Ende_mittags) && now.minusMinutes(Aktionsfenster).isBefore(Verschattung_Ende_mittags)) {
EG_Wohnen_Jalousie_rechts.sendCommand(Rolladen_offen)
EG_Wohnen_Rolladen.sendCommand(Rolladen_offen)
if (Sonnenschutz_Bianca.state == ON)
EG_Bianca_Rolladen.sendCommand(Rolladen_offen)
SB_Aenderung_mittags = true
logDebug("rules", "Sonnenschutz Mittagseite beendet, Jalousien werden wieder hochgefahren.")
}
if (now.isAfter(Verschattung_Ende_morgens) && now.minusMinutes(Aktionsfenster).isBefore(Verschattung_Ende_morgens)) {
EG_Kueche_Rolladen_Tuer.sendCommand(Rolladen_offen)
EG_Kueche_Rolladen_Fenster.sendCommand(Rolladen_offen)
EG_Essen_Rolladen.sendCommand(Rolladen_offen)
EG_Wohnen_Jalousie_links.sendCommand(Rolladen_offen)
EG_Wohnen_Jalousie_Mitte.sendCommand(Rolladen_offen)
SB_Aenderung_morgens = true
logDebug("rules", "Sonnenschutz Morgenseite beendet, Jalousien werden wieder hochgefahren.")
}
logDebug("rules", "Sonnenschutz: Verschattungs-Check ausgeführt.")
end