From c69a7bda77b90b41f8ce06e7a1e25db0bda50f7f Mon Sep 17 00:00:00 2001 From: LeonGaultier Date: Fri, 26 Apr 2019 21:14:46 +0000 Subject: [PATCH] 73_AutoShuttersControl: new major release 0.6, add wind support,chnage code and Attribut style git-svn-id: https://svn.fhem.de/fhem/trunk@19267 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 2 + fhem/FHEM/73_AutoShuttersControl.pm | 2708 +++++++++++++++++++-------- 2 files changed, 1909 insertions(+), 801 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 2d43dc312..c7a77b074 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,7 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - feature: 73_AutoShuttersControl: new major release 0.6, add wind support, + chnage code and Attribut style - feature: 93_DbLog: V4.1.0 from contrib, write function rewritten, new attr bulkInsert, fix reconnect behavior of MySQL-Forum: #99719 - change: 74_GardenaSmartDevice: change output for illigal year diff --git a/fhem/FHEM/73_AutoShuttersControl.pm b/fhem/FHEM/73_AutoShuttersControl.pm index 12c0dd095..74846f098 100644 --- a/fhem/FHEM/73_AutoShuttersControl.pm +++ b/fhem/FHEM/73_AutoShuttersControl.pm @@ -35,40 +35,49 @@ ### Notizen # - Feststellen ob ein Rolladen fährt oder nicht +# !!!!! - Innerhalb einer Shutterschleife kein CommandAttr verwenden. Bring Fehler!!! Kommen Raumnamen in die Shutterliste !!!!!! +# package main; use strict; use warnings; +use FHEM::Meta; -my $version = '0.4.0.9'; +my $version = '0.6.0'; sub AutoShuttersControl_Initialize($) { my ($hash) = @_; -## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname - # und davor mit :: getrennt der eigentliche package Name des Modules - $hash->{SetFn} = 'AutoShuttersControl::Set'; - $hash->{GetFn} = 'AutoShuttersControl::Get'; - $hash->{DefFn} = 'AutoShuttersControl::Define'; - $hash->{NotifyFn} = 'AutoShuttersControl::Notify'; - $hash->{UndefFn} = 'AutoShuttersControl::Undef'; - $hash->{AttrFn} = 'AutoShuttersControl::Attr'; - $hash->{AttrList} = - 'ASC_guestPresence:on,off ' - . 'ASC_temperatureSensor ' + ### alte Attribute welche entfernt werden + my $oldAttr = + 'ASC_temperatureSensor ' . 'ASC_temperatureReading ' - . 'ASC_brightnessMinVal ' - . 'ASC_brightnessMaxVal ' - . 'ASC_autoShuttersControlMorning:on,off ' - . 'ASC_autoShuttersControlEvening:on,off ' - . 'ASC_autoShuttersControlShading:on,off ' - . 'ASC_autoShuttersControlComfort:on,off ' . 'ASC_residentsDevice ' . 'ASC_residentsDeviceReading ' . 'ASC_rainSensorDevice ' . 'ASC_rainSensorReading ' . 'ASC_rainSensorShuttersClosedPos:0,10,20,30,40,50,60,70,80,90,100 ' + . 'ASC_brightnessMinVal ' + . 'ASC_brightnessMaxVal '; + +## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname + # und davor mit :: getrennt der eigentliche package Name des Modules + $hash->{SetFn} = 'FHEM::AutoShuttersControl::Set'; + $hash->{GetFn} = 'FHEM::AutoShuttersControl::Get'; + $hash->{DefFn} = 'FHEM::AutoShuttersControl::Define'; + $hash->{NotifyFn} = 'FHEM::AutoShuttersControl::Notify'; + $hash->{UndefFn} = 'FHEM::AutoShuttersControl::Undef'; + $hash->{AttrFn} = 'FHEM::AutoShuttersControl::Attr'; + $hash->{AttrList} = + 'ASC_tempSensor ' + . 'ASC_brightnessDriveUpDown ' + . 'ASC_autoShuttersControlMorning:on,off ' + . 'ASC_autoShuttersControlEvening:on,off ' + . 'ASC_autoShuttersControlShading:on,off ' + . 'ASC_autoShuttersControlComfort:on,off ' + . 'ASC_residentsDev ' + . 'ASC_rainSensor ' . 'ASC_autoAstroModeMorning:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON ' . 'ASC_autoAstroModeMorningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9 ' . 'ASC_autoAstroModeEvening:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON ' @@ -76,23 +85,24 @@ sub AutoShuttersControl_Initialize($) { . 'ASC_freezeTemp:-5,-4,-3,-2,-1,0,1,2,3,4,5 ' . 'ASC_shuttersDriveOffset ' . 'ASC_twilightDevice ' + . 'ASC_windSensor ' . 'ASC_expert:1 ' + . 'ASC_blockAscDrivesAfterManual:0,1 ' + . 'ASC_debug:1 ' + . $oldAttr . $readingFnAttributes; $hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn -## Ist nur damit sich bei einem reload auch die Versionsnummer erneuert. -# foreach my $d ( sort keys %{ $modules{AutoShuttersControl}{defptr} } ) { -# my $hash = $modules{AutoShuttersControl}{defptr}{$d}; -# $hash->{VERSION} = $version; -# } + return FHEM::Meta::InitMod( __FILE__, $hash ); } ## unserer packagename -package AutoShuttersControl; +package FHEM::AutoShuttersControl; use strict; use warnings; use POSIX; +use FHEM::Meta; use GPUtils qw(:all) ; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt @@ -141,65 +151,61 @@ BEGIN { ## Die Attributsliste welche an die Rolläden verteilt wird. Zusammen mit Default Werten my %userAttrList = ( - 'ASC_Mode_Up:absent,always,off,home' => 'always', - 'ASC_Mode_Down:absent,always,off,home' => 'always', - 'ASC_Up:time,astro,brightness' => 'astro', - 'ASC_Down:time,astro,brightness' => 'astro', - 'ASC_AutoAstroModeMorning:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON' => 'none', + 'ASC_Mode_Up:absent,always,off,home' => '-', + 'ASC_Mode_Down:absent,always,off,home' => '-', + 'ASC_Up:time,astro,brightness' => '-', + 'ASC_Down:time,astro,brightness' => '-', + 'ASC_AutoAstroModeMorning:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON' => '-', 'ASC_AutoAstroModeMorningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9' - => 'none', - 'ASC_AutoAstroModeEvening:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON' => 'none', + => '-', + 'ASC_AutoAstroModeEvening:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON' => '-', 'ASC_AutoAstroModeEveningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9' - => 'none', + => '-', 'ASC_Open_Pos:0,10,20,30,40,50,60,70,80,90,100' => [ '', 0, 100 ], 'ASC_Closed_Pos:0,10,20,30,40,50,60,70,80,90,100' => [ '', 100, 0 ], 'ASC_Pos_Reading' => [ '', 'position', 'pct' ], - 'ASC_Time_Up_Early' => '04:30', - 'ASC_Time_Up_Late' => '09:00', - 'ASC_Time_Up_WE_Holiday' => '08:30', - 'ASC_Time_Down_Early' => '15:30', - 'ASC_Time_Down_Late' => '22:30', - 'ASC_PrivacyDownTime_beforNightClose' => -1, - 'ASC_PrivacyDown_Pos' => 50, - 'ASC_WindowRec' => 'none', - 'ASC_Ventilate_Window_Open:on,off' => 'on', - 'ASC_LockOut:soft,hard,off' => 'off', - 'ASC_LockOut_Cmd:inhibit,blocked,protection' => 'none', - 'ASC_BlockingTime_afterManual' => 1200, - 'ASC_BlockingTime_beforNightClose' => 3600, - 'ASC_BlockingTime_beforDayOpen' => 3600, - 'ASC_Brightness_Sensor' => 'none', - 'ASC_Brightness_Reading' => 'brightness', - 'ASC_Shading_Direction' => 180, - 'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 80, 20 ], - 'ASC_Shading_Mode:absent,always,off,home' => 'off', - 'ASC_Shading_Angle_Left' => 75, - 'ASC_Shading_Angle_Right' => 75, - 'ASC_Shading_StateChange_Sunny' => 35000, - 'ASC_Shading_StateChange_Cloudy' => 20000, - 'ASC_Shading_Min_Elevation' => 25.0, - 'ASC_Shading_Min_OutsideTemperature' => 18, - 'ASC_Shading_WaitingPeriod' => 1200, - - # 'ASC_Shading_Fast_Open:on,off' => 'none', - # 'ASC_Shading_Fast_Close:on,off' => 'none', - 'ASC_Drive_Offset' => -1, - 'ASC_Drive_OffsetStart' => -1, - 'ASC_WindowRec_subType:twostate,threestate' => 'twostate', - 'ASC_ShuttersPlace:window,terrace' => 'window', + 'ASC_Time_Up_Early' => '-', + 'ASC_Time_Up_Late' => '-', + 'ASC_Time_Up_WE_Holiday' => '-', + 'ASC_Time_Down_Early' => '-', + 'ASC_Time_Down_Late' => '-', + 'ASC_PrivacyDownTime_beforNightClose' => '-', + 'ASC_PrivacyDown_Pos' => '-', + 'ASC_WindowRec' => '-', + 'ASC_Ventilate_Window_Open:on,off' => '-', + 'ASC_LockOut:soft,hard,off' => '-', + 'ASC_LockOut_Cmd:inhibit,blocked,protection' => '-', + 'ASC_BlockingTime_afterManual' => '-', + 'ASC_BlockingTime_beforNightClose' => '-', + 'ASC_BlockingTime_beforDayOpen' => '-', + 'ASC_BrightnessSensor' => '-', + 'ASC_Shading_Direction' => '-', + 'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 80, 20 ], + 'ASC_Shading_Mode:absent,always,off,home' => '-', + 'ASC_Shading_Angle_Left' => '-', + 'ASC_Shading_Angle_Right' => '-', + 'ASC_Shading_StateChange_Sunny' => '-', + 'ASC_Shading_StateChange_Cloudy' => '-', + 'ASC_Shading_Min_Elevation' => '-', + 'ASC_Shading_Min_OutsideTemperature' => '-', + 'ASC_Shading_WaitingPeriod' => '-', + 'ASC_Drive_Offset' => '-', + 'ASC_Drive_OffsetStart' => '-', + 'ASC_WindowRec_subType:twostate,threestate' => '-', + 'ASC_ShuttersPlace:window,terrace' => '-', 'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 70, 30 ], 'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100' => [ '', 20, 80 ], - 'ASC_GuestRoom:on,off' => 'none', - 'ASC_Antifreeze:off,soft,hard,am,pm' => 'off', + 'ASC_GuestRoom:on,off' => '-', + 'ASC_Antifreeze:off,soft,hard,am,pm' => '-', 'ASC_Antifreeze_Pos:5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100' => [ '', 85, 15 ], - 'ASC_Partymode:on,off' => 'off', - 'ASC_Roommate_Device' => 'none', - 'ASC_Roommate_Reading' => 'state', - 'ASC_Self_Defense_Exclude:on,off' => 'off', - 'ASC_BrightnessMinVal' => -1, - 'ASC_BrightnessMaxVal' => -1, - 'ASC_WiggleValue' => 5, + 'ASC_Partymode:on,off' => '-', + 'ASC_Roommate_Device' => '-', + 'ASC_Roommate_Reading' => '-', + 'ASC_Self_Defense_Exclude:on,off' => '-', + 'ASC_WiggleValue' => '-', + 'ASC_WindParameters' => '-', + 'ASC_DriveUpMaxDuration' => '-', ); my %posSetCmds = ( @@ -221,6 +227,7 @@ sub Define($$) { my ( $hash, $def ) = @_; my @a = split( '[ \t][ \t]*', $def ); + return $@ unless ( FHEM::Meta::SetInternals($hash) ); return 'only one AutoShuttersControl instance allowed' if ( devspec2array('TYPE=AutoShuttersControl') > 1 ) ; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen @@ -260,10 +267,6 @@ sub Define($$) { if ( $ascDev->getAutoShuttersControlMorning eq 'none' ); CommandAttr( undef, $name . ' ASC_autoShuttersControlEvening on' ) if ( $ascDev->getAutoShuttersControlEvening eq 'none' ); - CommandAttr( undef, $name . ' ASC_temperatureReading temperature' ) - if ( $ascDev->getTempReading eq 'none' ); - CommandAttr( undef, $name . ' ASC_freezeTemp 3' ) - if ( $ascDev->getFreezeTemp eq 'none' ); CommandAttr( undef, $name . ' devStateIcon selfeDefense.terrace:fts_door_tilt created.new.drive.timer:clock .*asleep:scene_sleeping roommate.(awoken|home):user_available residents.(home|awoken):status_available manual:fts_shutter_manual selfeDefense.active:status_locked selfeDefense.inactive:status_open day.open:scene_day night.close:scene_night shading.in:weather_sun shading.out:weather_cloudy' @@ -340,10 +343,6 @@ sub Notify($$) { readingsSingleUpdate( $hash, 'selfDefense', 'off', 0 ) if ( $ascDev->getSelfDefense eq 'none' ); - CommandDeleteReading( undef, $name . ' lockOut' ) - if ( ReadingsVal( $name, 'lockOut', 'none' ) ne 'none' ) - ; # temporär ab Version 0.2.2 - # Ist der Event ein globaler und passt zum Rest der Abfrage oben wird nach neuen Rolläden Devices gescannt und eine Liste im Rolladenmodul sortiert nach Raum generiert ShuttersDeviceScan($hash) unless ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'none' ); @@ -360,10 +359,10 @@ sub Notify($$) { WriteReadingsShuttersList($hash); UserAttributs_Readings_ForShutters( $hash, 'add' ); InternalTimer( gettimeofday() + 3, - 'AutoShuttersControl::RenewSunRiseSetShuttersTimer', + 'FHEM::AutoShuttersControl::RenewSunRiseSetShuttersTimer', $hash ); InternalTimer( gettimeofday() + 5, - 'AutoShuttersControl::AutoSearchTwilightDev', $hash ); + 'FHEM::AutoShuttersControl::AutoSearchTwilightDev', $hash ); } } elsif ( grep /^partyMode:.off$/, @{$events} ) { @@ -377,15 +376,7 @@ sub Notify($$) { { # Kommt ein globales Event und beinhaltet folgende Syntax wird die Funktion zur Verarbeitung aufgerufen if ( grep -/^(ATTR|DELETEATTR)\s(.*ASC_Roommate_Device|.*ASC_WindowRec|.*ASC_residentsDevice|.*ASC_rainSensorDevice|.*ASC_Brightness_Sensor|.*ASC_twilightDevice)(\s.*|$)/, - @{$events} - ) - { - EventProcessingGeneral( $hash, undef, join( ' ', @{$events} ) ); - } - elsif ( - grep -/^(ATTR|DELETEATTR)\s(.*ASC_Time_Up_WE_Holiday|.*ASC_Up|.*ASC_Down|.*ASC_AutoAstroModeMorning|.*ASC_AutoAstroModeMorningHorizon|.*ASC_AutoAstroModeEvening|.*ASC_AutoAstroModeEveningHorizon|.*ASC_Time_Up_Early|.*ASC_Time_Up_Late|.*ASC_Time_Down_Early|.*ASC_Time_Down_Late|.*ASC_autoAstroModeMorning|.*ASC_autoAstroModeMorningHorizon|.*ASC_PrivacyDownTime_beforNightClose|.*ASC_autoAstroModeEvening|.*ASC_autoAstroModeEveningHorizon)(\s.*|$)/, +/^(ATTR|DELETEATTR)\s(.*ASC_Time_Up_WE_Holiday|.*ASC_Up|.*ASC_Down|.*ASC_AutoAstroModeMorning|.*ASC_AutoAstroModeMorningHorizon|.*ASC_AutoAstroModeEvening|.*ASC_AutoAstroModeEveningHorizon|.*ASC_Time_Up_Early|.*ASC_Time_Up_Late|.*ASC_Time_Down_Early|.*ASC_Time_Down_Late|.*ASC_autoAstroModeMorning|.*ASC_autoAstroModeMorningHorizon|.*ASC_PrivacyDownTime_beforNightClose|.*ASC_autoAstroModeEvening|.*ASC_autoAstroModeEveningHorizon|.*ASC_Roommate_Device|.*ASC_WindowRec|.*ASC_residentsDev|.*ASC_rainSensor|.*ASC_windSensor|.*ASC_BrightnessSensor|.*ASC_twilightDevice)(\s.*|$)/, @{$events} ) { @@ -418,31 +409,33 @@ sub EventProcessingGeneral($$$) { if ( $deviceAttr eq 'ASC_Roommate_Device' ) ; # ist es ein Bewohner Device wird diese Funktion gestartet EventProcessingResidents( $hash, $device, $events ) - if ( $deviceAttr eq 'ASC_residentsDevice' ); + if ( $deviceAttr eq 'ASC_residentsDev' ); EventProcessingRain( $hash, $device, $events ) - if ( $deviceAttr eq 'ASC_rainSensorDevice' ); + if ( $deviceAttr eq 'ASC_rainSensor' ); + EventProcessingWind( $hash, $device, $events ) + if ( $deviceAttr eq 'ASC_windSensor' ); EventProcessingTwilightDevice( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_twilightDevice' ); $shutters->setShuttersDev($device) - if ( $deviceAttr eq 'ASC_Brightness_Sensor' ); + if ( $deviceAttr eq 'ASC_BrightnessSensor' ); if ( - $deviceAttr eq 'ASC_Brightness_Sensor' + $deviceAttr eq 'ASC_BrightnessSensor' and ( $shutters->getDown eq 'brightness' or $shutters->getUp eq 'brightness' ) ) { EventProcessingBrightness( $hash, $device, $events ); } - elsif ( $deviceAttr eq 'ASC_Brightness_Sensor' ) { + elsif ( $deviceAttr eq 'ASC_BrightnessSensor' ) { EventProcessingShadingBrightness( $hash, $device, $events ); } } } else { # alles was kein Devicenamen mit übergeben hat landet hier if ( $events =~ -m#^ATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDevice|ASC_rainSensorDevice|ASC_Brightness_Sensor|ASC_twilightDevice)\s(.*)$# +m#^ATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDev|ASC_rainSensor|ASC_windSensor|ASC_BrightnessSensor|ASC_twilightDevice)\s(.*)$# ) { # wurde den Attributen unserer Rolläden ein Wert zugewiesen ? AddNotifyDev( $hash, $3, $1, $2 ) if ( $3 ne 'none' ); @@ -450,7 +443,7 @@ m#^ATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDevice|ASC_rainSe "AutoShuttersControl ($name) - EventProcessing: ATTR" ); } elsif ( $events =~ -m#^DELETEATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDevice|ASC_rainSensorDevice|ASC_Brightness_Sensor|ASC_twilightDevice)$# +m#^DELETEATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDev|ASC_rainSensor|ASC_windSensor|ASC_BrightnessSensor|ASC_twilightDevice)$# ) { # wurde das Attribut unserer Rolläden gelöscht ? Log3( $name, 4, @@ -496,7 +489,7 @@ sub Set($$@) { elsif ( lc $cmd eq 'partymode' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ) - if ( join( ' ', @args ) ne ReadingsVal($name,'partyMode',0) ); + if ( join( ' ', @args ) ne ReadingsVal( $name, 'partyMode', 0 ) ); } elsif ( lc $cmd eq 'hardlockout' ) { return "usage: $cmd" if ( @args > 1 ); @@ -581,31 +574,14 @@ sub ShuttersDeviceScan($) { push( @{ $hash->{helper}{shuttersList} }, $_ ) ; ## einem Hash wird ein Array zugewiesen welches die Liste der erkannten Rollos beinhaltet - delFromDevAttrList( $_, 'ASC_lock-out:soft,hard' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.6 - delFromDevAttrList( $_, 'ASC_lock-outCmd:inhibit,blocked' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.6 - delFromDevAttrList( $_, - 'ASC_Pos_after_ComfortOpen:0,10,20,30,40,50,60,70,80,90,100' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.6 - - delFromDevAttrList( $_, 'ASC_Antifreeze:off,on' ) - if ( AttrVal( $_, 'ASC_Antifreeze', 'on' ) eq 'on' - or AttrVal( $_, 'ASC_Antifreeze', 'on' ) eq 'off' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.6 - - delFromDevAttrList( $_, -'ASC_AntifreezePos:5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100' - ); # temporär muss später gelöscht werden ab Version 0.2.0.7 - - delFromDevAttrList( $_, 'ASC_LockOut_Cmd:inhibit,blocked' ) - if ( AttrVal( $_, 'ASC_LockOut_Cmd', 'none' ) eq 'none' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.10 - - delFromDevAttrList( $_, 'ASC_Shading_Brightness_Sensor' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.12 - delFromDevAttrList( $_, 'ASC_Shading_Brightness_Reading' ) - ; # temporär muss später gelöscht werden ab Version 0.2.0.12 + delFromDevAttrList( $_, 'ASC_Wind_SensorDevice' ) + ; # temporär muss später gelöscht werden ab Version 0.4.0.10 + delFromDevAttrList( $_, 'ASC_Wind_SensorReading' ) + ; # temporär muss später gelöscht werden ab Version 0.4.0.10 + delFromDevAttrList( $_, 'ASC_Wind_minMaxSpeed' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta6 + delFromDevAttrList( $_, 'ASC_Wind_Pos' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta6 $shuttersList = $shuttersList . ',' . $_; $shutters->setShuttersDev($_); @@ -614,10 +590,58 @@ sub ShuttersDeviceScan($) { $shutters->setDelayCmd('none'); $shutters->setNoOffset(0); $shutters->setPosSetCmd( $posSetCmds{ $defs{$_}->{TYPE} } ); - $shutters->setShading('out'); + $shutters->setShadingStatus( + ( $shutters->getStatus != $shutters->getShadingPos ? 'out' : 'in' ) + ); } - # $hash->{NOTIFYDEV} = $hash->{NOTIFYDEV} . $shuttersList; + ### Temporär und muss später entfernt werden + CommandAttr( undef, + $name + . ' ASC_tempSensor ' + . AttrVal( $name, 'ASC_temperatureSensor', 'none' ) . ':' + . AttrVal( $name, 'ASC_temperatureReading', 'temperature' ) ) + if ( AttrVal( $name, 'ASC_temperatureSensor', 'none' ) ne 'none' ); + CommandAttr( undef, + $name + . ' ASC_residentsDev ' + . AttrVal( $name, 'ASC_residentsDevice', 'none' ) . ':' + . AttrVal( $name, 'ASC_residentsDeviceReading', 'state' ) ) + if ( AttrVal( $name, 'ASC_residentsDevice', 'none' ) ne 'none' ); + CommandAttr( undef, + $name + . ' ASC_rainSensor ' + . AttrVal( $name, 'ASC_rainSensorDevice', 'none' ) . ':' + . AttrVal( $name, 'ASC_rainSensorReading', 'rain' ) . ' 100 ' + . AttrVal( $name, 'ASC_rainSensorShuttersClosedPos', 50 ) ) + if ( AttrVal( $name, 'ASC_rainSensorDevice', 'none' ) ne 'none' ); + CommandAttr( undef, + $name + . ' ASC_brightnessDriveUpDown ' + . AttrVal( $name, 'ASC_brightnessMinVal', 500 ) . ':' + . AttrVal( $name, 'ASC_brightnessMaxVal', 800 ) ) + if ( AttrVal( $name, 'ASC_brightnessMinVal', 'none' ) ne 'none' ); + + CommandDeleteAttr( undef, $name . ' ASC_temperatureSensor' ) + if ( AttrVal( $name, 'ASC_temperatureSensor', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_temperatureReading' ) + if ( AttrVal( $name, 'ASC_temperatureReading', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_residentsDevice' ) + if ( AttrVal( $name, 'ASC_residentsDevice', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_residentsDeviceReading' ) + if ( AttrVal( $name, 'ASC_residentsDeviceReading', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_rainSensorDevice' ) + if ( AttrVal( $name, 'ASC_rainSensorDevice', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_rainSensorReading' ) + if ( AttrVal( $name, 'ASC_rainSensorReading', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_rainSensorShuttersClosedPos' ) + if ( + AttrVal( $name, 'ASC_rainSensorShuttersClosedPos', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_brightnessMinVal' ) + if ( AttrVal( $name, 'ASC_brightnessMinVal', 'none' ) ne 'none' ); + CommandDeleteAttr( undef, $name . ' ASC_brightnessMaxVal' ) + if ( AttrVal( $name, 'ASC_brightnessMaxVal', 'none' ) ne 'none' ); + $hash->{NOTIFYDEV} = "global," . $name . $shuttersList; if ( $ascDev->getMonitoredDevs ne 'none' ) { @@ -683,22 +707,24 @@ sub UserAttributs_Readings_ForShutters($$) { addToDevAttrList( $_, $attrib ) ; ## fhem.pl bietet eine Funktion um ein userAttr Attribut zu befüllen. Wir schreiben also in den Attribut userAttr alle unsere Attribute rein. Pro Rolladen immer ein Attribut pro Durchlauf ## Danach werden die Attribute die im userAttr stehen gesetzt und mit default Werten befüllt + ## CommandAttr hat nicht funktioniert. Führte zu Problemen + ## https://github.com/LeonGaultier/fhem-AutoShuttersControl/commit/e33d3cc7815031b087736c1054b98c57817e7083 if ( $cmd eq 'add' ) { if ( ref($attribValue) ne 'ARRAY' ) { $attr{$_}{ ( split( ':', $attrib ) )[0] } = $attribValue if ( - not - defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) ); + not defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) + and $attribValue ne '-' ); } else { $attr{$_}{ ( split( ':', $attrib ) )[0] } = $attribValue->[ AttrVal( $_, 'ASC', 2 ) ] if ( - not - defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) ); + not defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) + and $attrib eq 'ASC_Pos_Reading' ); } - ## Oder das Attribut wird wieder gelöscht. } + ## Oder das Attribut wird wieder gelöscht. elsif ( $cmd eq 'del' ) { $shutters->setShuttersDev($_); @@ -714,13 +740,20 @@ sub UserAttributs_Readings_ForShutters($$) { ## Fügt dem NOTIFYDEV Hash weitere Devices hinzu sub AddNotifyDev($@) { + ### Beispielaufruf: AddNotifyDev( $hash, $3, $1, $2 ) if ( $3 ne 'none' ); my ( $hash, $dev, $shuttersDev, $shuttersAttr ) = @_; + + $dev = ( split( ':', $dev ) )[0]; + my ( $key, $value ) = split( ':', ( split( ' ', $dev ) )[0], 2 ) + ; ## Wir versuchen die Device Attribute anders zu setzen. device=DEVICE reading=READING + $dev = $key; + my $name = $hash->{NAME}; my $notifyDev = $hash->{NOTIFYDEV}; - $notifyDev = "" if ( !$notifyDev ); - my %hash; + $notifyDev = '' if ( !$notifyDev ); + my %hash; %hash = map { ( $_ => 1 ) } split( ",", "$notifyDev,$dev" ); @@ -770,8 +803,11 @@ sub EventProcessingWindowRec($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; - if ( $events =~ m#state:\s(open(ed)?|closed|tilted)# # weitere mögliche Events (opened / closed) - and IsAfterShuttersManualBlocking($shuttersDev) ) + if ( + $events =~ + m#state:\s(open(ed)?|closed|tilted)# # weitere mögliche Events (opened / closed) + and IsAfterShuttersManualBlocking($shuttersDev) + ) { $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; @@ -781,9 +817,8 @@ sub EventProcessingWindowRec($@) { $shutters->setHardLockOut('off') if ( $1 eq 'closed' and $shutters->getShuttersPlace eq 'terrace' ); $shutters->setHardLockOut('on') - if ( ($1 eq 'open' or $1 eq 'opened') and $shutters->getShuttersPlace eq 'terrace' ); - - $shutters->setNoOffset(1); + if ( ( $1 eq 'open' or $1 eq 'opened' ) + and $shutters->getShuttersPlace eq 'terrace' ); my $queryShuttersPosWinRecTilted = ( $shutters->getShuttersPosCmdValueNegate @@ -796,71 +831,83 @@ sub EventProcessingWindowRec($@) { : $shutters->getStatus < $shutters->getComfortOpenPos ); -# ## Wird erstmal deaktiviert da es Sinnlos ist in meinen Augen -# if ( $shutters->getDelayCmd ne 'none' and $1 eq 'closed' ) -# { # Es wird geschaut ob wärend der Fenster offen Phase ein Fahrbefehl über das Modul kam,wenn ja wird dieser aus geführt -# $shutters->setLastDrive('delayed drive - window closed'); -# ShuttersCommandSet( $hash, $shuttersDev, $shutters->getDelayCmd ); -# } - if ( $1 eq 'closed' - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) - and ($shutters->getModeDown eq $homemode - or ( $shutters->getModeDown eq 'absent' - and $homemode eq 'gone' ) - or $shutters->getModeDown eq 'always') ) - { - if ( $shutters->getStatus == $shutters->getVentilatePos + if ( + $1 eq 'closed' + and IsAfterShuttersTimeBlocking($shuttersDev) + and ( $shutters->getStatus == $shutters->getVentilatePos or $shutters->getStatus == $shutters->getComfortOpenPos or $shutters->getStatus == $shutters->getOpenPos ) + ) + { + my $homemode = $shutters->getRoommatesStatus; + $homemode = $ascDev->getResidentsStatus + if ( $homemode eq 'none' ); + + if ( + IsDay($shuttersDev) + and $shutters->getStatus != $shutters->getOpenPos + and ( $homemode ne 'asleep' + or $homemode ne 'gotosleep' + or $homemode eq 'none' ) + ) { - my $homemode = $shutters->getRoommatesStatus; - $homemode = $ascDev->getResidentsStatus - if ( $homemode eq 'none' ); + $shutters->setLastDrive('window day closed'); + $shutters->setNoOffset(1); + $shutters->setDriveCmd( + ( + $shutters->getLastPos != $shutters->getClosedPos + ? $shutters->getLastPos + : $shutters->getOpenPos + ) + ); + } - if ( - IsDay( $hash, $shuttersDev ) - and $shutters->getStatus != $shutters->getOpenPos - and ( $homemode ne 'asleep' - or $homemode ne 'gotosleep' - or $homemode eq 'none' ) - ) - { - $shutters->setLastDrive('window day closed'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getLastPos ); - } - - elsif (not IsDay( $hash, $shuttersDev ) - or $homemode eq 'asleep' - or $homemode eq 'gotosleep' ) - { - $shutters->setLastDrive('window night closed'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getClosedPos ); - } + elsif (not IsDay($shuttersDev) + or $homemode eq 'asleep' + or $homemode eq 'gotosleep' ) + { + $shutters->setLastDrive('window night closed'); + $shutters->setNoOffset(1); + $shutters->setDriveCmd( $shutters->getClosedPos ); } } elsif ( ( $1 eq 'tilted' - or ( ($1 eq 'open' or $1 eq 'opened') and $shutters->getSubTyp eq 'twostate' ) + or ( ( $1 eq 'open' or $1 eq 'opened' ) + and $shutters->getSubTyp eq 'twostate' ) ) and $shutters->getVentilateOpen eq 'on' and $queryShuttersPosWinRecTilted ) { $shutters->setLastDrive('ventilate - window open'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getVentilatePos ); + $shutters->setNoOffset(1); + $shutters->setDriveCmd( $shutters->getVentilatePos ); } - elsif ( ($1 eq 'open' or $1 eq 'opened') - and $shutters->getSubTyp eq 'threestate' - and $ascDev->getAutoShuttersControlComfort eq 'on' - and $queryShuttersPosWinRecComfort ) + elsif ( ( $1 eq 'open' or $1 eq 'opened' ) + and $shutters->getSubTyp eq 'threestate' ) { - $shutters->setLastDrive('comfort - window open'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getComfortOpenPos ); + my $posValue; + my $setLastDrive; + if ( $ascDev->getAutoShuttersControlComfort eq 'on' + and $queryShuttersPosWinRecComfort ) + { + $posValue = $shutters->getComfortOpenPos; + $setLastDrive = 'comfort - window open'; + } + elsif ( $queryShuttersPosWinRecTilted + and $shutters->getVentilateOpen eq 'on' ) + { + $posValue = $shutters->getVentilatePos; + $setLastDrive = 'ventilate - window open'; + } + + if ( defined($posValue) and $posValue ) { + $shutters->setLastDrive($setLastDrive); + $shutters->setNoOffset(1); + $shutters->setDriveCmd($posValue); + } } } } @@ -881,14 +928,20 @@ sub EventProcessingRoommate($@) { "AutoShuttersControl ($name) - EventProcessingRoommate: $shuttersDev und Events $events" ); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; + my $getRoommatesLastStatus = $shutters->getRoommatesLastStatus; + if ( ( $1 eq 'home' or $1 eq 'awoken' ) and ( $shutters->getRoommatesStatus eq 'home' or $shutters->getRoommatesStatus eq 'awoken' ) and $ascDev->getAutoShuttersControlMorning eq 'on' - - and ( $shutters->getModeUp eq 'always' - or $shutters->getModeUp eq 'home' ) + and ( $getModeUp eq 'home' + or $getModeUp eq 'always' + or $getModeDown eq 'home' + or $getModeDown eq 'always' ) + and IsAfterShuttersManualBlocking($shuttersDev) ) { Log3( $name, 4, @@ -896,11 +949,13 @@ sub EventProcessingRoommate($@) { ); if ( ( - $shutters->getRoommatesLastStatus eq 'asleep' - or $shutters->getRoommatesLastStatus eq 'awoken' + $getRoommatesLastStatus eq 'asleep' + or $getRoommatesLastStatus eq 'awoken' ) - and IsDay( $hash, $shuttersDev ) - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) + and IsDay($shuttersDev) + and IsAfterShuttersTimeBlocking($shuttersDev) + and ( $getModeUp eq 'home' + or $getModeUp eq 'always' ) ) { Log3( $name, 4, @@ -913,19 +968,20 @@ sub EventProcessingRoommate($@) { if ( ( - $shutters->getRoommatesLastStatus eq 'absent' - or $shutters->getRoommatesLastStatus eq 'gone' - or $shutters->getRoommatesLastStatus eq 'home' + $getRoommatesLastStatus eq 'absent' + or $getRoommatesLastStatus eq 'gone' + + # or $getRoommatesLastStatus eq 'home' ) - and ( $shutters->getModeUp eq 'home' - or $shutters->getModeUp eq 'always' - or $shutters->getModeDown eq 'home' - or $shutters->getModeDown eq 'always' ) and $shutters->getRoommatesStatus eq 'home' ) { - if ( not IsDay( $hash, $shuttersDev ) - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) ) + if ( + not IsDay($shuttersDev) + and IsAfterShuttersTimeBlocking($shuttersDev) + and ( $getModeDown eq 'home' + or $getModeDown eq 'always' ) + ) { my $position; $shutters->setLastDrive('roommate home'); @@ -943,9 +999,14 @@ sub EventProcessingRoommate($@) { ShuttersCommandSet( $hash, $shuttersDev, $position ); } - elsif ( IsDay( $hash, $shuttersDev ) + elsif ( + IsDay($shuttersDev) and $shutters->getStatus == $shutters->getClosedPos - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) ) + and IsAfterShuttersTimeBlocking($shuttersDev) + and ( $getModeUp eq 'home' + or $getModeUp eq 'always' ) + and not $shutters->getIfInShading + ) { $shutters->setLastDrive('roommate home'); ShuttersCommandSet( $hash, $shuttersDev, @@ -955,11 +1016,12 @@ sub EventProcessingRoommate($@) { } elsif ( ( - $shutters->getModeDown eq 'always' - or $shutters->getModeDown eq 'home' + $getModeDown eq 'always' + or $getModeDown eq 'home' ) and ( $1 eq 'gotosleep' or $1 eq 'asleep' ) and $ascDev->getAutoShuttersControlEvening eq 'on' + and IsAfterShuttersManualBlocking($shuttersDev) ) { my $position; @@ -978,9 +1040,9 @@ sub EventProcessingRoommate($@) { ShuttersCommandSet( $hash, $shuttersDev, $position ); } - elsif ( $shutters->getModeDown eq 'absent' + elsif ( $getModeDown eq 'absent' and $1 eq 'absent' - and not IsDay( $hash, $shuttersDev ) ) + and not IsDay($shuttersDev) ) { $shutters->setLastDrive('roommate absent'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getClosedPos ); @@ -991,12 +1053,15 @@ sub EventProcessingRoommate($@) { sub EventProcessingResidents($@) { my ( $hash, $device, $events ) = @_; - my $name = $device; - my $reading = $ascDev->getResidentsReading; + my $name = $device; + my $reading = $ascDev->getResidentsReading; + my $getResidentsLastStatus = $ascDev->getResidentsLastStatus; if ( $events =~ m#$reading:\s(absent)# ) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; $shutters->setHardLockOut('off'); if ( CheckIfShuttersWindowRecOpen($shuttersDev) != 0 @@ -1004,11 +1069,11 @@ sub EventProcessingResidents($@) { and $shutters->getSelfDefenseExclude eq 'off' or ( ( - $shutters->getModeDown eq 'absent' - or $shutters->getModeDown eq 'always' + $getModeDown eq 'absent' + or $getModeDown eq 'always' ) - and not IsDay( $hash, $shuttersDev ) - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) + and not IsDay($shuttersDev) + and IsAfterShuttersTimeBlocking($shuttersDev) ) ) { @@ -1029,6 +1094,8 @@ sub EventProcessingResidents($@) { { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; $shutters->setHardLockOut('off'); if ( $shutters->getShuttersPlace eq 'terrace' ) { $shutters->setLastDrive('selfeDefense terrace'); @@ -1038,24 +1105,26 @@ sub EventProcessingResidents($@) { } elsif ( $events =~ m#$reading:\s(home)# - and ( $ascDev->getResidentsLastStatus eq 'absent' - or $ascDev->getResidentsLastStatus eq 'gone' - or $ascDev->getResidentsLastStatus eq 'asleep' - or $ascDev->getResidentsLastStatus eq 'awoken' ) + and ( $getResidentsLastStatus eq 'absent' + or $getResidentsLastStatus eq 'gone' + or $getResidentsLastStatus eq 'asleep' + or $getResidentsLastStatus eq 'awoken' ) ) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; if ( $shutters->getStatus != $shutters->getClosedPos - and not IsDay( $hash, $shuttersDev ) + and not IsDay($shuttersDev) and $shutters->getRoommatesStatus eq 'none' - and ( $shutters->getModeDown eq 'home' - or $shutters->getModeDown eq 'always' ) - and ( $ascDev->getResidentsLastStatus ne 'asleep' - or $ascDev->getResidentsLastStatus ne 'awoken' ) - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) + and ( $getModeDown eq 'home' + or $getModeDown eq 'always' ) + and ( $getResidentsLastStatus ne 'asleep' + or $getResidentsLastStatus ne 'awoken' ) + and IsAfterShuttersTimeBlocking($shuttersDev) ) { $shutters->setLastDrive('residents home'); @@ -1065,10 +1134,11 @@ sub EventProcessingResidents($@) { $ascDev->getSelfDefense eq 'on' and CheckIfShuttersWindowRecOpen($shuttersDev) != 0 and $shutters->getSelfDefenseExclude eq 'off' - or ( $ascDev->getResidentsLastStatus eq 'gone' + or ( $getResidentsLastStatus eq 'gone' and $shutters->getShuttersPlace eq 'terrace' ) - and ( $shutters->getModeUp eq 'absent' - or $shutters->getModeUp eq 'off' ) + and ( $getModeUp eq 'absent' + or $getModeUp eq 'off' ) + and not $shutters->getIfInShading ) { $shutters->setLastDrive('selfeDefense inactive'); @@ -1079,15 +1149,16 @@ sub EventProcessingResidents($@) { } elsif ( $shutters->getStatus == $shutters->getClosedPos - and IsDay( $hash, $shuttersDev ) + and IsDay($shuttersDev) and $shutters->getRoommatesStatus eq 'none' - and ( $shutters->getModeUp eq 'home' - or $shutters->getModeUp eq 'always' ) - and IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) + and ( $getModeUp eq 'home' + or $getModeUp eq 'always' ) + and IsAfterShuttersTimeBlocking($shuttersDev) + and not $shutters->getIfInShading ) { - if ( $ascDev->getResidentsLastStatus eq 'asleep' - or $ascDev->getResidentsLastStatus eq 'awoken' ) + if ( $getResidentsLastStatus eq 'asleep' + or $getResidentsLastStatus eq 'awoken' ) { $shutters->setLastDrive('residents awoken'); } @@ -1102,26 +1173,29 @@ sub EventProcessingRain($@) { my ( $hash, $device, $events ) = @_; my $name = $device; my $reading = $ascDev->getRainSensorReading; - my $val; if ( $events =~ m#$reading:\s(\d+|rain|dry)# ) { - if ( $1 eq 'rain' ) { $val = 1000 } - elsif ( $1 eq 'dry' ) { $val = 0 } + my $val; + my $triggerMax = $ascDev->getRainTriggerMax; + my $triggerMin = $ascDev->getRainTriggerMin; + my $closedPos = $ascDev->getRainSensorShuttersClosedPos; + + if ( $1 eq 'rain' ) { $val = $triggerMax + 1 } + elsif ( $1 eq 'dry' ) { $val = $triggerMin } else { $val = $1 } foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); - if ( $val > 100 - and $shutters->getStatus != - $ascDev->getRainSensorShuttersClosedPos ) + if ( $val > $triggerMax + and $shutters->getStatus != $closedPos + and IsAfterShuttersManualBlocking($shuttersDev) ) { $shutters->setLastDrive('rain protection'); - $shutters->setDriveCmd( - $ascDev->getRainSensorShuttersClosedPos ); + $shutters->setDriveCmd($closedPos); } - elsif ( $val == 0 - and $shutters->getStatus == - $ascDev->getRainSensorShuttersClosedPos ) + elsif ( ( $val == 0 or $val < $triggerMax ) + and $shutters->getStatus == $closedPos + and IsAfterShuttersManualBlocking($shuttersDev) ) { $shutters->setLastDrive('rain un-protection'); $shutters->setDriveCmd( $shutters->getLastPos ); @@ -1130,23 +1204,110 @@ sub EventProcessingRain($@) { } } +sub EventProcessingWind($@) { + my ( $hash, $shuttersDev, $events ) = @_; + my $name = $hash->{NAME}; + $shutters->setShuttersDev($shuttersDev); + + my $reading = $ascDev->getWindSensorReading; + if ( $events =~ m#$reading:\s(\d+)# ) { + foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + + ASC_Debug( 'EventProcessingWind: ' + . $shutters->getShuttersDev + . ' - WindProtection1: ' + . $shutters->getWindProtection + . ' WindMax1: ' + . $shutters->getWindMax + . ' WindMin1: ' + . $shutters->getWindMin + . ' Bekommender Wert1: ' + . $1 ); + + $shutters->setWindProtection('unprotection') + if ( not defined( $shutters->getWindProtection ) + or not $shutters->getWindProtection ); + + next + if ( CheckIfShuttersWindowRecOpen($shuttersDev) != 0 + and $shutters->getShuttersPlace eq 'terrace' ); + + if ( $1 > $shutters->getWindMax + and $shutters->getWindProtection eq 'unprotection' ) + { + $shutters->setLastDrive('wind protection'); + $shutters->setDriveCmd( $shutters->getWindPos ); + $shutters->setWindProtection('protection'); + } + elsif ( $1 < $shutters->getWindMin + and $shutters->getWindProtection eq 'protection' ) + { + $shutters->setLastDrive('wind un-protection'); + $shutters->setDriveCmd( $shutters->getLastPos ); + $shutters->setWindProtection('unprotection'); + } + + ASC_Debug( 'EventProcessingWind: ' + . $shutters->getShuttersDev + . ' - WindProtection2: ' + . $shutters->getWindProtection + . ' WindMax2: ' + . $shutters->getWindMax + . ' WindMin2: ' + . $shutters->getWindMin + . ' Bekommender Wert2: ' + . $1 ); + } + } +} +########## + sub EventProcessingBrightness($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Event von einem Helligkeitssensor erkannt. Verarbeitung läuft. Sollten keine weitere Meldungen aus der Funktion kommen, so befindet sich die aktuelle Zeit nicht innerhalb der Verarbeitungszeit für Sunset oder Sunrise' + ); + return EventProcessingShadingBrightness( $hash, $shuttersDev, $events ) unless ( - int( gettimeofday() / 86400 ) != - int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) - and int( gettimeofday() / 86400 ) == - int( computeAlignTime( '24:00', $shutters->getTimeUpLate ) / 86400 ) - or int( gettimeofday() / 86400 ) != - int( computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / 86400 ) - and int( gettimeofday() / 86400 ) == - int( computeAlignTime( '24:00', $shutters->getTimeDownLate ) / 86400 ) + ( + $shutters->getModeDown eq 'brightness' + or $shutters->getModeUp eq 'brightness' + ) + or ( + ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / + 86400 + ) + and int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeUpLate ) / + 86400 + ) + ) + or ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / + 86400 + ) + and int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeDownLate ) / + 86400 + ) + ) + ) ); + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Die aktuelle Zeit befindet sich innerhalb der Sunset/Sunrise Brightness Verarbeitungszeit. Also zwischen Time Early und Time Late' + ); + my $reading = $shutters->getBrightnessReading; if ( $events =~ m#$reading:\s(\d+)# ) { my $brightnessMinVal; @@ -1165,6 +1326,16 @@ sub EventProcessingBrightness($@) { $brightnessMaxVal = $ascDev->getBrightnessMaxVal; } + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Es wird geprüft ob Sunset oder Sunrise gefahren werden soll und der aktuelle übergebene Brightness-Wert: ' + . $1 + . ' Größer dem eingestellten Sunrise-Wert: ' + . $brightnessMaxVal + . ' oder kleiner dem eingestellten Sunset-Wert: ' + . $brightnessMinVal + . ' ist' ); + if ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 @@ -1174,11 +1345,18 @@ sub EventProcessingBrightness($@) { ) and $1 > $brightnessMaxVal and $shutters->getUp eq 'brightness' + and not $shutters->getSunrise ) { Log3( $name, 4, "AutoShuttersControl ($shuttersDev) - EventProcessingBrightness: Steuerung für Morgens" ); + + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitungszeit für Sunrise wurd erkannt. Prüfe Status der Roommates' + ); + my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); @@ -1204,12 +1382,23 @@ sub EventProcessingBrightness($@) { and CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) ) { + $shutters->setSunrise(1); + $shutters->setSunset(0); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getOpenPos ); + + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitung für Sunrise. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Grund des fahrens: ' + . $shutters->getLastDrive ); } else { EventProcessingShadingBrightness( $hash, $shuttersDev, $events ); + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitung für Sunrise. Roommatestatus nicht zum hochfahren oder Fenster sind offen. Fahrbebehl bleibt aus!!! Es wird an die Event verarbeitende Beschattungsfunktion weiter gereicht' + ); } } } @@ -1222,6 +1411,7 @@ sub EventProcessingBrightness($@) { ) and $1 < $brightnessMinVal and $shutters->getDown eq 'brightness' + and not $shutters->getSunset and IsAfterShuttersManualBlocking($shuttersDev) ) { @@ -1229,6 +1419,11 @@ sub EventProcessingBrightness($@) { "AutoShuttersControl ($shuttersDev) - EventProcessingBrightness: Steuerung für Abends" ); + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitungszeit für Sunset wurd erkannt. Prüfe Status der Roommates' + ); + my $posValue; if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' @@ -1255,15 +1450,41 @@ sub EventProcessingBrightness($@) { or $shutters->getModeDown eq 'always' ) { + $shutters->setSunrise(0); + $shutters->setSunset(1); ShuttersCommandSet( $hash, $shuttersDev, $posValue ); + + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitung für Sunset. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Zielposition: ' + . $posValue + . ' Grund des fahrens: ' + . $shutters->getLastDrive ); } else { EventProcessingShadingBrightness( $hash, $shuttersDev, $events ); + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitung für Sunset. Roommatestatus nicht zum runter fahren. Fahrbebehl bleibt aus!!! Es wird an die Event verarbeitende Beschattungsfunktion weiter gereicht' + ); } } + else { + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Brightness Event kam nicht innerhalb der Verarbeitungszeit für Sunset oder Sunris oder aber für beide wurden die entsprechendne Verarbeitungsschwellen nicht erreicht.' + ); + } + } + ### Wenn es kein Brightness Reading ist muss auch die Shading Funktion nicht aufgerufen werden. +# else { EventProcessingShadingBrightness( $hash, $shuttersDev, $events ); } + else { + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Leider konnte kein Korrekter Brightnesswert aus dem Event erkannt werden. Entweder passt das Reading oder der tatsächliche nummerishce Wert des Events nicht' + ); } - else { EventProcessingShadingBrightness( $hash, $shuttersDev, $events ); } } sub EventProcessingShadingBrightness($@) { @@ -1272,25 +1493,55 @@ sub EventProcessingShadingBrightness($@) { $shutters->setShuttersDev($shuttersDev); my $reading = $shutters->getBrightnessReading; + Log3( $name, 4, + "AutoShuttersControl ($shuttersDev) - EventProcessingShadingBrightness" + ); + + ASC_Debug( 'EventProcessingShadingBrightness: ' + . $shutters->getShuttersDev + . ' - Es wird nun geprüft ob der übergebene Event ein nummerischer Wert vom Brightnessreading ist.' + ); + if ( $events =~ m#$reading:\s(\d+)# ) { + Log3( + $name, 4, +"AutoShuttersControl ($shuttersDev) - EventProcessingShadingBrightness + Brightness: " . $1 + ); + + ASC_Debug( 'EventProcessingShadingBrightness: ' + . $shutters->getShuttersDev + . ' - Nummerischer Brightness-Wert wurde erkannt. Der Wert ist: ' + . $1 ); + my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); - ShadingProcessing( - $hash, $shuttersDev, - $ascDev->getAzimuth, $ascDev->getElevation, - $1, $ascDev->getOutTemp, - $shutters->getDirection, $shutters->getShadingAngleLeft, - $shutters->getShadingAngleRight - ) - - if ( + if ( ( $shutters->getShadingMode eq 'always' or $shutters->getShadingMode eq $homemode ) - and IsDay( $hash, $shuttersDev ) - ); + and IsDay($shuttersDev) + ) + { + ShadingProcessing( + $hash, + $shuttersDev, + $ascDev->getAzimuth, + $ascDev->getElevation, + $1, + $ascDev->getOutTemp, + $shutters->getDirection, + $shutters->getShadingAngleLeft, + $shutters->getShadingAngleRight + ); + + ASC_Debug( 'EventProcessingShadingBrightness: ' + . $shutters->getShuttersDev + . ' - Alle Bedingungen zur weiteren Beschattungsverarbeitung sind erfüllt. Es wird nun die eigentliche Beschattungsfunktion aufgerufen' + ); + } } } @@ -1305,11 +1556,16 @@ sub EventProcessingTwilightDevice($@) { # SunAz = azimuth = Sonnenwinkel # SunAlt = elevation = Sonnenhöhe + ASC_Debug( 'EventProcessingTwilightDevice: ' + . $shutters->getShuttersDev + . ' - Event vom Astro oder Twilight Device wurde erkannt. Event wird verarbeitet' + ); + if ( $events =~ m#(azimuth|elevation|SunAz|SunAlt):\s(\d+.\d+)# ) { my $name = $device; my ( $azimuth, $elevation ); - $azimuth = $2 if ( $1 eq 'azimuth' or $1 eq 'SunAz' ); + $azimuth = $2 if ( $1 eq 'azimuth' or $1 eq 'SunAz' ); $elevation = $2 if ( $1 eq 'elevation' or $1 eq 'SunAlt' ); $azimuth = $ascDev->getAzimuth @@ -1317,30 +1573,46 @@ sub EventProcessingTwilightDevice($@) { $elevation = $ascDev->getElevation if ( not defined($elevation) and not $elevation ); + ASC_Debug( 'EventProcessingTwilightDevice: ' + . $name + . ' - Passendes Event wurde erkannt. Verarbeitung über alle Rolllos beginnt' + ); + foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); - ShadingProcessing( - $hash, - $shuttersDev, - $azimuth, - $elevation, - $shutters->getBrightness, - $ascDev->getOutTemp, - $shutters->getDirection, - $shutters->getShadingAngleLeft, - $shutters->getShadingAngleRight - ) - if ( + if ( ( $shutters->getShadingMode eq 'always' or $shutters->getShadingMode eq $homemode ) - and IsDay( $hash, $shuttersDev ) - ); + and IsDay($shuttersDev) + ) + { + ShadingProcessing( + $hash, + $shuttersDev, + $azimuth, + $elevation, + $shutters->getBrightness, + $ascDev->getOutTemp, + $shutters->getDirection, + $shutters->getShadingAngleLeft, + $shutters->getShadingAngleRight + ); + + ASC_Debug( 'EventProcessingTwilightDevice: ' + . $shutters->getShuttersDev + . ' - Alle Bedingungen zur weiteren Beschattungsverarbeitung sind erfüllt. Es wird nun die Beschattungsfunktion ausgeführt' + ); + } + + $shutters->setShadingStatus('out') + if ( not IsDay($shuttersDev) + and $shutters->getShadingStatus ne 'out' ); } } } @@ -1355,9 +1627,38 @@ sub ShadingProcessing($@) { ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); - $shutters->setShading('out') - if ( not IsDay( $hash, $shuttersDev ) - and $shutters->getShading ne 'out' ); + + ASC_Debug( + 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Übergebende Werte - Azimuth:' + . $azimuth + . ', Elevation: ' + . $elevation + . ', Brightness: ' + . $brightness + . ', OutTemp: ' + . $outTemp + . ', Fenster Position: ' + . $winPos + . ', Winkel Links: ' + . $angleMinus + . ', Winkel Rechts: ' + . $anglePlus + . ', Ist es nach der Zeitblockadezeit: ' + . ( IsAfterShuttersTimeBlocking($shuttersDev) ? 'JA' : 'NEIN' ) + . ', Ist es nach der manuellen Blockadezeit: ' + . ( IsAfterShuttersManualBlocking($shuttersDev) ? 'JA' : 'NEIN' ) + . ', Ist es nach der Hälfte der Beschattungswartezeit: ' + . ( + ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < + ( $shutters->getShadingWaitingPeriod / 2 ) ? 'NEIN' : 'JA' + ) + ); + + $shutters->setShadingStatus('out') + if ( not IsDay($shuttersDev) + and $shutters->getShadingStatus ne 'out' ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " @@ -1376,17 +1677,49 @@ sub ShadingProcessing($@) { or $elevation == -1 or $brightness == -1 or $outTemp == -100 - or $outTemp < $shutters->getShadingMinOutsideTemperature - or not IsDay( $hash, $shuttersDev ) - or ( int( gettimeofday() ) - $shutters->getShadingTimestamp ) < + or ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < ( $shutters->getShadingWaitingPeriod / 2 ) - or not IsAfterShuttersTimeBlocking( $hash, $shuttersDev ) ); + or not IsAfterShuttersTimeBlocking($shuttersDev) + or not IsAfterShuttersManualBlocking($shuttersDev) ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " Nach dem return" ); + my $getShadingPos = $shutters->getShadingPos; + my $getStatus = $shutters->getStatus; + my $oldShadingStatus = $shutters->getShadingStatus; + + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Alle Werte für die weitere Verarbeitung sind korrekt vorhanden und es wird nun mit der Beschattungsverarbeitung begonnen' + ); + + if ( + ( + $outTemp < $shutters->getShadingMinOutsideTemperature - 3 + or not IsDay($shuttersDev) + ) + and $shutters->getShadingStatus ne 'out' + and $getStatus != $getShadingPos + ) + { + $shutters->setShadingStatus('out'); + $shutters->setLastDrive('shading out'); + + ShuttersCommandSet( $hash, $shuttersDev, $shutters->getLastPos ); + + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Es ist Nacht oder die Aussentemperatur unterhalb der Shading Temperatur. Die Beschattung wird Zwangsbeendet' + ); + + return Log3( $name, 4, +"AutoShuttersControl ($name) - Shading Processing - Es ist Sonnenuntergang vorbei oder die Aussentemperatur unterhalb der Shading Temperatur " + ); + } + # minimalen und maximalen Winkel des Fensters bestimmen. wenn die aktuelle Sonnenposition z.B. bei 205° läge und der Wert für angleMin/Max 85° wäre, dann würden zwischen 120° und 290° beschattet. my $winPosMin = $winPos - $angleMinus; my $winPosMax = $winPos + $anglePlus; @@ -1394,74 +1727,129 @@ sub ShadingProcessing($@) { if ( $azimuth < $winPosMin or $azimuth > $winPosMax or $elevation < $shutters->getShadingMinElevation - or $brightness <= $shutters->getShadingStateChangeCloudy ) + or $brightness < $shutters->getShadingStateChangeCloudy + or $outTemp < $shutters->getShadingMinOutsideTemperature ) { - $shutters->setShading('out reserved') - if ( $shutters->getShading eq 'in' - or $shutters->getShading eq 'in reserved' ); + $shutters->setShadingStatus('out reserved') + if ( $shutters->getShadingStatus eq 'in' + or $shutters->getShadingStatus eq 'in reserved' ); - $shutters->setShading('out') - if ( $shutters->getShading eq 'out reserved' - and ( int( gettimeofday() ) - $shutters->getShadingTimestamp ) >= - $shutters->getShadingWaitingPeriod ); + $shutters->setShadingStatus('out') + if ( + ( + $shutters->getShadingStatus eq 'out reserved' + and + ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) + > $shutters->getShadingWaitingPeriod + ) + or $azimuth > $winPosMax + ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " In der Out Abfrage, Shadingwert: " - . $shutters->getShading + . $shutters->getShadingStatus . ", Zeitstempel: " - . $shutters->getShadingTimestamp ); - } - elsif ( $azimuth >= $winPosMin - and $azimuth <= $winPosMax - and $elevation >= $shutters->getShadingMinElevation - and $brightness >= $shutters->getShadingStateChangeSunny ) - { - $shutters->setShading('in reserved') - if ( $shutters->getShading eq 'out' - or $shutters->getShading eq 'out reserved' ); + . $shutters->getShadingStatusTimestamp ); - $shutters->setShading('in') - if ( $shutters->getShading eq 'in reserved' - and ( int( gettimeofday() ) - $shutters->getShadingTimestamp ) >= + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Einer der Beschattungsbedingungen wird nicht mehr erfüllt und somit wird der Beschattungsstatus um eine Stufe reduziert. Alter Status: ' + . $oldShadingStatus + . ' Neuer Status: ' + . $shutters->getShadingStatus ); + } + elsif ( $azimuth > $winPosMin + and $azimuth < $winPosMax + and $elevation > $shutters->getShadingMinElevation + and $brightness > $shutters->getShadingStateChangeSunny + and $outTemp > $shutters->getShadingMinOutsideTemperature ) + { + $shutters->setShadingStatus('in reserved') + if ( $shutters->getShadingStatus eq 'out' + or $shutters->getShadingStatus eq 'out reserved' ); + + $shutters->setShadingStatus('in') + if ( $shutters->getShadingStatus eq 'in reserved' + and + ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) > ( $shutters->getShadingWaitingPeriod / 2 ) ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " In der In Abfrage, Shadingwert: " - . $shutters->getShading + . $shutters->getShadingStatus . ", Zeitstempel: " - . $shutters->getShadingTimestamp ); + . $shutters->getShadingStatusTimestamp ); + + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Alle Beschattungsbedingungen wurden erfüllt und somit wird der Beschattungsstatus um eine Stufe angehoben. Alter Status: ' + . $oldShadingStatus + . ' Neuer Status: ' + . $shutters->getShadingStatus ); } - if ( $shutters->getShading eq 'out' or $shutters->getShading eq 'in' ) { - $shutters->setShading( $shutters->getShading ) - if ( ( int( gettimeofday() ) - $shutters->getShadingTimestamp ) >= + if ( $shutters->getShadingStatus eq 'out' + or $shutters->getShadingStatus eq 'in' ) + { + ### Erstmal rausgenommen könnte Grund für nicht mehr reinfahren in die Beschattung sein + $shutters->setShadingStatus( $shutters->getShadingStatus ) + if ( + ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) > ( $shutters->getShadingWaitingPeriod / 2 ) ); - if ( $shutters->getShading eq 'in' - and $shutters->getShadingPos != $shutters->getStatus ) + if ( $shutters->getShadingStatus eq 'in' + and $getShadingPos != $getStatus ) { my $queryShuttersShadingPos = ( $shutters->getShuttersPosCmdValueNegate - ? $shutters->getStatus > $shutters->getShadingPos - : $shutters->getStatus < $shutters->getShadingPos + ? $getStatus > $getShadingPos + : $getStatus < $getShadingPos ); - $shutters->setLastDrive('shading in'); - ShuttersCommandSet( $hash, $shuttersDev, $shutters->getShadingPos ) - if ( not $queryShuttersShadingPos ); + if ( not $queryShuttersShadingPos ) { + $shutters->setLastDrive('shading in'); + ShuttersCommandSet( $hash, $shuttersDev, $getShadingPos ); + + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Der aktuelle Beschattungsstatus ist: ' + . $shutters->getShadingStatus + . ' und somit wird nun in die Position: ' + . $getShadingPos + . ' zum Beschatten gefahren' ); + } } - elsif ( $shutters->getShading eq 'out' - and $shutters->getShadingPos == $shutters->getStatus ) + elsif ( $shutters->getShadingStatus eq 'out' + and $getShadingPos == $getStatus ) { $shutters->setLastDrive('shading out'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getLastPos ); + + ASC_Debug( 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Der aktuelle Beschattungsstatus ist: ' + . $shutters->getShadingStatus + . ' und somit wird nun in die Position: ' + . $getShadingPos + . ' zum beenden der Beschattung gefahren' ); } Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing - In der Routine zum fahren der Rollläden, Shading Wert: " - . $shutters->getShading ); + . $shutters->getShadingStatus ); + + ASC_Debug( + 'ShadingProcessing: ' + . $shutters->getShuttersDev + . ' - Der aktuelle Beschattungsstatus ist: ' + . $shutters->getShadingStatus + . ', Beschattungsstatus Zeitstempel: ' + . strftime( + "%Y.%m.%e %T", localtime( $shutters->getShadingStatusTimestamp ) + ) + ); } } @@ -1471,8 +1859,9 @@ sub EventProcessingPartyMode($) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); - if ( not IsDay( $hash, $shuttersDev ) - and $shutters->getModeDown ne 'off' ) + if ( not IsDay($shuttersDev) + and $shutters->getModeDown ne 'off' + and IsAfterShuttersManualBlocking($shuttersDev) ) { if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' ) @@ -1501,7 +1890,9 @@ sub EventProcessingPartyMode($) { ); } } - elsif ( IsDay( $hash, $shuttersDev ) ) { + elsif ( IsDay($shuttersDev) + and IsAfterShuttersManualBlocking($shuttersDev) ) + { $shutters->setLastDrive('drive after party mode'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getDelayCmd ); } @@ -1515,7 +1906,8 @@ sub EventProcessingShutters($@) { if ( $events =~ m#.*:\s(\d+)# ) { $shutters->setShuttersDev($shuttersDev); $ascDev->setPosReading; - if ( ( int( gettimeofday() ) - $shutters->getLastPosTimestamp ) > 60 + if ( ( int( gettimeofday() ) - $shutters->getLastPosTimestamp ) > + $shutters->getDriveUpMaxDuration and $shutters->getLastPos != $shutters->getStatus ) { $shutters->setLastDrive('manual'); @@ -1539,10 +1931,7 @@ sub ShuttersCommandSet($$$) { ); if ( - ( - $posValue != $shutters->getShadingPos - or $shutters->getShuttersPlace eq 'terrace' - ) + $posValue != $shutters->getShadingPos and ( ( $shutters->getPartyMode eq 'on' @@ -1562,13 +1951,22 @@ sub ShuttersCommandSet($$$) { and $ascDev->getHardLockOut eq 'on' and not $queryShuttersPosValue ) + or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + and $shutters->getShuttersPlace eq 'terrace' + and not $queryShuttersPosValue ) ) ) { $shutters->setDelayCmd($posValue); $ascDev->setDelayCmdReading; + $shutters->setNoOffset(0); Log3( $name, 4, "AutoShuttersControl ($name) - ShuttersCommandSet in Delay" ); + + ASC_Debug( 'FnShuttersCommandSet: ' + . $shutters->getShuttersDev + . ' - Die Fahrt wird zurückgestellt. Grund kann ein geöffnetes Fenster sein oder ein aktivierter Party Modus' + ); } else { $shutters->setDriveCmd($posValue); @@ -1579,6 +1977,11 @@ sub ShuttersCommandSet($$$) { Log3( $name, 4, "AutoShuttersControl ($name) - ShuttersCommandSet setDriveCmd wird aufgerufen" ); + + ASC_Debug( 'FnShuttersCommandSet: ' + . $shutters->getShuttersDev + . ' - Das Rollo wird gefahren. Kein Partymodus aktiv und das zugordnete Fenster ist entweder nicht offen oder keine Terassentür' + ); } } @@ -1591,10 +1994,8 @@ sub CreateSunRiseSetShuttersTimer($$) { return if ( IsDisabled($name) ); - my $shuttersSunriseUnixtime = - ShuttersSunrise( $hash, $shuttersDev, 'unix' ) + 1; - my $shuttersSunsetUnixtime = - ShuttersSunset( $hash, $shuttersDev, 'unix' ) + 1; + my $shuttersSunriseUnixtime = ShuttersSunrise( $shuttersDev, 'unix' ) + 1; + my $shuttersSunsetUnixtime = ShuttersSunset( $shuttersDev, 'unix' ) + 1; $shutters->setSunriseUnixTime($shuttersSunriseUnixtime); $shutters->setSunsetUnixTime($shuttersSunsetUnixtime); @@ -1675,10 +2076,10 @@ sub CreateSunRiseSetShuttersTimer($$) { } InternalTimer( $shuttersSunsetUnixtime, - 'AutoShuttersControl::SunSetShuttersAfterTimerFn', \%funcHash ) + 'FHEM::AutoShuttersControl::SunSetShuttersAfterTimerFn', \%funcHash ) if ( $ascDev->getAutoShuttersControlEvening eq 'on' ); InternalTimer( $shuttersSunriseUnixtime, - 'AutoShuttersControl::SunRiseShuttersAfterTimerFn', \%funcHash ) + 'FHEM::AutoShuttersControl::SunRiseShuttersAfterTimerFn', \%funcHash ) if ( $ascDev->getAutoShuttersControlMorning eq 'on' ); $ascDev->setStateReading('created new drive timer'); @@ -1694,6 +2095,26 @@ sub RenewSunRiseSetShuttersTimer($) { RemoveInternalTimer( $shutters->getInTimerFuncHash ); $shutters->setInTimerFuncHash(undef); CreateSunRiseSetShuttersTimer( $hash, $_ ); + + ### Temporär angelegt damit die neue Attributs Parameter Syntax verteilt werden kann +# CommandAttr(undef, $_ . ' ASC_BrightnessSensor '.AttrVal($_, 'ASC_Brightness_Sensor', 'none').':'.AttrVal($_, 'ASC_Brightness_Reading', 'brightness').' '.AttrVal($_, 'ASC_BrightnessMinVal', 500).':'.AttrVal($_, 'ASC_BrightnessMaxVal', 700)) if ( AttrVal($_, 'ASC_Brightness_Sensor', 'none') ne 'none' ); + + $attr{$_}{'ASC_BrightnessSensor'} = + AttrVal( $_, 'ASC_Brightness_Sensor', 'none' ) . ':' + . AttrVal( $_, 'ASC_Brightness_Reading', 'brightness' ) . ' ' + . AttrVal( $_, 'ASC_BrightnessMinVal', 500 ) . ':' + . AttrVal( $_, 'ASC_BrightnessMaxVal', 700 ) + if ( AttrVal( $_, 'ASC_Brightness_Sensor', 'none' ) ne 'none' ); + + delFromDevAttrList( $_, 'ASC_Brightness_Sensor' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta9 + delFromDevAttrList( $_, 'ASC_Brightness_Reading' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta9 + delFromDevAttrList( $_, 'ASC_BrightnessMinVal' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta9 + delFromDevAttrList( $_, 'ASC_BrightnessMaxVal' ) + ; # temporär muss später gelöscht werden ab Version 0.4.11beta9 + } } @@ -1748,7 +2169,8 @@ sub wiggle($$) { } } - InternalTimer( gettimeofday() + 60, 'AutoShuttersControl::SetCmdFn', \%h ); + InternalTimer( gettimeofday() + 60, + 'FHEM::AutoShuttersControl::SetCmdFn', \%h ); } #### @@ -1780,22 +2202,24 @@ sub SunSetShuttersAfterTimerFn($) { and IsAfterShuttersManualBlocking($shuttersDev) ) { - $shutters->setLastDrive( - ( - $funcHash->{privacyMode} == 1 - ? 'privacy position' - : 'night close' - ) - ); - ShuttersCommandSet( - $hash, - $shuttersDev, - ( - $funcHash->{privacyMode} == 1 - ? $shutters->getPrivacyDownPos - : $posValue - ) + my $queryShuttersPosPrivacyDown = ( + $shutters->getShuttersPosCmdValueNegate + ? $shutters->getStatus > $shutters->getPrivacyDownPos + : $shutters->getStatus < $shutters->getPrivacyDownPos ); + + if ( $funcHash->{privacyMode} == 1 + and not $queryShuttersPosPrivacyDown ) + { + $shutters->setLastDrive('privacy position'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getPrivacyDownPos ); + } + elsif ( $funcHash->{privacyMode} == 0 ) { + $shutters->setSunset(1); + $shutters->setLastDrive('night close'); + ShuttersCommandSet( $hash, $shuttersDev, $posValue ); + } } CreateSunRiseSetShuttersTimer( $hash, $shuttersDev ); @@ -1834,6 +2258,7 @@ sub SunRiseShuttersAfterTimerFn($) { ) { $shutters->setLastDrive('day open'); + $shutters->setSunrise(1); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getOpenPos ); } } @@ -1856,20 +2281,26 @@ sub CreateNewNotifyDev($) { AddNotifyDev( $hash, AttrVal( $_, 'ASC_WindowRec', 'none' ), $_, 'ASC_WindowRec' ) if ( AttrVal( $_, 'ASC_WindowRec', 'none' ) ne 'none' ); - AddNotifyDev( $hash, AttrVal( $_, 'ASC_Brightness_Sensor', 'none' ), - $_, 'ASC_Brightness_Sensor' ) - if ( AttrVal( $_, 'ASC_Brightness_Sensor', 'none' ) ne 'none' ); + AddNotifyDev( $hash, AttrVal( $_, 'ASC_BrightnessSensor', 'none' ), + $_, 'ASC_BrightnessSensor' ) + if ( AttrVal( $_, 'ASC_BrightnessSensor', 'none' ) ne 'none' ); + $shuttersList = $shuttersList . ',' . $_; } - AddNotifyDev( $hash, AttrVal( $name, 'ASC_residentsDevice', 'none' ), - $name, 'ASC_residentsDevice' ) - if ( AttrVal( $name, 'ASC_residentsDevice', 'none' ) ne 'none' ); - AddNotifyDev( $hash, AttrVal( $name, 'ASC_rainSensorDevice', 'none' ), - $name, 'ASC_rainSensorDevice' ) - if ( AttrVal( $name, 'ASC_rainSensorDevice', 'none' ) ne 'none' ); + + AddNotifyDev( $hash, AttrVal( $name, 'ASC_residentsDev', 'none' ), + $name, 'ASC_residentsDev' ) + if ( AttrVal( $name, 'ASC_residentsDev', 'none' ) ne 'none' ); + AddNotifyDev( $hash, AttrVal( $name, 'ASC_rainSensor', 'none' ), + $name, 'ASC_rainSensor' ) + if ( AttrVal( $name, 'ASC_rainSensor', 'none' ) ne 'none' ); AddNotifyDev( $hash, AttrVal( $name, 'ASC_twilightDevice', 'none' ), $name, 'ASC_twilightDevice' ) if ( AttrVal( $name, 'ASC_twilightDevice', 'none' ) ne 'none' ); + AddNotifyDev( $hash, AttrVal( $name, 'ASC_windSensor', 'none' ), + $name, 'ASC_windSensor' ) + if ( AttrVal( $name, 'ASC_windSensor', 'none' ) ne 'none' ); + $hash->{NOTIFYDEV} = $hash->{NOTIFYDEV} . $shuttersList; } @@ -1901,6 +2332,8 @@ sub GetShuttersInformation($) { $ret .= "Position"; $ret .= " "; $ret .= "Last Position"; + $ret .= " "; + $ret .= "Shading Info"; $ret .= ''; my $linecount = 1; @@ -1938,6 +2371,12 @@ sub GetShuttersInformation($) { $ret .= "" . $shutters->getStatus . ""; $ret .= " "; $ret .= "" . $shutters->getLastPos . ""; + $ret .= " "; + $ret .= "" + . $shutters->getShadingStatus . ' - ' + . strftime( "%H:%M:%S", + localtime( $shutters->getShadingStatusTimestamp ) ) + . ""; $ret .= ''; $linecount++; } @@ -1984,21 +2423,6 @@ sub GetMonitoredDevs($) { } } - ###### create Links - my $aHref; - -# create define Link -# $aHref="{host}."/fhem?cmd=set+".$::FW_CSRF."\">Create new NOTIFYDEV structure"; -# $aHref="Create new NOTIFYDEV structure"; -# $aHref="{station}{name})."+Aqicn+".$dataset->{uid}.$FW_CSRF."\">Create Station Device"; - - # $ret .= ' '; - # $ret .= ' '; - # $ret .= " "; - # $ret .= " "; - # $ret .= " "; - # $ret .= " "; - # $ret .= "".$aHref.""; $ret .= ''; $ret .= ''; @@ -2022,6 +2446,31 @@ sub AutoSearchTwilightDev($) { } } +sub GetAttrValues($@) { + my ( $dev, $attribut, $default ) = @_; + + my @values = split( ' ', + AttrVal( $dev, $attribut, ( defined($default) ? $default : 'none' ) ) ); + my ( $value1, $value2 ) = split( ':', $values[0] ); + my ( $value3, $value4 ) = split( ':', $values[1] ) + if ( defined( $values[1] ) ); + my ( $value5, $value6 ) = split( ':', $values[2] ) + if ( defined( $values[2] ) ); + my ( $value7, $value8 ) = split( ':', $values[2] ) + if ( defined( $values[3] ) ); + + return ( + $value1, + defined($value2) ? $value2 : 'none', + defined($value3) ? $value3 : 'none', + defined($value4) ? $value4 : 'none', + defined($value5) ? $value5 : 'none', + defined($value6) ? $value6 : 'none', + defined($value7) ? $value7 : 'none', + defined($value8) ? $value8 : 'none' + ); +} + # Hilfsfunktion welche meinen ReadingString zum finden der getriggerten Devices und der Zurdnung was das Device überhaupt ist und zu welchen Rolladen es gehört aus liest und das Device extraiert sub ExtractNotifyDevFromEvent($$$) { my ( $hash, $shuttersDev, $shuttersAttr ) = @_; @@ -2051,28 +2500,105 @@ sub ExtractNotifyDevFromEvent($$$) { } ## Ist Tag oder Nacht für den entsprechende Rolladen -sub IsDay($$) { - my ( $hash, $shuttersDev ) = @_; +sub IsDay($) { + my ($shuttersDev) = @_; $shutters->setShuttersDev($shuttersDev); - my $name = $hash->{NAME}; - my $isday = ( ShuttersSunrise( $hash, $shuttersDev, 'unix' ) > - ShuttersSunset( $hash, $shuttersDev, 'unix' ) ? 1 : 0 ); + my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) > + ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 ); my $respIsDay = $isday; - $respIsDay = ( ($shutters->getBrightness > $shutters->getBrightnessMinVal and $isday) ? 1 : 0 ) - if ( $shutters->getDown eq 'brightness' ); + ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay ); - $respIsDay = ( (($shutters->getBrightness > $shutters->getBrightnessMaxVal and not $isday) or $respIsDay) ? 1 : 0 ) - if ( $shutters->getUp eq 'brightness' ); + if ( + ( + $shutters->getDown eq 'brightness' + or $shutters->getUp eq 'brightness' + ) + and ( + ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / + 86400 + ) + and int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeUpLate ) / + 86400 + ) + ) + or ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / + 86400 + ) + and int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeDownLate ) / + 86400 + ) + ) + ) + ) + { + my $brightnessMinVal; + if ( $shutters->getBrightnessMinVal > -1 ) { + $brightnessMinVal = $shutters->getBrightnessMinVal; + } + else { + $brightnessMinVal = $ascDev->getBrightnessMinVal; + } + + my $brightnessMaxVal; + if ( $shutters->getBrightnessMaxVal > -1 ) { + $brightnessMaxVal = $shutters->getBrightnessMaxVal; + } + else { + $brightnessMaxVal = $ascDev->getBrightnessMaxVal; + } + + $respIsDay = ( + ( + ( $shutters->getBrightness > $brightnessMinVal and $isday ) + or $shutters->getSunset + ) ? 1 : 0 + ) if ( $shutters->getDown eq 'brightness' ); + + ASC_Debug( 'FnIsDay: ' + . $shuttersDev + . ' getDownBrightness: ' + . $respIsDay + . ' Brightness: ' + . $shutters->getBrightness + . ' BrightnessMin: ' + . $brightnessMinVal + . ' Sunset: ' + . $shutters->getSunset ); + + $respIsDay = ( + ( + ( $shutters->getBrightness > $brightnessMaxVal and not $isday ) + or $respIsDay + or $shutters->getSunrise + ) ? 1 : 0 + ) if ( $shutters->getUp eq 'brightness' ); + + ASC_Debug( 'FnIsDay: ' + . $shuttersDev + . ' getUpBrightness: ' + . $respIsDay + . ' Brightness: ' + . $shutters->getBrightness + . ' BrightnessMax: ' + . $brightnessMaxVal + . ' Sunset: ' + . $shutters->getSunrise ); + } return $respIsDay; } -sub ShuttersSunrise($$$) { - my ( $hash, $shuttersDev, $tm ) = +sub ShuttersSunrise($$) { + my ( $shuttersDev, $tm ) = @_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit - my $name = $hash->{NAME}; my $autoAstroMode; $shutters->setShuttersDev($shuttersDev); @@ -2163,15 +2689,109 @@ sub ShuttersSunrise($$$) { } } else { - $shuttersSunriseUnixtime = ( - computeAlignTime( - '24:00', - sunrise_abs( - $autoAstroMode, 0, - $shutters->getTimeUpWeHoliday + if ( + IsWe() + and ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ) / 86400 ) - ) + 1 - ); + or int( gettimeofday() / 86400 ) != int( + ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ) / 86400 + ) + ) + ) + { + $shuttersSunriseUnixtime = ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ); + } + elsif ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, + 0, + $shutters->getTimeUpEarly, + $shutters->getTimeUpLate + ) + ) + 1 + ) / 86400 + ) + ) + { + $shuttersSunriseUnixtime = ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, + 0, + $shutters->getTimeUpEarly, + $shutters->getTimeUpLate + ) + ) + 1 + ); + } + else { + if ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ) / 86400 + ) + ) + { + $shuttersSunriseUnixtime = ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 86401 + ); + } + else { + $shuttersSunriseUnixtime = ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ); + } + } } } else { @@ -2283,17 +2903,17 @@ sub ShuttersSunrise($$$) { } } -sub IsAfterShuttersTimeBlocking($$) { - my ( $hash, $shuttersDev ) = @_; +sub IsAfterShuttersTimeBlocking($) { + my ($shuttersDev) = @_; $shutters->setShuttersDev($shuttersDev); if ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < $shutters->getBlockingTimeAfterManual - or ( not IsDay( $hash, $shuttersDev ) + or ( not IsDay($shuttersDev) and $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) < $shutters->getBlockingTimeBeforDayOpen ) - or ( IsDay( $hash, $shuttersDev ) + or ( IsDay($shuttersDev) and $shutters->getSunsetUnixTime - ( int( gettimeofday() ) ) < $shutters->getBlockingTimeBeforNightClose ) ) @@ -2308,7 +2928,19 @@ sub IsAfterShuttersManualBlocking($) { my $shuttersDev = shift; $shutters->setShuttersDev($shuttersDev); - if ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < + if ( $ascDev->getblockAscDrivesAfterManual + and $shutters->getStatus != $shutters->getOpenPos + and $shutters->getStatus != $shutters->getClosedPos + and $shutters->getStatus != $shutters->getWindPos + and $shutters->getStatus != $shutters->getShadingPos + and $shutters->getStatus != $shutters->getComfortOpenPos + and $shutters->getStatus != $shutters->getVentilatePos + and $shutters->getStatus != $shutters->getAntiFreezePos + and $shutters->getLastDrive eq 'manual' ) + { + return 0; + } + elsif ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < $shutters->getBlockingTimeAfterManual ) { return 0; @@ -2317,10 +2949,9 @@ sub IsAfterShuttersManualBlocking($) { else { return 1 } } -sub ShuttersSunset($$$) { - my ( $hash, $shuttersDev, $tm ) = +sub ShuttersSunset($$) { + my ( $shuttersDev, $tm ) = @_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit - my $name = $hash->{NAME}; my $autoAstroMode; $shutters->setShuttersDev($shuttersDev); @@ -2353,7 +2984,7 @@ sub ShuttersSunset($$$) { ) + 1 ); if ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' ) { - $shuttersSunsetUnixtime = ( $shuttersSunsetUnixtime + 86400 ) + $shuttersSunsetUnixtime += 86400 if ( $shuttersSunsetUnixtime < ( $oldFuncHash->{sunsettime} + 180 ) and $oldFuncHash->{sunsettime} < gettimeofday() ); @@ -2385,7 +3016,11 @@ sub CheckIfShuttersWindowRecOpen($) { my $shuttersDev = shift; $shutters->setShuttersDev($shuttersDev); - if ( $shutters->getWinStatus eq 'open' or $shutters->getWinStatus eq 'opened' ) { return 2; } + if ( $shutters->getWinStatus eq 'open' + or $shutters->getWinStatus eq 'opened' ) + { + return 2; + } elsif ( $shutters->getWinStatus eq 'tilted' and $shutters->getSubTyp eq 'threestate' ) { @@ -2395,7 +3030,7 @@ sub CheckIfShuttersWindowRecOpen($) { } sub makeReadingName($) { - my ($name) = @_; + my ($rname) = @_; my %charHash = ( "ä" => "ae", "Ä" => "Ae", @@ -2407,11 +3042,10 @@ sub makeReadingName($) { ); my $charHashkeys = join( "|", keys(%charHash) ); - $name = "UNDEFINED" if ( !defined($name) ); - return $name if ( $name =~ m/^\./ ); - $name =~ s/($charHashkeys)/$charHash{$1}/gi; - $name =~ s/[^a-z0-9._\-\/]/_/gi; - return $name; + return $rname if ( $rname =~ m/^\./ ); + $rname =~ s/($charHashkeys)/$charHash{$1}/gi; + $rname =~ s/[^a-z0-9._\-\/]/_/gi; + return $rname; } sub TimeMin2Sec($) { @@ -2423,54 +3057,15 @@ sub TimeMin2Sec($) { } sub IsWe() { - my ( undef, undef, undef, undef, undef, undef, $wday, undef, undef ) = - localtime( gettimeofday() ); - my $we = ( ( $wday == 0 || $wday == 6 ) ? 1 : 0 ); - - if ( !$we ) { - foreach my $h2we ( split( ",", AttrVal( "global", "holiday2we", "" ) ) ) - { - my ( $a, $b ) = - ReplaceEventMap( $h2we, [ $h2we, Value($h2we) ], 0 ); - $we = 1 if ( $b && $b ne "none" ); - } - } + my $we = main::IsWe(); return $we; } sub IsWeTomorrow() { - my ( undef, undef, undef, undef, undef, undef, $wday, undef, undef ) = - localtime( gettimeofday() ); - my $we = ( - ( ( ( $wday + 1 == 7 ? 0 : $wday + 1 ) ) == 0 || ( $wday + 1 ) == 6 ) - ? 1 - : 0 - ); - - if ( !$we ) { - foreach my $h2we ( split( ",", AttrVal( "global", "holiday2we", "" ) ) ) - { - my ( $a, $b ) = ReplaceEventMap( $h2we, - [ $h2we, ReadingsVal( $h2we, "tomorrow", "none" ) ], 0 ); - $we = 1 if ( $b && $b ne "none" ); - } - } + my $we = main::IsWe('tomorrow'); return $we; } -sub IsHoliday($) { - my $hash = shift; - my $name = $hash->{NAME}; - - return ( - ReadingsVal( - AttrVal( $name, 'ASC_timeUpHolidayDevice', 'none' ), - AttrVal( $name, 'ASC_timeUpHolidayReading', 'state' ), - 0 - ) == 1 ? 1 : 0 - ); -} - sub SetCmdFn($) { my $h = shift; my $shuttersDev = $h->{shuttersDev}; @@ -2491,8 +3086,23 @@ sub SetCmdFn($) { else { $shutters->setLastDrive( ReadingsVal( $shuttersDev, 'ASC_ShuttersLastDrive', 'none' ) ); + ASC_Debug( 'FnSetCmdFn: ' + . $shuttersDev + . ' - Abbruch aktuelle Position ist gleich der Zielposition ' + . $shutters->getStatus . '=' + . $posValue ); + return; } + ASC_Debug( 'FnSetCmdFn: ' + . $shuttersDev + . ' - Rolllo wird gefahren, aktuelle Position: ' + . $shutters->getStatus + . ', Zielposition: ' + . $posValue + . '. Grund der Fahrt: ' + . $shutters->getLastDrive ); + CommandSet( undef, $shuttersDev . ':FILTER=' @@ -2502,9 +3112,23 @@ sub SetCmdFn($) { . $posValue ); } +sub ASC_Debug($) { + return + unless ( AttrVal( $ascDev->getName, 'ASC_debug', 0 ) ); + + my $debugMsg = shift; + my $debugTimestamp = strftime( "%Y.%m.%e %T", localtime(time) ); + + print( + "\n" . 'ASC_DEBUG!!! ' . $debugTimestamp . ' - ' . $debugMsg . "\n" ); +} + +###################################### +###################################### ########## Begin der Klassendeklarierungen für OOP (Objektorientierte Programmierung) ######################### ## Klasse Rolläden (Shutters) und die Subklassen Attr und Readings ## ## desweiteren wird noch die Klasse ASC_Roommate mit eingebunden + package ASC_Shutters; our @ISA = qw(ASC_Shutters::Readings ASC_Shutters::Attr ASC_Roommate ASC_Window); @@ -2523,7 +3147,8 @@ BEGIN { readingsSingleUpdate gettimeofday InternalTimer - CommandSet) + CommandSet + Log3) ); } @@ -2581,11 +3206,13 @@ sub setNoOffset { sub setDriveCmd { my ( $self, $posValue ) = @_; - my $offSet = 0; + my $offSet; + my $offSetStart; ### antifreeze Routine if ( $shutters->getFreezeStatus > 0 ) { if ( $shutters->getFreezeStatus != 1 ) { + $posValue = $shutters->getStatus; $shutters->setLastDrive('no drive - antifreeze defense'); $shutters->setLastDriveReading; @@ -2603,17 +3230,31 @@ sub setDriveCmd { posValue => $posValue, ); - $offSet = $shutters->getOffset if ( $shutters->getOffset > 0 ); - $offSet = $ascDev->getShuttersOffset if ( $shutters->getOffset == -1 ); + $offSet = $shutters->getOffset if ( $shutters->getOffset > -1 ); + $offSet = $ascDev->getShuttersOffset if ( $shutters->getOffset < 0 ); + $offSetStart = $shutters->getOffsetStart; - InternalTimer( - gettimeofday() + int( rand($offSet) + $shutters->getOffsetStart ), - 'AutoShuttersControl::SetCmdFn', \%h ) - if ( $offSet > 0 and not $shutters->getNoOffset ); - AutoShuttersControl::SetCmdFn( \%h ) - if ( $offSet == 0 or $shutters->getNoOffset ); + if ( $offSetStart > 0 and not $shutters->getNoOffset ) { + InternalTimer( + gettimeofday() + int( rand($offSet) + $shutters->getOffsetStart ), + 'FHEM::AutoShuttersControl::SetCmdFn', \%h ); + + FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' + . $shutters->getShuttersDev + . ' - versetztes fahren' ); + } + elsif ( $offSetStart < 1 or $shutters->getNoOffset ) { + FHEM::AutoShuttersControl::SetCmdFn( \%h ); + FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' + . $shutters->getShuttersDev + . ' - NICHT versetztes fahren' ); + } + + FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' + . $shutters->getShuttersDev + . ' - NoOffset: ' + . ( $shutters->getNoOffset ? 'JA' : 'NEIN' ) ); $shutters->setNoOffset(0); - return 0; } @@ -2624,6 +3265,13 @@ sub setSunsetUnixTime { return 0; } +sub setSunset { + my ( $self, $value ) = @_; + + $self->{ $self->{shuttersDev} }{sunset} = $value; + return 0; +} + sub setSunriseUnixTime { my ( $self, $unixtime ) = @_; @@ -2631,6 +3279,13 @@ sub setSunriseUnixTime { return 0; } +sub setSunrise { + my ( $self, $value ) = @_; + + $self->{ $self->{shuttersDev} }{sunrise} = $value; + return 0; +} + sub setDelayCmd { my ( $self, $posValue ) = @_; @@ -2721,8 +3376,7 @@ sub getFreezeStatus { if ( $shutters->getAntiFreeze eq 'soft' ) { return 1; } - elsif ($shutters->getAntiFreeze eq $daytime ) - { + elsif ( $shutters->getAntiFreeze eq $daytime ) { return 2; } elsif ( $shutters->getAntiFreeze eq 'hard' ) { @@ -2812,12 +3466,32 @@ sub getSunsetUnixTime { return $self->{ $self->{shuttersDev} }{sunsettime}; } +sub getSunset { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{sunset} ) + ? $self->{ $self->{shuttersDev} }{sunset} + : 0 + ); +} + sub getSunriseUnixTime { my $self = shift; return $self->{ $self->{shuttersDev} }{sunrisetime}; } +sub getSunrise { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{sunrise} ) + ? $self->{ $self->{shuttersDev} }{sunrise} + : 0 + ); +} + sub getRoommatesStatus { my $self = shift; my $loop = 0; @@ -2869,32 +3543,62 @@ sub getRoommatesLastStatus { } ### Begin Beschattung Objekt mit Daten befüllen -sub setShading { +sub setShadingStatus { my ( $self, $value ) = @_; ### Werte für value = in, out, in reserved, out reserved - $self->{ $self->{shuttersDev} }{Shading}{VAL} = $value + $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value if ( defined($value) ); - $self->{ $self->{shuttersDev} }{Shading}{TIME} = int( gettimeofday() ) - if ( defined( $self->{ $self->{shuttersDev} }{Shading} ) ); + $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = int( gettimeofday() ) + if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) ); return 0; } -sub getShading { # Werte für value = in, out, in reserved, out reserved - my $self = shift; +sub setWindProtection { # Werte protection, unprotection + my ( $self, $value ) = @_; - return $self->{ $self->{shuttersDev} }{Shading}{VAL} - if ( defined( $self->{ $self->{shuttersDev} }{Shading} ) - and defined( $self->{ $self->{shuttersDev} }{Shading}{VAL} ) ); + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value + if ( defined($value) ); + return 0; } -sub getShadingTimestamp { +sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved my $self = shift; - return $self->{ $self->{shuttersDev} }{Shading}{TIME} + return $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} + if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) + and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) ); +} + +sub getIfInShading { + my $self = shift; + + return ( + ( + $shutters->getShadingMode eq 'always' + or $shutters->getShadingMode eq 'home' + ) + and $shutters->getShadingStatus eq 'in' ? 1 : 0 + ); +} + +sub getWindProtection { # Werte protection, unprotection + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} + if ( defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} ) + and + defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} ) + ); +} + +sub getShadingStatusTimestamp { + my $self = shift; + + return $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} if ( defined( $self->{ $self->{shuttersDev} } ) - and defined( $self->{ $self->{shuttersDev} }{Shading} ) - and defined( $self->{ $self->{shuttersDev} }{Shading}{TIME} ) ); + and defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) + and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) ); } ### Ende Beschattung @@ -2910,7 +3614,8 @@ use GPUtils qw(GP_Import); BEGIN { GP_Import( qw( - AttrVal) + AttrVal + gettimeofday) ); } @@ -2924,7 +3629,9 @@ sub getASC { sub getAntiFreezePos { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze_Pos', 50 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze_Pos', + $userAttrList{ASC_Antifreeze_Pos} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getShuttersPlace { @@ -2960,80 +3667,120 @@ sub getWiggleValue { ### Begin Beschattung sub getShadingPos { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 10 if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Pos', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Pos', + $userAttrList{'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getShadingMode { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'off' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Mode', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Mode', 'off' ); } sub _getBrightnessSensor { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'none' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Brightness_Sensor', $default ); + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $device, $reading, $max, $min ) = + FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, + 'ASC_BrightnessSensor', 'none' ); + + ### erwartetes Ergebnis + # DEVICE:READING MAX:MIN + + return $device if ( $device eq 'none' ); + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device} = $device; + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} = + ( $reading ne 'none' ? $reading : 'brightness' ); + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} = + ( $min ne 'none' ? $min : '-1' ); + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermax} = + ( $max ne 'none' ? $max : '-1' ); + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device}; } sub getBrightnessReading { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'brightness' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Brightness_Reading', $default ); + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $shutters->_getBrightnessSensor; + + return ( + defined( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} + ) + ? $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} + : 'brightness' + ); } sub getDirection { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Direction', -1 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Direction', 180 ); } sub getShadingAngleLeft { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Left', -1 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Left', 75 ); } sub getShadingAngleRight { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Right', -1 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Right', 75 ); } sub getShadingMinOutsideTemperature { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_OutsideTemperature', - 2 ); + 18 ); } sub getShadingMinElevation { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_Elevation', 15.0 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_Elevation', 25.0 ); } sub getShadingStateChangeSunny { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_StateChange_Sunny', - 5000 ); + 35000 ); } sub getShadingStateChangeCloudy { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_StateChange_Cloudy', - 2000 ); + 20000 ); } sub getShadingWaitingPeriod { @@ -3046,16 +3793,16 @@ sub getShadingWaitingPeriod { sub getOffset { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Drive_Offset', 0 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Drive_Offset', -1 ); } sub getOffsetStart { my $self = shift; return ( - AttrVal( $self->{shuttersDev}, 'ASC_Drive_OffsetStart', 3 ) > 2 - ? AttrVal( $self->{shuttersDev}, 'ASC_Drive_OffsetStart', 3 ) - : 3 + AttrVal( $self->{shuttersDev}, 'ASC_Drive_OffsetStart', -1 ) > 0 + ? AttrVal( $self->{shuttersDev}, 'ASC_Drive_OffsetStart', -1 ) + : -1 ); } @@ -3089,31 +3836,39 @@ sub getPosCmd { sub getOpenPos { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Open_Pos', 0 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Open_Pos', + $userAttrList{'ASC_Open_Pos:0,10,20,30,40,50,60,70,80,90,100'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getVentilatePos { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Pos', 80 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Pos', + $userAttrList{'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getClosedPos { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Closed_Pos', 100 ); + return AttrVal( $self->{shuttersDev}, 'ASC_Closed_Pos', + $userAttrList{'ASC_Closed_Pos:0,10,20,30,40,50,60,70,80,90,100'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getVentilateOpen { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', 'off' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', 'on' ); } sub getComfortOpenPos { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_ComfortOpen_Pos', 50 ); + return AttrVal( $self->{shuttersDev}, 'ASC_ComfortOpen_Pos', + $userAttrList{'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getPartyMode { @@ -3123,31 +3878,94 @@ sub getPartyMode { } sub getRoommates { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'none' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Device', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Device', 'none' ); } sub getRoommatesReading { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'state' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Reading', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Reading', 'state' ); +} + +sub getWindPos { + my $self = shift; + my $name = $self->{name}; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $shutters->getWindMax; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos}; +} + +sub getWindMax { + my $self = shift; + my $name = $self->{name}; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $max, $hyst, $pos ) = + FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, + 'ASC_WindParameters', '50:20' ); + + ## Erwartetes Ergebnis + # max:hyst pos + + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax} = $max; + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst} = + $hyst; + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos} = + ( $pos ne 'none' ? $pos : $shutters->getOpenPos ); + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax}; +} + +sub getWindMin { + my $self = shift; + my $name = $self->{name}; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $shutters->getWindMax; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst}; } sub getModeUp { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Up', 'off' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Up', 'always' ); } sub getModeDown { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Down', 'off' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Down', 'always' ); } sub getLockOut { @@ -3169,35 +3987,29 @@ sub getAntiFreeze { } sub getAutoAstroModeMorning { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'none' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', - $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', 'none' ); } sub getAutoAstroModeEvening { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'none' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', - $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', 'none' ); } sub getAutoAstroModeMorningHorizon { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorningHorizon', - 0 ); + 'none' ); } sub getAutoAstroModeEveningHorizon { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon', - 0 ); + 'none' ); } sub getUp { @@ -3215,44 +4027,75 @@ sub getDown { sub getTimeUpEarly { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Early', '04:30:00' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Early', '05:00' ); } sub getTimeUpLate { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Late', '09:00:00' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Late', '08:30' ); } sub getTimeDownEarly { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Early', '15:30:00' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Early', '16:00' ); } sub getTimeDownLate { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Late', '22:00:00' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Late', '22:00' ); } sub getTimeUpWeHoliday { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', - '04:00:00' ); + return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', '08:00' ); } sub getBrightnessMinVal { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_BrightnessMinVal', -1 ); + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $shutters->_getBrightnessSensor; + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{triggermin}; } sub getBrightnessMaxVal { my $self = shift; - return AttrVal( $self->{shuttersDev}, 'ASC_BrightnessMaxVal', -1 ); + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermax} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + and ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $shutters->_getBrightnessSensor; + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{triggermax}; +} + +sub getDriveUpMaxDuration { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_DriveUpMaxDuration', 60 ); } ## Subklasse Readings von ASC_Shutters ## @@ -3275,10 +4118,17 @@ BEGIN { sub getBrightness { my $self = shift; - return ReadingsVal( $shutters->_getBrightnessSensor, + return ReadingsNum( $shutters->_getBrightnessSensor, $shutters->getBrightnessReading, -1 ); } +sub getWindStatus { + my $self = shift; + + return ReadingsVal( $ascDev->_getWindSensor, + $ascDev->getWindSensorReading, -1 ); +} + sub getStatus { my $self = shift; @@ -3286,8 +4136,7 @@ sub getStatus { } sub getDelayCmd { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; return $self->{ $self->{shuttersDev} }{delayCmd}; } @@ -3313,19 +4162,15 @@ BEGIN { } sub getSubTyp { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'twostate' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', 'twostate' ); } sub _getWinDev { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'none' if ( not defined($default) ); - return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec', $default ); + return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec', 'none' ); } ## Subklasse Readings von Klasse ASC_Window ## @@ -3345,11 +4190,9 @@ BEGIN { } sub getWinStatus { - my $self = shift; - my $default = $self->{defaultarg}; + my $self = shift; - $default = 'closed' if ( not defined($default) ); - return ReadingsVal( $shutters->_getWinDev, 'state', $default ); + return ReadingsVal( $shutters->_getWinDev, 'state', 'closed' ); } ## Klasse ASC_Roommate ## @@ -3371,10 +4214,8 @@ BEGIN { sub _getRoommateStatus { my $self = shift; my $roommate = $self->{roommate}; - my $default = $self->{defaultarg}; - $default = 'none' if ( not defined($default) ); - return ReadingsVal( $roommate, $shutters->getRoommatesReading, $default ); + return ReadingsVal( $roommate, $shutters->getRoommatesReading, 'none' ); } sub _getRoommateLastStatus { @@ -3415,6 +4256,11 @@ sub setDefault { return $self->{defaultarg}; } +sub getName { + my $self = shift; + return $self->{name}; +} + ## Subklasse Readings ## package ASC_Dev::Readings; @@ -3476,30 +4322,24 @@ sub setLastPosReading { } sub getPartyMode { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return ReadingsVal( $name, 'partyMode', $default ); + return ReadingsVal( $name, 'partyMode', 'none' ); } sub getHardLockOut { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return ReadingsVal( $name, 'hardLockOut', $default ); + return ReadingsVal( $name, 'hardLockOut', 'none' ); } sub getSunriseTimeWeHoliday { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return ReadingsVal( $name, 'sunriseTimeWeHoliday', $default ); + return ReadingsVal( $name, 'sunriseTimeWeHoliday', 'none' ); } sub getMonitoredDevs { @@ -3573,7 +4413,8 @@ use GPUtils qw(GP_Import); BEGIN { GP_Import( qw( - AttrVal) + AttrVal + gettimeofday) ); } @@ -3581,25 +4422,41 @@ sub getShuttersOffset { my $self = shift; my $name = $self->{name}; - return AttrVal( $name, 'ASC_shuttersDriveOffset', 0 ); + return AttrVal( $name, 'ASC_shuttersDriveOffset', -1 ); } sub getBrightnessMinVal { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 8000 if ( not defined($default) ); - return AttrVal( $name, 'ASC_brightnessMinVal', $default ); + return $self->{ASC_brightness}->{triggermin} + if ( exists( $self->{ASC_brightness}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); + $ascDev->getBrightnessMaxVal; + + return $self->{ASC_brightness}->{triggermin}; } sub getBrightnessMaxVal { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 20000 if ( not defined($default) ); - return AttrVal( $name, 'ASC_brightnessMaxVal', $default ); + return $self->{ASC_brightness}->{triggermax} + if ( exists( $self->{ASC_brightness}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); + $self->{ASC_brightness}->{LASTGETTIME} = int( gettimeofday() ); + + my ( $triggermax, $triggermin ) = + FHEM::AutoShuttersControl::GetAttrValues( $name, + 'ASC_brightnessDriveUpDown', '800:500' ); + + ## erwartetes Ergebnis + # max:min + + $self->{ASC_brightness}->{triggermin} = $triggermin; + $self->{ASC_brightness}->{triggermax} = $triggermax; + + return $self->{ASC_brightness}->{triggermax}; } sub _getTwilightDevice { @@ -3610,12 +4467,10 @@ sub _getTwilightDevice { } sub getAutoAstroModeEvening { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_autoAstroModeEvening', $default ); + return AttrVal( $name, 'ASC_autoAstroModeEvening', 'none' ); } sub getAutoAstroModeEveningHorizon { @@ -3626,12 +4481,10 @@ sub getAutoAstroModeEveningHorizon { } sub getAutoAstroModeMorning { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_autoAstroModeMorning', $default ); + return AttrVal( $name, 'ASC_autoAstroModeMorning', 'none' ); } sub getAutoAstroModeMorningHorizon { @@ -3642,21 +4495,17 @@ sub getAutoAstroModeMorningHorizon { } sub getAutoShuttersControlMorning { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_autoShuttersControlMorning', $default ); + return AttrVal( $name, 'ASC_autoShuttersControlMorning', 'none' ); } sub getAutoShuttersControlEvening { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_autoShuttersControlEvening', $default ); + return AttrVal( $name, 'ASC_autoShuttersControlEvening', 'none' ); } sub getAutoShuttersControlComfort { @@ -3667,89 +4516,205 @@ sub getAutoShuttersControlComfort { } sub getFreezeTemp { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 3 if ( not defined($default) ); - return AttrVal( $name, 'ASC_freezeTemp', $default ); + return AttrVal( $name, 'ASC_freezeTemp', 3 ); } sub _getTempSensor { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_temperatureSensor', $default ); + return $self->{ASC_tempSensor}->{device} + if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_tempSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_tempSensor', + 'none' ); + + ## erwartetes Ergebnis + # DEVICE:READING + + return $device if ( $device eq 'none' ); + $self->{ASC_tempSensor}->{device} = $device; + $self->{ASC_tempSensor}->{reading} = + ( $reading ne 'none' ? $reading : 'temperature' ); + + return $self->{ASC_tempSensor}->{device}; } sub getTempReading { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_temperatureReading', $default ); + return $self->{ASC_tempSensor}->{reading} + if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getTempSensor; + return $self->{ASC_tempSensor}->{reading}; } sub _getResidentsDev { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_residentsDevice', $default ); + return $self->{ASC_residentsDev}->{device} + if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 ); + $self->{ASC_residentsDev}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_residentsDev', + 'none' ); + + $self->{ASC_residentsDev}->{device} = $device; + $self->{ASC_residentsDev}->{reading} = + ( $reading ne 'none' ? $reading : 'state' ); + + return $self->{ASC_residentsDev}->{device}; } sub getResidentsReading { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'state' if ( not defined($default) ); - return AttrVal( $name, 'ASC_residentsDeviceReading', $default ); + return $self->{ASC_residentsDev}->{reading} + if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 ); + $ascDev->_getResidentsDev; + return $self->{ASC_residentsDev}->{reading}; } -sub getRainSensor { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; +sub _getRainSensor { + my $self = shift; + my $name = $self->{name}; - $default = 'none' if ( not defined($default) ); - return AttrVal( $name, 'ASC_rainSensorDevice', $default ); + return $self->{ASC_rainSensor}->{device} + if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_rainSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading, $max, $hyst, $pos ) = + FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_rainSensor', + 'none' ); + + ## erwartetes Ergebnis + # DEVICE:READING MAX:HYST + + return $device if ( $device eq 'none' ); + $self->{ASC_rainSensor}->{device} = $device; + $self->{ASC_rainSensor}->{reading} = + ( $reading ne 'none' ? $reading : 'state' ); + $self->{ASC_rainSensor}->{triggermax} = ( $max ne 'none' ? $max : 1000 ); + $self->{ASC_rainSensor}->{triggerhyst} = + ( $hyst ne 'none' ? $max - $hyst : ( $max * 0 ) ); + $self->{ASC_rainSensor}->{shuttersClosedPos} = + ( $pos ne 'none' ? $pos : 50 ); + + return $self->{ASC_rainSensor}->{device}; } sub getRainSensorReading { - my $self = shift; - my $name = $self->{name}; - my $default = $self->{defaultarg}; + my $self = shift; + my $name = $self->{name}; - $default = 'state' if ( not defined($default) ); - return AttrVal( $name, 'ASC_rainSensorReading', $default ); + return $self->{ASC_rainSensor}->{reading} + if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getRainSensor; + return $self->{ASC_rainSensor}->{reading}; +} + +sub getRainTriggerMax { + my $self = shift; + my $name = $self->{name}; + + return $self->{ASC_rainSensor}->{triggermax} + if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getRainSensor; + return $self->{ASC_rainSensor}->{triggermax}; +} + +sub getRainTriggerMin { + my $self = shift; + my $name = $self->{name}; + + return $self->{ASC_rainSensor}->{triggerhyst} + if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getRainSensor; + return $self->{ASC_rainSensor}->{triggerhyst}; } sub getRainSensorShuttersClosedPos { my $self = shift; my $name = $self->{name}; - return AttrVal( $name, 'ASC_rainSensorShuttersClosedPos', 50 ); + return $self->{ASC_rainSensor}->{shuttersClosedPos} + if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getRainSensor; + return $self->{ASC_rainSensor}->{shuttersClosedPos}; } + +sub _getWindSensor { + my $self = shift; + my $name = $self->{name}; + + return $self->{ASC_windSensor}->{device} + if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_windSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_windSensor', + 'none' ); + + return $device if ( $device eq 'none' ); + $self->{ASC_windSensor}->{device} = $device; + $self->{ASC_windSensor}->{reading} = + ( $reading ne 'none' ? $reading : 'wind' ); + + return $self->{ASC_windSensor}->{device}; +} + +sub getWindSensorReading { + my $self = shift; + my $name = $self->{name}; + + return $self->{ASC_windSensor}->{reading} + if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} ) + and ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); + $ascDev->_getWindSensor; + return ( + defined( $self->{ASC_windSensor}->{reading} ) + ? $self->{ASC_windSensor}->{reading} + : 'wind' + ); +} + +sub getblockAscDrivesAfterManual { + my $self = shift; + my $name = $self->{name}; + + return AttrVal( $name, 'ASC_blockAscDrivesAfterManual', 0 ); +} + 1; =pod =item device -=item summary Modul +=item summary Module for controlling shutters depending on various conditions =item summary_DE Modul zur Automatischen Rolladensteuerung auf Basis bestimmter Ereignisse =begin html -

