automatisches ein/ausschalten der Beleuchtung

Begonnen von pjakobs, 07 Januar 2019, 12:01:31

Vorheriges Thema - Nächstes Thema

pjakobs

Moin zusammen,

ich dachte, ich teile mal was mit Euch, das hier seit geraumer Zeit läuft und, zumindest in meiner Installation ganz gut funktioniert.
Nachdem ich letztes Jahr endlich mal die Routinen neu geschrieben habe sind sie jetzt auch halbwegs vorzeigbar.

Was tut der Code?
Abhängig von Lichtszenen, des Homestatus und der Helligkeit werden beliebig viele Lampen automatisch gedimmt.
Das ganze ist aktuell auf meine Umgebung zugeschnitten und wer es nutzen will, wird vielleicht ein paar Anpassungen vornehmen müssen.

Was braucht man?
- ein twilight Device oder etwas ähnliches, das die Helligkeit außen zwischen 0 und 100% liefert.
- ein Präsenz-Device, das angibt, ob $mensch zuhause ist oder nicht
- Leuchten, die sich per "set hsv" steuern lassen (natürlich anpassbar)
- Lightscenes
- Ein Notify, dass bei veränderung des Außenlichts die Routine aufruft.

Das Präsenz-Devices ist aktuell hart codiert (RGR_Residents), das lässt sich aber ändern.

Die Leuchten selbst brauchen ein paar extra Attribute:

define LED_TVo LedController LED-TVo.fritz.box
attr LED_TVo userattr lightSceneParamsToSave lightSceneRestoreOnlyIfChanged:1,0 twilightDimHSV twilightDimThreshold
attr LED_TVo colorTemp 2700
attr LED_TVo defaultColor 0,10,80
attr LED_TVo defaultRamp 6000
attr LED_TVo lightSceneParamsToSave hsv
attr LED_TVo room Licht,Wohnzimmer
attr LED_TVo twilightDimHSV 0,0,30
attr LED_TVo twilightDimThreshold 70
attr LED_TVo verbose 2
attr LED_TVo webCmd rgb:rgb FFFFFF:rgb AFAFAF:rgb 7F7F7F:rgb 3F3F3F:rgb 000000:rgb 401020
attr LED_TVo widgetOverride rgb:colorpicker,HSV


Im wesentlichen sind das
twilightDimHSV und twilightDimThreshold

twilightDimThreshold bestimmt, ab welcher Helligkeit (bzw. Dunkelheit) diese Leuchte anfängt, gedimmt zu werden
twilightDimHSV bestimmt den Maximalwert, den diese Leuchte bei 0% Helligkeit erreicht.

Das Notify ist simpel:

define NO_Twilight_Tick notify myTwiLight:twilight_weather:.* {twilightDim($EVTPART1)}


Nun zum Code:

sub twilightDim($){
Log3("",2,"enter twilightDim Residents are: ".ReadingsVal("RGR_Residents","state",""));
    return if(ReadingsVal("RGR_Residents","state","") ne "home");
    #Log3("",2,"twilightDim -> continue");
    my $twilightState=shift;
    $twilightState=$twilightState+0.0;
    my @lightScenes=getLightScenes();
    #print "twilightDim \n".Dumper(@lightScenes);
    foreach my $lightScene (@lightScenes){
Log3("",2,"twilightDim -> current Scene: ".$lightScene." state: ".ReadingsVal($lightScene,"state","off"));
        if(ReadingsVal($lightScene,"state","off") eq "auto"){
            my @lights=getLights($lightScene);
            #print "twilightDim \n".Dumper(@lights)."\n";
            foreach my $light (@lights){
              # this should filter out any devices that only know ON and OFF, iE SONOFF-TASMOTA
              if(AttrVal($light,"webCmd","" ne "ON:OFF")){ 
                twilightDimLight($light, $twilightState);
                }
            }
Log3("",2,"twilightDim: next light scene");
        }else{
Log3("",2,"twilightDim: skipping scene ".$lightScene);
}
    }
}

twilightDim bekommt als Parameter den aktuellen Helligkeitswert und durchläuft dann
1. alle Lightscenes und
2. für die lightscenes, deren Szene auf "auto" gesetzt ist alle Lichter.
An der Stelle noch ein kleiner Hack: weil mein Verstärker per Sonoff Tasmota in zwei Scenes vorkommt, würde er mit eingestellt worden, als "schnellen" Hack habe ich da nun die Abfrage auf das webCMD und verändere keine Devices, die nur "ON:OFF" da stehen haben. Nicht schön, eigentlich sollte ich schauen, ob die Attribute twilightDimHSV und twilightDimThreshold gesetzt sind und sonst das Device alleine lassen bzw. die beiden so ändern, dass ich damit auch on/off schalten kann.