Automatic shutter control - ASC

+

Automatische Rollladensteuerung - ASC


- This command creates a AutoShuttersControl device named myASControl.
- After creating the device, all shutter devices which shall be controlled have to get set the attribut AutoShuttersControl with value 1 or 2.
- Value 1 means "Inverse or shutter e.g.: shutter up 0,shutter down 100 and the command for percentual movement is position",2 = "Homematic Style e.g.: shutter up 100,shutter down 0 and the command for percentual movement istpct.
- If the attribute is set, you may start automatic scan for your devices . + Der Befehl erstellt ein AutoShuttersControl Device mit Namen myASControl.
+ Nachdem das Device angelegt wurde, muss in allen Rollläden Devices, welche gesteuert werden sollen, das Attribut ASC mit Wert 1 oder 2 gesetzt werden.
+ Dabei bedeutet 1 = "Inverse oder Rollo - Bsp.: Rollo Oben 0,Rollo Unten 100 und der Befehl zum prozentualen Fahren ist position",2 = "Homematic Style - Bsp.: Rollo Oben 100,Rollo Unten 0 und der Befehl zum prozentualen Fahren ist pct.
+ Habt Ihr das Attribut gesetzt, könnt Ihr den automatischen Scan nach den Devices anstossen.

@@ -3772,108 +4737,165 @@ sub getRainSensorShuttersClosedPos {

Set

Get

Attributes @@ -3954,86 +4976,170 @@ sub getRainSensorShuttersClosedPos { =end html_DE +=for :application/json;q=META.json 73_AutoShuttersControl.pm +{ + "abstract": "Module for controlling shutters depending on various conditions", + "x_lang": { + "de": { + "abstract": "Modul zur Automatischen Rolladensteuerung auf Basis bestimmter Ereignisse" + } + }, + "keywords": [ + "fhem-mod-device", + "fhem-core", + "Shutter", + "Automation", + "Rollladen", + "Rollo", + "Control" + ], + "release_status": "under develop", + "license": "GPL_2", + "author": [ + "Marko Oldenburg " + ], + "x_fhem_maintainer": [ + "CoolTux" + ], + "x_fhem_maintainer_github": [ + "LeonGaultier" + ], + "prereqs": { + "runtime": { + "requires": { + "FHEM": 5.00918799, + "perl": 5.016, + "Meta": 0, + "JSON": 0 + }, + "recommends": { + }, + "suggests": { + } + } + } +} +=end :application/json;q=META.json + =cut