Das eigentliche Dimmen einer einzelnen Leuchte geschieht hier:

sub twilightDimLight($$){
    my($light, $twilightState)=(@_);
    # print "twilightDimLight: ".$light.", ".$twilightState."\n";
    my $twilightDimThreshold = AttrVal($light,"twilightDimThreshold",0);
    #print "twilightDim Threshold: ".$twilightDimThreshold."\n";
    my $setting = AttrVal($light, "twilightDimSetting", "hsv");
    if($twilightState<$twilightDimThreshold){

        my $twilightDimHSV     = AttrVal($light,"twilightDimHSV",0);
        my $twilightDimCurrent = ReadingsVal($light,"hsv","0,0,0");

        my ($h,$s,$v)    = split(",",$twilightDimHSV);
        my ($hc,$sc,$vc) = split(",",$twilightDimCurrent);

        my $hnew = int(($h/$twilightDimThreshold)*($twilightDimThreshold-$twilightState));
        my $snew = int(($s/$twilightDimThreshold)*($twilightDimThreshold-$twilightState));
        my $vnew = int(($v/$twilightDimThreshold)*($twilightDimThreshold-$twilightState));

        Log3("",2,"twilightDim: Light: ".$light." Threshold: ".$twilightDimThreshold." setting: ".$setting."\ntwilightDimHSV: ".$twilightDimHSV." twilightDimCurrent: ".$twilightDimCurrent);
        fhem("set $light $setting $hnew,$snew,$vnew");
    }else{
        fhem("set $light $setting 0,0,0");
    }
}

Die Leuchte wird also einfach linear von 0% kurz vor twilightDimThreshold auf twilightDimHSV bei 0% Licht hochgefahren. Man könnte hier vielleicht noch eine der Helligkeitswahrnehmung angepasstere Kurve nehmen.

Zuletzt die beiden Hilfsroutinen, die die Lightscenes und Lichter enumerieren:


sub getLightScenes() {
    my $rawList=fhem("list LS_.*");
    #print "twilightDim->getLightScenes, ".$rawList;
    my @lightScenes=(split(/^/,$rawList));
    #print "twilightDim->getLightScenes, ".Dumper(@lightScenes);
    chomp @lightScenes;
    #print "twilightDim->getLightScenes, ".Dumper(@lightScenes);
    return @lightScenes;
}

sub getLights($){
    my ($lightScene)=(@_);
    my $rawList=InternalVal($lightScene,"DEF","");
    my @lights=split(/ /, $rawList);
    foreach my $light (@lights){
        chomp $light;
        $light=~ s/,//;
    }
    return @lights;
}

Damit eine LightScene erfasst wird, muss sie mit "LS_" beginnen (oder Ihr ändert den Code dort entsprechend) Ich habe auf die Schnelle keinen schönen Weg gefunden, alle Devices eines Typs aufzulisten.

Weil die ganze Routine so angelegt ist, dass sie nur ausgeführt wird, wenn RGR_Residents den status "home" hat, passiert nichts, wenn man nicht zuhause ist.

Im HomeCMDmode-gotosleep meines HOMEMODE device führe ich einfach folgendes aus:

fhem("set LS_Terasse scene auto");
fhem("set LS_Wohnzimmer scene auto");
fhem("set LS_Flur scene auto");
fhem("set LS_Schlafzimmer scene gotosleep");

Damit gehen dann alle Lichter aus (wobei ich, wie ich das schreibe, offen gesprochen nicht weiß, warum sie das tun. Ich werde wohl alt) und erst, wenn der der homemode wieder auf "home" springt, werden sie auf's neue heller.
Es ist dabei empfehlenswert, im HomeCMDmode-awoken ein "twilightDim(ReadingsVal("myTwiLight","twilight_weather",100));" einzufügen, weil das Notify ja nicht unbedingt sofort triggert.
Das gleiche gilt für den Moment, in dem ich von einer Reise heimkehre, da steht dann im HomeCMDlocation-arrival:

fhem("set LS_.* scene auto");
twilightDim(ReadingsVal("myTwiLight","twilight_weather",100));


Jetzt bin ich mal gespannt, ob a) das bei Euch funktioniert, und b) welche Ideen Ihr dafür sonst noch so habt.

grüße

pj