############################################################################### # # Developed with Kate # # (c) 2018-2020 Copyright: Marko Oldenburg (leongaultier at gmail dot com) # All rights reserved # # Special thanks goes to: # - Bernd (Cluni) this module is based on the logic of his script "Rollladensteuerung für HM/ROLLO inkl. Abschattung und Komfortfunktionen in Perl" (https://forum.fhem.de/index.php/topic,73964.0.html) # - Beta-User for many tests, many suggestions and good discussions # - pc1246 write english commandref # - FunkOdyssey commandref style # - sledge fix many typo in commandref # - many User that use with modul and report bugs # - Christoph (christoph.kaiser.in) Patch that expand RegEx for Window Events # - Julian (Loredo) expand Residents Events for new Residents functions # - Christoph (Christoph Morrison) for fix Commandref, many suggestions and good discussions # # # This script is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License,or # any later version. # # The GNU General Public License can be found at # http://www.gnu.org/copyleft/gpl.html. # A copy is found in the textfile GPL.txt and important notices to the license # from the author is found in LICENSE.txt distributed with these scripts. # # This script is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # $Id$ # ############################################################################### ### Notizen # !!!!! - Innerhalb einer Shutterschleife kein CommandAttr verwenden. Bring Fehler!!! Kommen Raumnamen in die Shutterliste !!!!!! # package main; use strict; use warnings; sub ascAPIget($@) { my ( $getCommand, $shutterDev, $value ) = @_; return AutoShuttersControl_ascAPIget( $getCommand, $shutterDev, $value ); } ## unserer packagename package FHEM::AutoShuttersControl; use strict; use warnings; use POSIX; use utf8; use Encode; use FHEM::Meta; use GPUtils qw(GP_Import GP_Export); use Data::Dumper; #only for Debugging use Date::Parse; # try to use JSON::MaybeXS wrapper # for chance of better performance + open code eval { require JSON::MaybeXS; import JSON::MaybeXS qw( decode_json encode_json ); 1; }; if ($@) { $@ = undef; # try to use JSON wrapper # for chance of better performance eval { # JSON preference order local $ENV{PERL_JSON_BACKEND} = 'Cpanel::JSON::XS,JSON::XS,JSON::PP,JSON::backportPP' unless ( defined( $ENV{PERL_JSON_BACKEND} ) ); require JSON; import JSON qw( decode_json encode_json ); 1; }; if ($@) { $@ = undef; # In rare cases, Cpanel::JSON::XS may # be installed but JSON|JSON::MaybeXS not ... eval { require Cpanel::JSON::XS; import Cpanel::JSON::XS qw(decode_json encode_json); 1; }; if ($@) { $@ = undef; # In rare cases, JSON::XS may # be installed but JSON not ... eval { require JSON::XS; import JSON::XS qw(decode_json encode_json); 1; }; if ($@) { $@ = undef; # Fallback to built-in JSON which SHOULD # be available since 5.014 ... eval { require JSON::PP; import JSON::PP qw(decode_json encode_json); 1; }; if ($@) { $@ = undef; # Fallback to JSON::backportPP in really rare cases require JSON::backportPP; import JSON::backportPP qw(decode_json encode_json); 1; } } } } } ## Import der FHEM Funktionen #-- Run before package compilation BEGIN { # Import from main context GP_Import( qw( devspec2array readingsSingleUpdate readingsBulkUpdate readingsBulkUpdateIfChanged readingsBeginUpdate readingsEndUpdate defs modules Log3 CommandAttr attr CommandDeleteAttr CommandDeleteReading CommandSet readingFnAttributes AttrVal ReadingsVal IsDisabled deviceEvents init_done addToDevAttrList addToAttrList delFromDevAttrList delFromAttrList gettimeofday sunset sunset_abs sunrise sunrise_abs InternalTimer RemoveInternalTimer computeAlignTime ReplaceEventMap) ); } #-- Export to main context with different name GP_Export( qw( Initialize ascAPIget DevStateIcon ) ); ## Die Attributsliste welche an die Rolläden verteilt wird. Zusammen mit Default Werten my %userAttrList = ( 'ASC_Mode_Up:absent,always,off,home' => '-', 'ASC_Mode_Down:absent,always,off,home' => '-', 'ASC_Up:time,astro,brightness,roommate' => '-', 'ASC_Down:time,astro,brightness,roommate' => '-', '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' => '-', 'ASC_AutoAstroModeEveningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9' => '-', '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_Sleep_Pos:0,10,20,30,40,50,60,70,80,90,100' => '-', 'ASC_Pos_Reading' => [ '', 'position', 'pct' ], 'ASC_Time_Up_Early' => '-', 'ASC_Time_Up_Late' => '-', 'ASC_Time_Up_WE_Holiday' => '-', 'ASC_Time_Down_Early' => '-', 'ASC_Time_Down_Late' => '-', 'ASC_PrivacyUpValue_beforeDayOpen' => '-', 'ASC_PrivacyDownValue_beforeNightClose' => '-', 'ASC_PrivacyUp_Pos' => '-', 'ASC_PrivacyDown_Pos' => '-', 'ASC_TempSensor' => '-', '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_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 80, 20 ], 'ASC_Shading_Mode:absent,always,off,home' => '-', 'ASC_Shading_InOutAzimuth' => '-', 'ASC_Shading_StateChange_SunnyCloudy' => '-', 'ASC_Shading_MinMax_Elevation' => '-', 'ASC_Shading_Min_OutsideTemperature' => '-', 'ASC_Shading_WaitingPeriod' => '-', 'ASC_Drive_Delay' => '-', 'ASC_Drive_DelayStart' => '-', 'ASC_Shutter_IdleDetection' => '-', 'ASC_WindowRec' => '-', 'ASC_WindowRec_subType:twostate,threestate' => '-', 'ASC_WindowRec_PosAfterDayClosed:open,lastManual' => '-', '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' => '-', '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' => '-', 'ASC_Roommate_Device' => '-', 'ASC_Roommate_Reading' => '-', 'ASC_Self_Defense_Mode:absent,gone,off' => '-', 'ASC_Self_Defense_AbsentDelay' => '-', 'ASC_WiggleValue' => '-', 'ASC_WindParameters' => '-', 'ASC_DriveUpMaxDuration' => '-', 'ASC_WindProtection:on,off' => '-', 'ASC_RainProtection:on,off' => '-', 'ASC_ExternalTrigger' => '-', 'ASC_Adv:on,off' => '-' ); my %posSetCmds = ( ZWave => 'dim', Siro => 'pct', CUL_HM => 'pct', ROLLO => 'pct', SOMFY => 'position', tahoma => 'dim', KLF200Node => 'pct', DUOFERN => 'position', HM485 => 'level', SELVECommeo => 'position', SELVE => 'position', EnOcean => 'position', ); my $shutters = new ASC_Shutters(); my $ascDev = new ASC_Dev(); sub ascAPIget($@) { my ( $getCommand, $shutterDev, $value ) = @_; my $getter = 'get' . $getCommand; if ( defined($value) and $value ) { $shutters->setShuttersDev($shutterDev); return $shutters->$getter($value); } elsif ( defined($shutterDev) and $shutterDev ) { $shutters->setShuttersDev($shutterDev); return $shutters->$getter; } else { return $ascDev->$getter; } } sub 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} = '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_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 ' . 'ASC_autoAstroModeEveningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9 ' . 'ASC_freezeTemp:-5,-4,-3,-2,-1,0,1,2,3,4,5 ' . 'ASC_shuttersDriveDelay ' . 'ASC_twilightDevice ' . 'ASC_windSensor ' . 'ASC_expert:1 ' . 'ASC_blockAscDrivesAfterManual:0,1 ' . 'ASC_debug:1 ' . $readingFnAttributes; $hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn $hash->{FW_detailFn} = 'FHEM::AutoShuttersControl::ShuttersInformation'; return FHEM::Meta::InitMod( __FILE__, $hash ); } sub Define($$) { my ( $hash, $def ) = @_; my @a = split( '[ \t][ \t]*', $def ); return $@ unless ( FHEM::Meta::SetInternals($hash) ); use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' ); 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 return 'too few parameters: define ShuttersControl' if ( @a != 2 ); my $name = $a[0]; $hash->{MID} = 'da39a3ee5e6b4b0d3255bfef95601890afd80709' ; # eine Ein Eindeutige ID für interne FHEM Belange / nicht weiter wichtig $hash->{VERSION} = version->parse($VERSION)->normal; $hash->{NOTIFYDEV} = 'global,' . $name; # Liste aller Devices auf deren Events gehört werden sollen #$hash->{shutters} = $shutters; #$hash->{ascDev} = $ascDev; $ascDev->setName($name); readingsSingleUpdate( $hash, 'state', 'please set attribute ASC with value 1 or 2 in all auto controlled shutter devices and then execute \'set DEVICENAME scanForShutters\'', 1 ); CommandAttr( undef, $name . ' room ASC' ) if ( AttrVal( $name, 'room', 'none' ) eq 'none' ); CommandAttr( undef, $name . ' icon fts_shutter_automatic' ) if ( AttrVal( $name, 'icon', 'none' ) eq 'none' ); CommandAttr( undef, $name . ' devStateIcon { AutoShuttersControl_DevStateIcon($name) }' ) if ( AttrVal( $name, 'devStateIcon', 'none' ) eq 'none' ); addToAttrList('ASC:0,1,2'); Log3( $name, 3, "AutoShuttersControl ($name) - defined" ); $modules{AutoShuttersControl}{defptr}{ $hash->{MID} } = $hash; return undef; } sub Undef($$) { my ( $hash, $arg ) = @_; my $name = $hash->{NAME}; UserAttributs_Readings_ForShutters( $hash, 'del' ) ; # es sollen alle Attribute und Readings in den Rolläden Devices gelöscht werden welche vom Modul angelegt wurden delFromAttrList('ASC:0,1,2'); delete( $modules{AutoShuttersControl}{defptr}{ $hash->{MID} } ); Log3( $name, 3, "AutoShuttersControl ($name) - delete device $name" ); return undef; } sub Attr(@) { my ( $cmd, $name, $attrName, $attrVal ) = @_; # my $hash = $defs{$name}; return undef; } sub Notify($$) { my ( $hash, $dev ) = @_; my $name = $hash->{NAME}; my $devname = $dev->{NAME}; my $devtype = $dev->{TYPE}; my $events = deviceEvents( $dev, 1 ); return if ( !$events ); Log3( $name, 4, "AutoShuttersControl ($name) - Devname: " . $devname . " Name: " . $name . " Notify: " . Dumper $events); # mit Dumper if ( ( grep /^DEFINED.$name$/, @{$events} and $devname eq 'global' and $init_done ) or ( grep /^INITIALIZED$/, @{$events} or grep /^REREADCFG$/, @{$events} or grep /^MODIFIED.$name$/, @{$events} ) and $devname eq 'global' ) { readingsSingleUpdate( $hash, 'partyMode', 'off', 0 ) if ( $ascDev->getPartyMode eq 'none' ); readingsSingleUpdate( $hash, 'hardLockOut', 'off', 0 ) if ( $ascDev->getHardLockOut eq 'none' ); readingsSingleUpdate( $hash, 'sunriseTimeWeHoliday', 'off', 0 ) if ( $ascDev->getSunriseTimeWeHoliday eq 'none' ); readingsSingleUpdate( $hash, 'selfDefense', 'off', 0 ) if ( $ascDev->getSelfDefense eq 'none' ); readingsSingleUpdate( $hash, 'controlShading', 'off', 0 ) if ( $ascDev->getAutoShuttersControlShading eq 'none' ); readingsSingleUpdate( $hash, 'ascEnable', 'on', 0 ) if ( $ascDev->getASCenable eq 'none' ); CommandAttr( undef, $name . ' devStateIcon { AutoShuttersControl_DevStateIcon($name) }' ) unless ( AttrVal( $name, 'devStateIcon', '{ AutoShuttersControl_DevStateIcon($name) }' ) eq '{ AutoShuttersControl_DevStateIcon($name) }' ); CommandDeleteAttr( undef, $name . ' event-on-change-reading' ) unless ( AttrVal( $name, 'event-on-change-reading', 'none' ) eq 'none' ); CommandDeleteAttr( undef, $name . ' event-on-update-reading' ) unless ( AttrVal( $name, 'event-on-update-reading', 'none' ) eq 'none' ); # 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' ); } return unless ( ref( $hash->{helper}{shuttersList} ) eq 'ARRAY' and scalar( @{ $hash->{helper}{shuttersList} } ) > 0 ); my $posReading = $shutters->getPosCmd; if ( $devname eq $name ) { if ( grep /^userAttrList:.rolled.out$/, @{$events} ) { unless ( scalar( @{ $hash->{helper}{shuttersList} } ) == 0 ) { WriteReadingsShuttersList($hash); UserAttributs_Readings_ForShutters( $hash, 'add' ); InternalTimer( gettimeofday() + 3, 'FHEM::AutoShuttersControl::RenewSunRiseSetShuttersTimer', $hash ); InternalTimer( gettimeofday() + 5, 'FHEM::AutoShuttersControl::AutoSearchTwilightDev', $hash ); } } elsif ( grep /^partyMode:.off$/, @{$events} ) { EventProcessingPartyMode($hash); } elsif ( grep /^sunriseTimeWeHoliday:.(on|off)$/, @{$events} ) { RenewSunRiseSetShuttersTimer($hash); } } elsif ( $devname eq "global" ) { # Kommt ein globales Event und beinhaltet folgende Syntax wird die Funktion zur Verarbeitung aufgerufen if ( 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_PrivacyDownValue_beforeNightClose|.*ASC_PrivacyUpValue_beforeDayOpen|.*ASC_autoAstroModeEvening|.*ASC_autoAstroModeEveningHorizon|.*ASC_Roommate_Device|.*ASC_WindowRec|.*ASC_residentsDev|.*ASC_rainSensor|.*ASC_windSensor|.*ASC_BrightnessSensor|.*ASC_twilightDevice|.*ASC_ExternalTrigger)(\s.*|$)/, @{$events} ) { EventProcessingGeneral( $hash, undef, join( ' ', @{$events} ) ); } } elsif ( grep /^($posReading):\s\d+$/, @{$events} ) { ASC_Debug( 'Notify: ' . ' ASC_Pos_Reading Event vom Rollo wurde erkannt ' . ' - RECEIVED EVENT: ' . Dumper $events); EventProcessingShutters( $hash, $devname, join( ' ', @{$events} ) ); } else { EventProcessingGeneral( $hash, $devname, join( ' ', @{$events} ) ) ; # bei allen anderen Events wird die entsprechende Funktion zur Verarbeitung aufgerufen } return; } sub EventProcessingGeneral($$$) { my ( $hash, $devname, $events ) = @_; my $name = $hash->{NAME}; if ( defined($devname) and ($devname) ) { # es wird lediglich der Devicename der Funktion mitgegeben wenn es sich nicht um global handelt daher hier die Unterschiedung while ( my ( $device, $deviceAttr ) = each %{ $hash->{monitoredDevs}{$devname} } ) { EventProcessingWindowRec( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_WindowRec' ) ; # ist es ein Fensterdevice wird die Funktion gestartet EventProcessingRoommate( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_Roommate_Device' ) ; # ist es ein Bewohner Device wird diese Funktion gestartet EventProcessingResidents( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_residentsDev' ); EventProcessingRain( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_rainSensor' ); EventProcessingWind( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_windSensor' ); EventProcessingTwilightDevice( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_twilightDevice' ); EventProcessingExternalTriggerDevice( $hash, $device, $events ) if ( $deviceAttr eq 'ASC_ExternalTrigger' ); $shutters->setShuttersDev($device) if ( $deviceAttr eq 'ASC_BrightnessSensor' ); if ( $deviceAttr eq 'ASC_BrightnessSensor' and ( $shutters->getDown eq 'brightness' or $shutters->getUp eq 'brightness' ) ) { EventProcessingBrightness( $hash, $device, $events ); } 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_residentsDev|ASC_rainSensor|ASC_windSensor|ASC_BrightnessSensor|ASC_ExternalTrigger|ASC_twilightDevice)\s(.*)$# ) { # wurde den Attributen unserer Rolläden ein Wert zugewiesen ? AddNotifyDev( $hash, $3, $1, $2 ) if ( $3 ne 'none' ); Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessing: ATTR" ); } elsif ( $events =~ m#^DELETEATTR\s(.*)\s(ASC_Roommate_Device|ASC_WindowRec|ASC_residentsDev|ASC_rainSensor|ASC_windSensor|ASC_BrightnessSensor|ASC_ExternalTrigger|ASC_twilightDevice)$# ) { # wurde das Attribut unserer Rolläden gelöscht ? Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessing: DELETEATTR" ); DeleteNotifyDev( $hash, $1, $2 ); } elsif ( $events =~ m#^(DELETEATTR|ATTR)\s(.*)\s(ASC_Time_Up_WE_Holiday|ASC_Up|ASC_Down|ASC_AutoAstroModeMorning|ASC_AutoAstroModeMorningHorizon|ASC_PrivacyDownValue_beforeNightClose|ASC_PrivacyUpValue_beforeDayOpen|ASC_AutoAstroModeEvening|ASC_AutoAstroModeEveningHorizon|ASC_Time_Up_Early|ASC_Time_Up_Late|ASC_Time_Down_Early|ASC_Time_Down_Late)(.*)?# ) { CreateSunRiseSetShuttersTimer( $hash, $2 ) if ( $3 ne 'ASC_Time_Up_WE_Holiday' or ( $3 eq 'ASC_Time_Up_WE_Holiday' and $ascDev->getSunriseTimeWeHoliday eq 'on' ) ); } elsif ( $events =~ m#^(DELETEATTR|ATTR)\s(.*)\s(ASC_autoAstroModeMorning|ASC_autoAstroModeMorningHorizon|ASC_autoAstroModeEvening|ASC_autoAstroModeEveningHorizon)(.*)?# ) { RenewSunRiseSetShuttersTimer($hash); } } } sub Set($$@) { my ( $hash, $name, @aa ) = @_; my ( $cmd, @args ) = @aa; if ( lc $cmd eq 'renewalltimer' ) { return "usage: $cmd" if ( @args != 0 ); RenewSunRiseSetShuttersTimer($hash); } elsif ( lc $cmd eq 'renewtimer' ) { return "usage: $cmd" if ( @args > 1 ); CreateSunRiseSetShuttersTimer( $hash, $args[0] ); } elsif ( lc $cmd eq 'scanforshutters' ) { return "usage: $cmd" if ( @args != 0 ); ShuttersDeviceScan($hash); } elsif ( lc $cmd eq 'createnewnotifydev' ) { return "usage: $cmd" if ( @args != 0 ); CreateNewNotifyDev($hash); } 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 ) ); } elsif ( lc $cmd eq 'hardlockout' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ); HardewareBlockForShutters( $hash, join( ' ', @args ) ); } elsif ( lc $cmd eq 'sunrisetimeweholiday' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ); } elsif ( lc $cmd eq 'controlshading' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ); } elsif ( lc $cmd eq 'selfdefense' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ); } elsif ( lc $cmd eq 'ascenable' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $hash, $cmd, join( ' ', @args ), 1 ); } elsif ( lc $cmd eq 'advdrivedown' ) { return "usage: $cmd" if ( @args != 0 ); EventProcessingAdvShuttersClose($hash); } elsif ( lc $cmd eq 'shutterascenabletoggle' ) { return "usage: $cmd" if ( @args > 1 ); readingsSingleUpdate( $defs{ $args[0] }, 'ASC_Enable', ( ReadingsVal( $args[0], 'ASC_Enable', 'off' ) eq 'on' ? 'off' : 'on' ), 1 ); } elsif ( lc $cmd eq 'wiggle' ) { return "usage: $cmd" if ( @args > 1 ); ( $args[0] eq 'all' ? wiggleAll($hash) : wiggle( $hash, $args[0] ) ); } else { my $list = 'scanForShutters:noArg'; $list .= ' renewAllTimer:noArg advDriveDown:noArg partyMode:on,off hardLockOut:on,off sunriseTimeWeHoliday:on,off controlShading:on,off selfDefense:on,off ascEnable:on,off wiggle:all,' . join( ',', @{ $hash->{helper}{shuttersList} } ) . ' shutterASCenableToggle:' . join( ',', @{ $hash->{helper}{shuttersList} } ) . ' renewTimer:' . join( ',', @{ $hash->{helper}{shuttersList} } ) if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' ); $list .= ' createNewNotifyDev:noArg' if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' and AttrVal( $name, 'ASC_expert', 0 ) == 1 ); return "Unknown argument $cmd,choose one of $list"; } return undef; } sub Get($$@) { my ( $hash, $name, @aa ) = @_; my ( $cmd, @args ) = @aa; if ( lc $cmd eq 'shownotifydevsinformations' ) { return "usage: $cmd" if ( @args != 0 ); my $ret = GetMonitoredDevs($hash); return $ret; } else { my $list = ""; $list .= " showNotifyDevsInformations:noArg" if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' and AttrVal( $name, 'ASC_expert', 0 ) == 1 ); return "Unknown argument $cmd,choose one of $list"; } } sub ShuttersDeviceScan($) { my $hash = shift; my $name = $hash->{NAME}; delete $hash->{helper}{shuttersList}; my @list; @list = devspec2array('ASC=[1-2]'); CommandDeleteReading( undef, $name . ' .*_nextAstroTimeEvent' ); unless ( scalar(@list) > 0 ) { readingsBeginUpdate($hash); readingsBulkUpdate( $hash, 'userAttrList', 'none' ); readingsBulkUpdate( $hash, 'state', 'no shutters found' ); readingsEndUpdate( $hash, 1 ); return; } my $shuttersList = ''; foreach (@list) { push( @{ $hash->{helper}{shuttersList} }, $_ ) ; ## einem Hash wird ein Array zugewiesen welches die Liste der erkannten Rollos beinhaltet $shutters->setShuttersDev($_); #### Ab hier können temporäre Änderungen der Attribute gesetzt werden #### Gleichlautende Attribute wo lediglich die Parameter geändert werden sollen müssen hier gelöscht und die Parameter in der Funktion renewSetSunriseSunsetTimer gesetzt werden, #### vorher empfiehlt es sich die dort vergebenen Parameter aus zu lesen um sie dann hier wieder neu zu setzen. Dazu wird das shutters Objekt um einen Eintrag #### 'AttrUpdateChanges' erweitert if ( ReadingsVal( $_, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, 0 ) == 0 ) { $shutters->setAttrUpdateChanges( 'ASC_Up', AttrVal( $_, 'ASC_Up', 'none' ) ); delFromDevAttrList( $_, 'ASC_Up' ); $shutters->setAttrUpdateChanges( 'ASC_Down', AttrVal( $_, 'ASC_Down', 'none' ) ); delFromDevAttrList( $_, 'ASC_Down' ); $shutters->setAttrUpdateChanges( 'ASC_Self_Defense_Mode', AttrVal( $_, 'ASC_Self_Defense_Mode', 'none' ) ); delFromDevAttrList( $_, 'ASC_Self_Defense_Mode' ); $shutters->setAttrUpdateChanges( 'ASC_Self_Defense_Exclude', AttrVal( $_, 'ASC_Self_Defense_Exclude', 'none' ) ); delFromDevAttrList( $_, 'ASC_Self_Defense_Exclude' ); } #### #### $shuttersList = $shuttersList . ',' . $_; $shutters->setLastManPos( $shutters->getStatus ); $shutters->setLastPos( $shutters->getStatus ); $shutters->setDelayCmd('none'); $shutters->setNoDelay(0); $shutters->setSelfDefenseAbsent( 0, 0 ); $shutters->setPosSetCmd( $posSetCmds{ $defs{$_}->{TYPE} } ); $shutters->setShadingStatus( ( $shutters->getStatus != $shutters->getShadingPos ? 'out' : 'in' ) ); $shutters->setShadingLastStatus( ( $shutters->getStatus != $shutters->getShadingPos ? 'in' : 'out' ) ); $shutters->setPushBrightnessInArray( $shutters->getBrightness ); readingsSingleUpdate( $defs{$_}, 'ASC_Enable', 'on', 0 ) if ( ReadingsVal( $_, 'ASC_Enable', 'none' ) eq 'none' ); if ( $shutters->getIsDay ) { $shutters->setSunrise(1); $shutters->setSunset(0); } else { $shutters->setSunrise(0); $shutters->setSunset(1); } } $hash->{NOTIFYDEV} = "global," . $name . $shuttersList; if ( $ascDev->getMonitoredDevs ne 'none' ) { $hash->{monitoredDevs} = eval { decode_json( $ascDev->getMonitoredDevs ) }; my $notifyDevString = $hash->{NOTIFYDEV}; while ( each %{ $hash->{monitoredDevs} } ) { $notifyDevString .= ',' . $_; } $hash->{NOTIFYDEV} = $notifyDevString; } readingsSingleUpdate( $hash, 'userAttrList', 'rolled out', 1 ); } ## Die Funktion schreibt in das Moduldevice Readings welche Rolläden in welchen Räumen erfasst wurden. sub WriteReadingsShuttersList($) { my $hash = shift; my $name = $hash->{NAME}; CommandDeleteReading( undef, $name . ' room_.*' ); readingsBeginUpdate($hash); foreach ( @{ $hash->{helper}{shuttersList} } ) { readingsBulkUpdate( $hash, 'room_' . makeReadingName( AttrVal( $_, 'room', 'unsorted' ) ), ReadingsVal( $name, 'room_' . makeReadingName( AttrVal( $_, 'room', 'unsorted' ) ), '' ) . ',' . $_ ) if ( ReadingsVal( $name, 'room_' . makeReadingName( AttrVal( $_, 'room', 'unsorted' ) ), 'none' ) ne 'none' ); readingsBulkUpdate( $hash, 'room_' . makeReadingName( AttrVal( $_, 'room', 'unsorted' ) ), $_ ) if ( ReadingsVal( $name, 'room_' . makeReadingName( AttrVal( $_, 'room', 'unsorted' ) ), 'none' ) eq 'none' ); } readingsBulkUpdate( $hash, 'state', 'active' ); readingsEndUpdate( $hash, 0 ); } sub UserAttributs_Readings_ForShutters($$) { my ( $hash, $cmd ) = @_; my $name = $hash->{NAME}; while ( my ( $attrib, $attribValue ) = each %{userAttrList} ) { foreach ( @{ $hash->{helper}{shuttersList} } ) { 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] } ) and $attribValue ne '-' ); } else { $attr{$_}{ ( split( ':', $attrib ) )[0] } = $attribValue->[ AttrVal( $_, 'ASC', 2 ) ] if ( not defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) and $attrib eq 'ASC_Pos_Reading' ); } ### associatedWith damit man sieht das der Rollladen mit einem ASC Device verbunden ist my $associatedString = ReadingsVal( $_, 'associatedWith', 'none' ); if ( $associatedString ne 'none' ) { my %hash; %hash = map { ( $_ => 1 ) } split( ',', "$associatedString,$name" ); readingsSingleUpdate( $defs{$_}, 'associatedWith', join( ',', sort keys %hash ), 0 ); } else { readingsSingleUpdate( $defs{$_}, 'associatedWith', $name, 0 ); } ####################################### } ## Oder das Attribut wird wieder gelöscht. elsif ( $cmd eq 'del' ) { $shutters->setShuttersDev($_); RemoveInternalTimer( $shutters->getInTimerFuncHash ); CommandDeleteReading( undef, $_ . ' .?(ASC)_.*' ); CommandDeleteAttr( undef, $_ . ' ASC' ); delFromDevAttrList( $_, $attrib ); ### associatedWith wird wieder entfernt my $associatedString = ReadingsVal( $_, 'associatedWith', 'none' ); my %hash; %hash = map { ( $_ => 1 ) } grep { " $name " !~ m/ $_ / } split( ',', "$associatedString,$name" ); if ( keys %hash > 1 ) { readingsSingleUpdate( $defs{$_}, 'associatedWith', join( ',', sort keys %hash ), 0 ); } else { CommandDeleteReading( undef, $_ . ' associatedWith' ); } ################################### } } } } ## 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; %hash = map { ( $_ => 1 ) } split( ',', "$notifyDev,$dev" ); $hash->{NOTIFYDEV} = join( ',', sort keys %hash ); my @devs = split( ',', $dev ); foreach (@devs) { $hash->{monitoredDevs}{$_}{$shuttersDev} = $shuttersAttr; } readingsSingleUpdate( $hash, '.monitoredDevs', eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); } ## entfernt aus dem NOTIFYDEV Hash Devices welche als Wert in Attributen steckten sub DeleteNotifyDev($@) { my ( $hash, $shuttersDev, $shuttersAttr ) = @_; my $name = $hash->{NAME}; my $notifyDevs = ExtractNotifyDevFromEvent( $hash, $shuttersDev, $shuttersAttr ); foreach my $notifyDev ( keys( %{$notifyDevs} ) ) { Log3( $name, 4, "AutoShuttersControl ($name) - DeleteNotifyDev - NotifyDev: " . $_ ); delete $hash->{monitoredDevs}{$notifyDev}{$shuttersDev}; if ( !keys %{ $hash->{monitoredDevs}{$notifyDev} } ) { delete $hash->{monitoredDevs}{$notifyDev}; my $notifyDevString = $hash->{NOTIFYDEV}; $notifyDevString = '' if ( !$notifyDevString ); my %hash; %hash = map { ( $_ => 1 ) } grep { " $notifyDev " !~ m/ $_ / } split( ',', "$notifyDevString,$notifyDev" ); $hash->{NOTIFYDEV} = join( ',', sort keys %hash ); } } readingsSingleUpdate( $hash, '.monitoredDevs', eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); } ## Sub zum steuern der Rolläden bei einem Fenster Event sub EventProcessingWindowRec($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; my $reading = $shutters->getWinDevReading; if ( $events =~ m#.*$reading:.*?([Oo]pen(?>ed)?|[Cc]losed?|tilt(?>ed)?|true|false)# and IsAfterShuttersManualBlocking($shuttersDev) ) { my $match = $1; ASC_Debug( 'EventProcessingWindowRec: ' . $shutters->getShuttersDev . ' - RECEIVED EVENT: ' . $events . ' - IDENTIFIED EVENT: ' . $1 . ' - STORED EVENT: ' . $match ); $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); #### Hardware Lock der Rollläden $shutters->setHardLockOut('off') if ( $match =~ /[Cc]lose|true/ and $shutters->getShuttersPlace eq 'terrace' ); $shutters->setHardLockOut('on') if ( $match =~ /[Oo]pen|false/ and $shutters->getShuttersPlace eq 'terrace' ); ASC_Debug( 'EventProcessingWindowRec: ' . $shutters->getShuttersDev . ' - HOMEMODE: ' . $homemode . ' QueryShuttersPosWinRecTilted:' . $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) . ' QueryShuttersPosWinRecComfort: ' . $shutters->getQueryShuttersPos( $shutters->getComfortOpenPos ) ); if ( $match =~ /[Cc]lose|true/ and IsAfterShuttersTimeBlocking($shuttersDev) and ( $shutters->getStatus == $shutters->getVentilatePos or $shutters->getStatus == $shutters->getComfortOpenPos or $shutters->getStatus == $shutters->getOpenPos ) and ( $shutters->getVentilateOpen eq 'on' or $ascDev->getAutoShuttersControlComfort eq 'on' ) ) { ASC_Debug( 'EventProcessingWindowRec: ' . $shutters->getShuttersDev . ' Event Closed' ); if ( $shutters->getIsDay and ( ( $homemode ne 'asleep' and $homemode ne 'gotosleep' ) or $homemode eq 'none' ) and $shutters->getModeUp ne 'absent' and $shutters->getModeUp ne 'off' ) { if ( $shutters->getIfInShading and $shutters->getShadingPos != $shutters->getStatus ) { $shutters->setLastDrive('shading in'); $shutters->setNoDelay(1); $shutters->setDriveCmd( $shutters->getShadingPos ); } elsif ($shutters->getStatus != $shutters->getOpenPos or $shutters->getStatus != $shutters->getLastManPos ) { if ( $shutters->getPrivacyDownStatus == 2 ) { $shutters->setLastDrive( 'window closed at privacy night close'); $shutters->setNoDelay(1); $shutters->setDriveCmd( $shutters->getPrivacyDownPos ); } # elsif ( $shutters->getPrivacyUpStatus == 2 ) { # $shutters->setLastDrive( # 'window closed at privacy day open'); # $shutters->setNoDelay(1); # $shutters->setDriveCmd( $shutters->getPrivacyUpPos ); # } else { $shutters->setLastDrive('window closed at day'); $shutters->setNoDelay(1); $shutters->setDriveCmd( ( $shutters->getVentilatePosAfterDayClosed eq 'open' ? $shutters->getOpenPos : $shutters->getLastManPos ) ); } } } elsif ( $shutters->getModeDown ne 'absent' and $shutters->getModeDown ne 'off' and ( not $shutters->getIsDay or $homemode eq 'asleep' or $homemode eq 'gotosleep' ) and $ascDev->getAutoShuttersControlEvening eq 'on' ) { if ( $shutters->getPrivacyUpStatus == 2 ) { $shutters->setLastDrive( 'window closed at privacy day open'); $shutters->setNoDelay(1); $shutters->setDriveCmd( $shutters->getPrivacyDownPos ); } else { $shutters->setLastDrive('window closed at night'); $shutters->setNoDelay(1); $shutters->setDriveCmd( ( $shutters->getSleepPos > 0 ? $shutters->getSleepPos : $shutters->getClosedPos ) ); } } } elsif ( ( $match =~ /tilt/ or ( $match =~ /[Oo]pen|false/ and $shutters->getSubTyp eq 'twostate' ) ) and $shutters->getVentilateOpen eq 'on' and $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) ) { $shutters->setLastDrive('ventilate - window open'); $shutters->setNoDelay(1); $shutters->setDriveCmd( ( ( $shutters->getShuttersPlace eq 'terrace' and $shutters->getSubTyp eq 'twostate' ) ? $shutters->getOpenPos : $shutters->getVentilatePos ) ); } elsif ( $match =~ /[Oo]pen|false/ and $shutters->getSubTyp eq 'threestate' ) { my $posValue; my $setLastDrive; if ( $ascDev->getAutoShuttersControlComfort eq 'on' and $shutters->getQueryShuttersPos( $shutters->getComfortOpenPos ) ) { $posValue = $shutters->getComfortOpenPos; $setLastDrive = 'comfort - window open'; } elsif ( $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) and $shutters->getVentilateOpen eq 'on' ) { $posValue = $shutters->getVentilatePos; $setLastDrive = 'ventilate - window open'; } if ( defined($posValue) and $posValue ) { $shutters->setLastDrive($setLastDrive); $shutters->setNoDelay(1); $shutters->setDriveCmd( # ( # $shutters->getShuttersPlace eq 'terrace' # ? $shutters->getOpenPos $posValue # ) ); } } } } ## Sub zum steuern der Rolladen bei einem Bewohner/Roommate Event sub EventProcessingRoommate($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); my $reading = $shutters->getRoommatesReading; if ( $events =~ m#$reading:\s(absent|gotosleep|asleep|awoken|home)# ) { Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingRoommate: " . $shutters->getRoommatesReading ); Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingRoommate: $shuttersDev und Events $events" ); my $getModeUp = $shutters->getModeUp; my $getModeDown = $shutters->getModeDown; my $getRoommatesStatus = $shutters->getRoommatesStatus; my $getRoommatesLastStatus = $shutters->getRoommatesLastStatus; my $posValue; if ( ( $1 eq 'home' or $1 eq 'awoken' ) and ( $getRoommatesStatus eq 'home' or $getRoommatesStatus eq 'awoken' ) and ( $ascDev->getAutoShuttersControlMorning eq 'on' or $shutters->getUp eq 'roommate' ) and IsAfterShuttersManualBlocking($shuttersDev) ) { Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingRoommate_1: $shuttersDev und Events $events" ); if ( ( $getRoommatesLastStatus eq 'asleep' or $getRoommatesLastStatus eq 'awoken' ) and ( $shutters->getIsDay or $shutters->getUp eq 'roommate' ) and ( IsAfterShuttersTimeBlocking($shuttersDev) or $shutters->getUp eq 'roommate' ) ) { Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingRoommate_2: $shuttersDev und Events $events" ); if ( $shutters->getIfInShading and not $shutters->getShadingManualDriveStatus and $shutters->getStatus != $shutters->getShadingPos ) { $shutters->setLastDrive('shading in'); $posValue = $shutters->getShadingPos; } else { $shutters->setLastDrive('roommate awoken'); $posValue = $shutters->getOpenPos; } ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } elsif ( ( $getRoommatesLastStatus eq 'absent' or $getRoommatesLastStatus eq 'gone' ) and $getRoommatesStatus eq 'home' ) { if ( not $shutters->getIsDay and IsAfterShuttersTimeBlocking($shuttersDev) and ( $getModeDown eq 'home' or $getModeDown eq 'always' ) ) { $shutters->setLastDrive('roommate come home'); if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 or $shutters->getVentilateOpen eq 'off' ) { $posValue = ( $shutters->getSleepPos > 0 ? $shutters->getSleepPos : $shutters->getClosedPos ); } else { $posValue = $shutters->getVentilatePos; $shutters->setLastDrive( $shutters->getLastDrive . ' - ventilate mode' ); } ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } elsif ( ( $shutters->getIsDay or $shutters->getUp eq 'roommate' ) and IsAfterShuttersTimeBlocking($shuttersDev) and ( $getModeUp eq 'home' or $getModeUp eq 'always' ) ) { if ( $shutters->getIfInShading and not $shutters->getShadingManualDriveStatus and $shutters->getStatus == $shutters->getOpenPos and $shutters->getShadingMode eq 'home' ) { $shutters->setLastDrive('shading in'); $posValue = $shutters->getShadingPos; ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } elsif ( ( not $shutters->getIfInShading or $shutters->getShadingMode eq 'absent' ) and ( $shutters->getStatus == $shutters->getClosedPos or $shutters->getStatus == $shutters->getShadingPos ) ) { $shutters->setLastDrive( ( $shutters->getStatus == $shutters->getClosedPos ? 'roommate come home' : 'shading out' ) ); $posValue = $shutters->getOpenPos; ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } } } } elsif ( ( $1 eq 'gotosleep' or $1 eq 'asleep' ) and ( $ascDev->getAutoShuttersControlEvening eq 'on' or $shutters->getDown eq 'roommate' ) and ( IsAfterShuttersManualBlocking($shuttersDev) or $shutters->getDown eq 'roommate' ) ) { $shutters->setLastDrive('roommate asleep'); if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 or $shutters->getVentilateOpen eq 'off' ) { $posValue = ( $shutters->getSleepPos > 0 ? $shutters->getSleepPos : $shutters->getClosedPos ); } else { $posValue = $shutters->getVentilatePos; $shutters->setLastDrive( $shutters->getLastDrive . ' - ventilate mode' ); } ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } elsif ( $1 eq 'absent' and ( not $shutters->getIsDay or $shutters->getDown eq 'roommate' or $shutters->getShadingMode eq 'absent' ) ) { if ( ( $shutters->getIsDay or $shutters->getUp eq 'roommate' ) and $shutters->getIfInShading and not $shutters->getQueryShuttersPos( $shutters->getShadingPos ) and $shutters->getShadingMode eq 'absent' ) { $posValue = $shutters->getShadingPos; $shutters->setLastDrive('shading in'); ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } elsif ( ( not $shutters->getIsDay or $shutters->getDown eq 'roommate' ) and $getModeDown eq 'absent' and $getRoommatesStatus eq 'absent' ) { $posValue = $shutters->getClosedPos; $shutters->setLastDrive('roommate absent'); ShuttersCommandSet( $hash, $shuttersDev, $posValue ); } } } } sub EventProcessingResidents($@) { my ( $hash, $device, $events ) = @_; my $name = $device; my $reading = $ascDev->getResidentsReading; my $getResidentsLastStatus = $ascDev->getResidentsLastStatus; if ( $events =~ m#$reading:\s((?:pet_[a-z]+)|(?:absent))# ) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); my $getModeUp = $shutters->getModeUp; my $getModeDown = $shutters->getModeDown; $shutters->setHardLockOut('off'); if ( $ascDev->getSelfDefense eq 'on' and $shutters->getSelfDefenseMode ne 'off' or ( $getModeDown eq 'absent' or $getModeDown eq 'always' ) ) { if ( $ascDev->getSelfDefense eq 'on' and ( $shutters->getSelfDefenseMode eq 'absent' or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSelfDefenseMode eq 'gone' and $shutters->getShuttersPlace eq 'terrace' and $shutters->getSelfDefenseMode ne 'off' ) ) ) { $shutters->setLastDrive('selfDefense absent active'); $shutters->setSelfDefenseAbsent( 0, 1 ) ; # der erste Wert ist ob der timer schon läuft, der zweite ist ob self defense aktiv ist durch die Bedingungen $shutters->setSelfDefenseState(1); $shutters->setDriveCmd( $shutters->getClosedPos ); } elsif ( ( $getModeDown eq 'absent' or $getModeDown eq 'always' ) and not $shutters->getIsDay and IsAfterShuttersTimeBlocking($shuttersDev) and $shutters->getRoommatesStatus eq 'none' ) { $shutters->setLastDrive('residents absent'); $shutters->setDriveCmd( $shutters->getClosedPos ); } } } } elsif ( $events =~ m#$reading:\s(gone)# and $ascDev->getSelfDefense eq 'on' ) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); $shutters->setHardLockOut('off'); if ( $shutters->getSelfDefenseMode ne 'off' ) { $shutters->setLastDrive('selfDefense gone active'); $shutters->setSelfDefenseState(1); $shutters->setDriveCmd( $shutters->getClosedPos ); } } } elsif ( $events =~ m#$reading:\s((?:[a-z]+_)?home)# 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 $shutters->getIsDay and $shutters->getRoommatesStatus eq 'none' and ( $getModeDown eq 'home' or $getModeDown eq 'always' ) and $getResidentsLastStatus ne 'asleep' and $getResidentsLastStatus ne 'awoken' and IsAfterShuttersTimeBlocking($shuttersDev) and not $shutters->getSelfDefenseState ) { $shutters->setLastDrive('residents come home'); $shutters->setDriveCmd( $shutters->getClosedPos ); } elsif ( ( $shutters->getShadingMode eq 'home' or $shutters->getShadingMode eq 'always' ) and $shutters->getIsDay and $shutters->getIfInShading and $shutters->getRoommatesStatus eq 'none' and $shutters->getStatus != $shutters->getShadingPos and not $shutters->getShadingManualDriveStatus and not( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' ) and not $shutters->getSelfDefenseState ) { $shutters->setLastDrive('shading in'); $shutters->setDriveCmd( $shutters->getShadingPos ); } elsif ( $shutters->getShadingMode eq 'absent' and $shutters->getIsDay and $shutters->getIfInShading and $shutters->getStatus == $shutters->getShadingPos and $shutters->getRoommatesStatus eq 'none' and not $shutters->getShadingManualDriveStatus and not( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' ) and not $shutters->getSelfDefenseState ) { $shutters->setLastDrive('shading out'); $shutters->setDriveCmd( $shutters->getLastPos ); } elsif ( $ascDev->getSelfDefense eq 'on' and $shutters->getSelfDefenseMode ne 'off' and not $shutters->getIfInShading and ( $getResidentsLastStatus eq 'gone' or $getResidentsLastStatus eq 'absent' ) and $shutters->getSelfDefenseState ) { RemoveInternalTimer( $shutters->getSelfDefenseAbsentTimerhash ) if ( $getResidentsLastStatus eq 'absent' and $ascDev->getSelfDefense eq 'on' and $shutters->getSelfDefenseMode ne 'off' and not $shutters->getSelfDefenseAbsent and $shutters->getSelfDefenseAbsentTimerrun ); if ( $shutters->getStatus == $shutters->getClosedPos and $shutters->getIsDay ) { $shutters->setHardLockOut('on') if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' and ( $getModeUp eq 'absent' or $getModeUp eq 'off' ) ); $shutters->setSelfDefenseState(0); $shutters->setLastDrive('selfDefense inactive'); $shutters->setDriveCmd( ( $shutters->getPrivacyDownStatus == 2 ? $shutters->getPrivacyDownPos : $shutters->getOpenPos ) ); } } elsif ( $shutters->getStatus == $shutters->getClosedPos and $shutters->getIsDay and $shutters->getRoommatesStatus eq 'none' and ( $getModeUp eq 'home' or $getModeUp eq 'always' ) and IsAfterShuttersTimeBlocking($shuttersDev) and not $shutters->getIfInShading and not $shutters->getSelfDefenseState ) { if ( $getResidentsLastStatus eq 'asleep' or $getResidentsLastStatus eq 'awoken' ) { $shutters->setLastDrive('residents awoken'); } else { $shutters->setLastDrive('residents home'); } $shutters->setDriveCmd( $shutters->getOpenPos ); } } } } sub EventProcessingRain($@) { #### Ist noch nicht fertig, es fehlt noch das verzögerte Prüfen auf erhalten bleiben des getriggerten Wertes. my ( $hash, $device, $events ) = @_; my $name = $device; my $reading = $ascDev->getRainSensorReading; if ( $events =~ m#$reading:\s(\d+(\.\d+)?|rain|dry)# ) { 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 } RainProtection( $hash, $val, $triggerMax, $closedPos ); } } sub RainProtection(@) { my ( $hash, $val, $triggerMax, $closedPos ) = @_; foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); next if ( $shutters->getRainProtection eq 'off' ); if ( $val > $triggerMax and $shutters->getStatus != $closedPos and IsAfterShuttersManualBlocking($shuttersDev) and $shutters->getRainProtectionStatus eq 'unprotected' ) { $shutters->setLastDrive('rain protected'); $shutters->setDriveCmd($closedPos); $shutters->setRainProtectionStatus('protected'); } elsif ( ( $val == 0 or $val < $triggerMax ) and $shutters->getStatus == $closedPos and IsAfterShuttersManualBlocking($shuttersDev) and $shutters->getRainProtectionStatus eq 'protected' ) { $shutters->setLastDrive('rain un-protected'); $shutters->setDriveCmd( ( $shutters->getIsDay ? $shutters->getLastPos : ( $shutters->getPrivacyDownStatus == 2 ? $shutters->getPrivacyDownPos : $shutters->getClosedPos ) ) ); $shutters->setRainProtectionStatus('unprotected'); } } } sub EventProcessingWind($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); my $reading = $ascDev->getWindSensorReading; if ( $events =~ m#$reading:\s(\d+(\.\d+)?)# ) { foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); ASC_Debug( 'EventProcessingWind: ' . $shutters->getShuttersDev . ' - WindProtection1: ' . $shutters->getWindProtectionStatus . ' WindMax1: ' . $shutters->getWindMax . ' WindMin1: ' . $shutters->getWindMin . ' Bekommender Wert1: ' . $1 ); next if ( ( CheckIfShuttersWindowRecOpen($shuttersDev) != 0 and $shutters->getShuttersPlace eq 'terrace' ) or $shutters->getWindProtection eq 'off' ); if ( $1 > $shutters->getWindMax and $shutters->getWindProtectionStatus eq 'unprotected' ) { $shutters->setLastDrive('wind protected'); $shutters->setDriveCmd( $shutters->getWindPos ); $shutters->setWindProtectionStatus('protected'); } elsif ( $1 < $shutters->getWindMin and $shutters->getWindProtectionStatus eq 'protected' ) { $shutters->setLastDrive('wind un-protected'); $shutters->setDriveCmd( ( $shutters->getIsDay ? $shutters->getLastPos : ( $shutters->getPrivacyDownStatus == 2 ? $shutters->getPrivacyDownPos : $shutters->getClosedPos ) ) ); $shutters->setWindProtectionStatus('unprotected'); } ASC_Debug( 'EventProcessingWind: ' . $shutters->getShuttersDev . ' - WindProtection2: ' . $shutters->getWindProtectionStatus . ' 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 ( ( $shutters->getDown eq 'brightness' or $shutters->getUp eq 'brightness' ) or ( ( ( ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) and ( not IsWe() or ( IsWe() and $ascDev->getSunriseTimeWeHoliday eq 'off' ) ) ) or ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) and IsWe() and $ascDev->getSunriseTimeWeHoliday eq 'on' ) ) 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+(\.\d+)?)# ) { 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; } my $brightnessPrivacyUpVal = $shutters->getPrivacyUpBrightnessVal; my $brightnessPrivacyDownVal = $shutters->getPrivacyDownBrightnessVal; 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. Werte für weitere Parameter - getUp ist: ' . $shutters->getUp . ' getDown ist: ' . $shutters->getDown . ' getSunrise ist: ' . $shutters->getSunrise . ' getSunset ist: ' . $shutters->getSunset ); if ( ( ( ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) and ( not IsWe() or ( IsWe() and $ascDev->getSunriseTimeWeHoliday eq 'off' ) ) ) or ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) and IsWe() and $ascDev->getSunriseTimeWeHoliday eq 'on' ) ) and int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeUpLate ) / 86400 ) ) and ( $1 > $brightnessMaxVal or ( $1 > $brightnessPrivacyUpVal and $shutters->getPrivacyUpStatus == 1 ) ) and $shutters->getUp eq 'brightness' and not $shutters->getSunrise and $ascDev->getAutoShuttersControlMorning eq 'on' and ( $ascDev->getSelfDefense eq 'off' or $shutters->getSelfDefenseMode eq 'off' or ( $ascDev->getSelfDefense eq 'on' and $ascDev->getResidentsStatus ne 'gone' ) ) ) { 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' ); if ( $shutters->getModeUp eq $homemode or ( $shutters->getModeUp eq 'absent' and $homemode eq 'gone' ) or $shutters->getModeUp eq 'always' ) { my $roommatestatus = $shutters->getRoommatesStatus; if ( $roommatestatus eq 'home' or $roommatestatus eq 'awoken' or $roommatestatus eq 'absent' or $roommatestatus eq 'gone' or $roommatestatus eq 'none' and ( $ascDev->getSelfDefense eq 'off' or ( $ascDev->getSelfDefense eq 'on' and CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) or ( $ascDev->getSelfDefense eq 'on' and CheckIfShuttersWindowRecOpen($shuttersDev) != 0 and $ascDev->getResidentsStatus eq 'home' ) ) ) { if ( $brightnessPrivacyUpVal > 0 and $1 < $brightnessMaxVal and $1 > $brightnessPrivacyUpVal ) # and $shutters->getPrivacyUpStatus == 1 ) { $shutters->setPrivacyUpStatus(2); $shutters->setLastDrive('brightness privacy day open'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getPrivacyUpPos ) unless ( not $shutters->getQueryShuttersPos( $shutters->getPrivacyUpPos ) ); ASC_Debug( 'EventProcessingBrightness: ' . $shutters->getShuttersDev . ' - Verarbeitung für Sunrise Privacy Down. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Grund des fahrens: ' . $shutters->getLastDrive ); CreateSunRiseSetShuttersTimer( $hash, $shuttersDev ); } else { $shutters->setLastDrive( 'maximum brightness threshold exceeded'); $shutters->setSunrise(1); $shutters->setSunset(0); $shutters->setPrivacyUpStatus(0) if ( $shutters->getPrivacyUpStatus == 2 ); 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' ); } } } elsif ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / 86400 ) and int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeDownLate ) / 86400 ) and ( $1 < $brightnessMinVal or ( $1 < $brightnessPrivacyDownVal and $shutters->getPrivacyDownStatus == 1 ) ) and $shutters->getDown eq 'brightness' and not $shutters->getSunset and IsAfterShuttersManualBlocking($shuttersDev) and $ascDev->getAutoShuttersControlEvening eq 'on' ) { Log3( $name, 4, "AutoShuttersControl ($shuttersDev) - EventProcessingBrightness: Steuerung für Abends" ); ASC_Debug( 'EventProcessingBrightness: ' . $shutters->getShuttersDev . ' - Verarbeitungszeit für Sunset wurd erkannt. Prüfe Status der Roommates' ); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); if ( $shutters->getModeDown eq $homemode or ( $shutters->getModeDown eq 'absent' and $homemode eq 'gone' ) or $shutters->getModeDown eq 'always' ) { my $posValue; my $lastDrive; ## Setzt den PrivacyDown Modus für die Sichtschutzfahrt auf den Status 0 ## 1 bedeutet das PrivacyDown Timer aktiviert wurde, 2 beudet das er im privacyDown ist ## also das Rollo in privacyDown Position steht und VOR der endgültigen Nachfahrt # $shutters->setPrivacyDownStatus(0) # if ( not defined( $shutters->getPrivacyDownStatus ) ); if ( $brightnessPrivacyDownVal > 0 and $1 > $brightnessMinVal and $1 < $brightnessPrivacyDownVal ) { $lastDrive = 'brightness privacy night close'; $posValue = ( ( not $shutters->getQueryShuttersPos( $shutters->getPrivacyDownPos ) ) ? $shutters->getPrivacyDownPos : $shutters->getStatus ); $shutters->setPrivacyDownStatus(2); ASC_Debug( 'EventProcessingBrightness: ' . $shutters->getShuttersDev . ' - Verarbeitung für Sunset Privacy Down. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Grund des fahrens: ' . $shutters->getLastDrive ); } elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' and $ascDev->getAutoShuttersControlComfort eq 'on' ) { $posValue = $shutters->getComfortOpenPos; $lastDrive = 'minimum brightness threshold fell below'; } elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 or $shutters->getVentilateOpen eq 'off' ) { $posValue = ( $shutters->getSleepPos > 0 ? $shutters->getSleepPos : $shutters->getClosedPos ); $lastDrive = 'minimum brightness threshold fell below'; } else { $posValue = $shutters->getVentilatePos; $lastDrive = 'minimum brightness threshold fell below'; } $shutters->setLastDrive($lastDrive); if ( $shutters->getPrivacyDownStatus != 2 and ( $posValue != $shutters->getStatus or $shutters->getSelfDefenseState ) ) { $shutters->setSunrise(0); $shutters->setSunset(1); } $shutters->setPrivacyDownStatus(0) if ( $shutters->getPrivacyDownStatus == 2 and $shutters->getSunrise ); 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 ) unless ( $shutters->getPrivacyDownStatus == 2 ); 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 { EventProcessingShadingBrightness( $hash, $shuttersDev, $events ) unless ( $shutters->getPrivacyDownStatus == 2 ); 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.' ); } } 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' ); } } sub EventProcessingShadingBrightness($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); my $reading = $shutters->getBrightnessReading; my $outTemp = $ascDev->getOutTemp; 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+(\.\d+)?)# ) { Log3( $name, 4, "AutoShuttersControl ($shuttersDev) - EventProcessingShadingBrightness Brightness: " . $1 ); ## Brightness Wert in ein Array schieben zur Berechnung eines Average Wertes $shutters->setPushBrightnessInArray($1); ASC_Debug( 'EventProcessingShadingBrightness: ' . $shutters->getShuttersDev . ' - Nummerischer Brightness-Wert wurde erkannt. Der Brightness Average Wert ist: ' . $shutters->getBrightnessAverage . ' RainProtection: ' . $shutters->getRainProtectionStatus . ' WindProtection: ' . $shutters->getWindProtectionStatus ); if ( $ascDev->getAutoShuttersControlShading eq 'on' and $shutters->getRainProtectionStatus eq 'unprotected' and $shutters->getWindProtectionStatus eq 'unprotected' ) { $outTemp = $shutters->getOutTemp if ( $shutters->getOutTemp != -100 ); ShadingProcessing( $hash, $shuttersDev, $ascDev->getAzimuth, $ascDev->getElevation, $outTemp, $shutters->getShadingAzimuthLeft, $shutters->getShadingAzimuthRight ); ASC_Debug( 'EventProcessingShadingBrightness: ' . $shutters->getShuttersDev . ' - Alle Bedingungen zur weiteren Beschattungsverarbeitung sind erfüllt. Es wird nun die eigentliche Beschattungsfunktion aufgerufen' ); } } } sub EventProcessingTwilightDevice($@) { my ( $hash, $device, $events ) = @_; # Twilight # azimuth = azimuth = Sonnenwinkel # elevation = elevation = Sonnenhöhe # # Astro # 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 ); my $outTemp = $ascDev->getOutTemp; $azimuth = $2 if ( $1 eq 'azimuth' or $1 eq 'SunAz' ); $elevation = $2 if ( $1 eq 'elevation' or $1 eq 'SunAlt' ); $azimuth = $ascDev->getAzimuth if ( not defined($azimuth) and not $azimuth ); $elevation = $ascDev->getElevation if ( not defined($elevation) and not $elevation ); ASC_Debug( 'EventProcessingTwilightDevice: ' . $name . ' - Passendes Event wurde erkannt. Verarbeitung über alle Rollos beginnt' ); foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); $outTemp = $shutters->getOutTemp if ( $shutters->getOutTemp != -100 ); ASC_Debug( 'EventProcessingTwilightDevice: ' . $shutters->getShuttersDev . ' RainProtection: ' . $shutters->getRainProtectionStatus . ' WindProtection: ' . $shutters->getWindProtectionStatus ); if ( $ascDev->getAutoShuttersControlShading eq 'on' and $shutters->getRainProtectionStatus eq 'unprotected' and $shutters->getWindProtectionStatus eq 'unprotected' ) { ShadingProcessing( $hash, $shuttersDev, $azimuth, $elevation, $outTemp, $shutters->getShadingAzimuthLeft, $shutters->getShadingAzimuthRight ); ASC_Debug( 'EventProcessingTwilightDevice: ' . $shutters->getShuttersDev . ' - Alle Bedingungen zur weiteren Beschattungsverarbeitung sind erfüllt. Es wird nun die Beschattungsfunktion ausgeführt' ); } } } } sub ShadingProcessing($@) { ### angleMinus ist $shutters->getShadingAzimuthLeft ### anglePlus ist $shutters->getShadingAzimuthRight ### winPos ist die Fensterposition $shutters->getDirection my ( $hash, $shuttersDev, $azimuth, $elevation, $outTemp, $azimuthLeft, $azimuthRight ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); my $brightness = $shutters->getBrightnessAverage; ASC_Debug( 'ShadingProcessing: ' . $shutters->getShuttersDev . ' - Übergebende Werte - Azimuth:' . $azimuth . ', Elevation: ' . $elevation . ', Brightness: ' . $brightness . ', OutTemp: ' . $outTemp . ', Azimut Beschattung: ' . $azimuthLeft . ', Azimut Endschattung: ' . $azimuthRight . ', Ist es nach der Zeitblockadezeit: ' . ( IsAfterShuttersTimeBlocking($shuttersDev) ? 'JA' : 'NEIN' ) . ', Das Rollo ist in der Beschattung und wurde manuell gefahren: ' . ( $shutters->getShadingManualDriveStatus ? 'JA' : 'NEIN' ) . ', Ist es nach der Hälfte der Beschattungswartezeit: ' . ( ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < ( $shutters->getShadingWaitingPeriod / 2 ) ? 'NEIN' : 'JA' ) ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " Azimuth: " . $azimuth . " Elevation: " . $elevation . " Brightness: " . $brightness . " OutTemp: " . $outTemp ); return if ( $azimuth == -1 or $elevation == -1 or $brightness == -1 or $outTemp == -100 or ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < ( $shutters->getShadingWaitingPeriod / 2 ) or $shutters->getShadingMode eq 'off' ); 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 $azimuth < $azimuthLeft or $azimuth > $azimuthRight ) and $shutters->getShadingStatus ne 'out' ) { $shutters->setShadingLastStatus('in'); $shutters->setShadingStatus('out'); ASC_Debug( 'ShadingProcessing: ' . $shutters->getShuttersDev . ' - Es ist Nacht oder die Aussentemperatur unterhalb der Shading Temperatur. Die Beschattung wird Zwangsbeendet' ); Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing - Der Sonnenstand ist ausserhalb der Winkelangaben oder die Aussentemperatur unterhalb der Shading Temperatur " ); } elsif ($azimuth < $azimuthLeft or $azimuth > $azimuthRight or $elevation < $shutters->getShadingMinElevation or $elevation > $shutters->getShadingMaxElevation or $brightness < $shutters->getShadingStateChangeCloudy or $outTemp < $shutters->getShadingMinOutsideTemperature ) { $shutters->setShadingStatus('out reserved') if ( $shutters->getShadingStatus eq 'in' or $shutters->getShadingStatus eq 'in reserved' ); if ( ( $shutters->getShadingStatus eq 'out reserved' and ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) ) > $shutters->getShadingWaitingPeriod ) { $shutters->setShadingStatus('out'); $shutters->setShadingLastStatus('in') if ( $shutters->getShadingLastStatus eq 'out' ); } Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " In der Out Abfrage, Shadingwert: " . $shutters->getShadingStatus . ", Zeitstempel: " . $shutters->getShadingStatusTimestamp ); 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 > $azimuthLeft and $azimuth < $azimuthRight and $elevation > $shutters->getShadingMinElevation and $elevation < $shutters->getShadingMaxElevation and $brightness > $shutters->getShadingStateChangeSunny and $outTemp > $shutters->getShadingMinOutsideTemperature ) { $shutters->setShadingStatus('in reserved') if ( $shutters->getShadingStatus eq 'out' or $shutters->getShadingStatus eq 'out reserved' ); if ( $shutters->getShadingStatus eq 'in reserved' and ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) > ( $shutters->getShadingWaitingPeriod / 2 ) ) { $shutters->setShadingStatus('in'); $shutters->setShadingLastStatus('out') if ( $shutters->getShadingLastStatus eq 'in' ); } Log3( $name, 4, "AutoShuttersControl ($name) - Shading Processing, Rollladen: " . $shuttersDev . " In der In Abfrage, Shadingwert: " . $shutters->getShadingStatus . ", Zeitstempel: " . $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 ); } ShadingProcessingDriveCommand( $hash, $shuttersDev ) if ( $shutters->getIsDay and IsAfterShuttersTimeBlocking($shuttersDev) and not $shutters->getShadingManualDriveStatus and ( ( $shutters->getShadingStatus eq 'out' and $shutters->getShadingLastStatus eq 'in' ) or ( $shutters->getShadingStatus eq 'in' and $shutters->getShadingLastStatus eq 'out' ) ) ); } sub ShadingProcessingDriveCommand($$) { my ( $hash, $shuttersDev ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); my $getShadingPos = $shutters->getShadingPos; my $getStatus = $shutters->getStatus; my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); if ( $shutters->getShadingMode eq 'always' or $shutters->getShadingMode eq $homemode ) { $shutters->setShadingStatus( $shutters->getShadingStatus ) if ( ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) > ( $shutters->getShadingWaitingPeriod / 2 ) ); if ( $shutters->getShadingStatus eq 'in' and $getShadingPos != $getStatus ) { if ( not $shutters->getQueryShuttersPos($getShadingPos) and not( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' ) ) { $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->getShadingStatus eq 'out' and $getShadingPos == $getStatus ) { $shutters->setLastDrive('shading out'); ShuttersCommandSet( $hash, $shuttersDev, ( $getShadingPos == $shutters->getLastPos ? $shutters->getOpenPos : ( $shutters->getQueryShuttersPos( $shutters->getLastPos ) ? $shutters->getLastPos : $shutters->getOpenPos ) ) ); 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->getShadingStatus ); ASC_Debug( 'ShadingProcessing: ' . $shutters->getShuttersDev . ' - Der aktuelle Beschattungsstatus ist: ' . $shutters->getShadingStatus . ', Beschattungsstatus Zeitstempel: ' . strftime( "%Y.%m.%e %T", localtime( $shutters->getShadingStatusTimestamp ) ) ); } } sub EventProcessingPartyMode($) { my $hash = shift; my $name = $hash->{NAME}; foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); next if ( $shutters->getPartyMode eq 'off' ); if ( not $shutters->getIsDay and $shutters->getModeDown ne 'off' and IsAfterShuttersManualBlocking($shuttersDev) ) { if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' ) { Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingPartyMode Fenster offen" ); $shutters->setDelayCmd( $shutters->getClosedPos ); Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingPartyMode - Spring in ShuttersCommandDelaySet" ); } else { Log3( $name, 4, "AutoShuttersControl ($name) - EventProcessingPartyMode Fenster nicht offen" ); $shutters->setLastDrive('drive after party mode'); ShuttersCommandSet( $hash, $shuttersDev, ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ? $shutters->getClosedPos : $shutters->getVentilatePos ) ); } } elsif ( $shutters->getDelayCmd ne 'none' and $shutters->getIsDay and IsAfterShuttersManualBlocking($shuttersDev) ) { $shutters->setLastDrive('drive after party mode'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getDelayCmd ); } } } sub EventProcessingAdvShuttersClose($) { my $hash = shift; my $name = $hash->{NAME}; foreach my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shuttersDev); next if ( not $shutters->getAdv and not $shutters->getAdvDelay ); $shutters->setLastDrive('adv delay close'); $shutters->setAdvDelay(1); ShuttersCommandSet( $hash, $shuttersDev, ( $shutters->getDelayCmd ne 'none' ? $shutters->getDelayCmd : $shutters->getClosedPos ) ); } } sub EventProcessingShutters($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; ASC_Debug( 'EventProcessingShutters: ' . ' Fn wurde durch Notify aufgerufen da ASC_Pos_Reading Event erkannt wurde ' . ' - RECEIVED EVENT: ' . Dumper $events); if ( $events =~ m#.*:\s(\d+)# ) { $shutters->setShuttersDev($shuttersDev); $ascDev->setPosReading; ASC_Debug( 'EventProcessingShutters: ' . $shutters->getShuttersDev . ' - Event vom Rollo erkannt. Es wird nun eine etwaige manuelle Fahrt ausgewertet.' . ' Int von gettimeofday: ' . int( gettimeofday() ) . ' Last Position Timestamp: ' . $shutters->getLastPosTimestamp . ' Drive Up Max Duration: ' . $shutters->getDriveUpMaxDuration . ' Last Position: ' . $shutters->getLastPos . ' aktuelle Position: ' . $shutters->getStatus ); if ( ( int( gettimeofday() ) - $shutters->getLastPosTimestamp ) > $shutters->getDriveUpMaxDuration and ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) > $shutters->getDriveUpMaxDuration ) { $shutters->setLastDrive('manual'); $shutters->setLastDriveReading; $ascDev->setStateReading; $shutters->setLastManPos($1); $shutters->setShadingManualDriveStatus(1) if ( $shutters->getIsDay and $shutters->getIfInShading ); ASC_Debug( 'EventProcessingShutters: eine manualle Fahrt wurde erkannt!'); } else { $shutters->setLastDriveReading; $ascDev->setStateReading; ASC_Debug( 'EventProcessingShutters: eine automatisierte Fahrt durch ASC wurde erkannt! Es werden nun die LastDriveReading und StateReading Werte gesetzt!' ); } } ASC_Debug( 'EventProcessingShutters: ' . ' Fn wurde durlaufen und es sollten Debugausgaben gekommen sein. ' . ' !!!Wenn nicht!!! wurde der Event nicht korrekt als Nummerisch erkannt. ' ); } sub EventProcessingExternalTriggerDevice($@) { my ( $hash, $shuttersDev, $events ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); ASC_Debug( 'EventProcessingExternalTriggerDevice: ' . ' Fn wurde durch Notify ' . ' - RECEIVED EVENT: ' . Dumper $events); my $reading = $shutters->getExternalTriggerReading; my $triggerValActive = $shutters->getExternalTriggerValueActive; my $triggerValInactive = $shutters->getExternalTriggerValueInactive; my $triggerPosActive = $shutters->getExternalTriggerPosActive; my $triggerPosInactive = $shutters->getExternalTriggerPosInactive; if ( $events =~ m#$reading:\s($triggerValActive)# and not $shutters->getQueryShuttersPos($triggerPosActive) ) { ASC_Debug( 'EventProcessingExternalTriggerDevice: ' . ' In der RegEx Schleife Trigger Val Aktiv' . ' - TriggerVal: ' . $triggerValActive ); $shutters->setLastDrive('external trigger device active'); $shutters->setNoDelay(1); $shutters->setExternalTriggerState(1); ShuttersCommandSet( $hash, $shuttersDev, $triggerPosActive ); } elsif ( $events =~ m#$reading:\s($triggerValInactive)# and ( $shutters->getPrivacyDownStatus != 2 or $shutters->getPrivacyUpStatus != 2 ) and not $shutters->getIfInShading ) { ASC_Debug( 'EventProcessingExternalTriggerDevice: ' . ' In der RegEx Schleife Trigger Val Inaktiv' . ' - TriggerVal: ' . $triggerValInactive ); $shutters->setLastDrive('external trigger device inactive'); $shutters->setNoDelay(1); $shutters->setExternalTriggerState(1); ShuttersCommandSet( $hash, $shuttersDev, $triggerPosInactive ); } ASC_Debug( 'EventProcessingExternalTriggerDevice: ' . ' Funktion durchlaufen' ); } # Sub für das Zusammensetzen der Rolläden Steuerbefehle sub ShuttersCommandSet($$$) { my ( $hash, $shuttersDev, $posValue ) = @_; my $name = $hash->{NAME}; $shutters->setShuttersDev($shuttersDev); if ( ( $posValue == $shutters->getShadingPos and ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' and ( $shutters->getLockOut eq 'soft' or $shutters->getLockOut eq 'hard' ) and not $shutters->getQueryShuttersPos($posValue) ) ) or ( $posValue != $shutters->getShadingPos and ( ( $shutters->getPartyMode eq 'on' and $ascDev->getPartyMode eq 'on' ) or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' and ( $ascDev->getAutoShuttersControlComfort eq 'off' or $shutters->getComfortOpenPos != $posValue ) and $shutters->getVentilateOpen eq 'on' and $shutters->getShuttersPlace eq 'window' and $shutters->getLockOut ne 'off' ) or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' and $ascDev->getAutoShuttersControlComfort eq 'on' and $shutters->getVentilateOpen eq 'off' and $shutters->getShuttersPlace eq 'window' and $shutters->getLockOut ne 'off' ) or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and ( $shutters->getLockOut eq 'soft' or $shutters->getLockOut eq 'hard' ) and not $shutters->getQueryShuttersPos($posValue) ) or ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getShuttersPlace eq 'terrace' and not $shutters->getQueryShuttersPos($posValue) ) or ( $shutters->getRainProtectionStatus eq 'protected' and $shutters->getWindProtectionStatus eq 'protected' ) ) ) ) { $shutters->setDelayCmd($posValue); $ascDev->setDelayCmdReading; $shutters->setNoDelay(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); $ascDev->setLastPosReading; 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' ); } } ## Sub welche die InternalTimer nach entsprechenden Sunset oder Sunrise zusammen stellt sub CreateSunRiseSetShuttersTimer($$) { my ( $hash, $shuttersDev ) = @_; my $name = $hash->{NAME}; my $shuttersDevHash = $defs{$shuttersDev}; my %funcHash; $shutters->setShuttersDev($shuttersDev); return if ( IsDisabled($name) ); my $shuttersSunriseUnixtime = ShuttersSunrise( $shuttersDev, 'unix' ) + 1; my $shuttersSunsetUnixtime = ShuttersSunset( $shuttersDev, 'unix' ) + 1; $shutters->setSunriseUnixTime($shuttersSunriseUnixtime); $shutters->setSunsetUnixTime($shuttersSunsetUnixtime); ## In jedem Rolladen werden die errechneten Zeiten hinterlegt,es sei denn das autoShuttersControlEvening/Morning auf off steht readingsBeginUpdate($shuttersDevHash); readingsBulkUpdate( $shuttersDevHash, 'ASC_Time_DriveDown', ( $ascDev->getAutoShuttersControlEvening eq 'on' ? ( $shutters->getDown eq 'roommate' ? 'roommate only' : strftime( "%e.%m.%Y - %H:%M", localtime($shuttersSunsetUnixtime) ) ) : 'AutoShuttersControl off' ) ); readingsBulkUpdate( $shuttersDevHash, 'ASC_Time_DriveUp', ( $ascDev->getAutoShuttersControlMorning eq 'on' ? ( $shutters->getUp eq 'roommate' ? 'roommate only' : strftime( "%e.%m.%Y - %H:%M", localtime($shuttersSunriseUnixtime) ) ) : 'AutoShuttersControl off' ) ); readingsEndUpdate( $shuttersDevHash, 0 ); readingsBeginUpdate($hash); readingsBulkUpdateIfChanged( $hash, $shuttersDev . '_nextAstroTimeEvent', ( $shuttersSunriseUnixtime < $shuttersSunsetUnixtime ? strftime( "%e.%m.%Y - %H:%M", localtime($shuttersSunriseUnixtime) ) : strftime( "%e.%m.%Y - %H:%M", localtime($shuttersSunsetUnixtime) ) ) ); readingsEndUpdate( $hash, 1 ); RemoveInternalTimer( $shutters->getInTimerFuncHash ) if ( defined( $shutters->getInTimerFuncHash ) ); ## Setzt den Privacy Modus für die Sichtschutzfahrt auf den Status 0 ## 1 bedeutet das PrivacyDown Timer aktiviert wurde, 2 beudet das er im privacyDown ist ## also das Rollo in privacy Position steht und VOR der endgültigen Nacht oder Tagfahrt $shutters->setPrivacyUpStatus(0) if ( not defined( $shutters->getPrivacyUpStatus ) ); $shutters->setPrivacyDownStatus(0) if ( not defined( $shutters->getPrivacyDownStatus ) ); ## Abfrage für die Sichtschutzfahrt am Morgen vor dem eigentlichen kompletten öffnen if ( $shutters->getPrivacyUpTime > 0 ) { $shuttersSunriseUnixtime = PrivacyUpTime( $shuttersDevHash, $shuttersSunriseUnixtime ); } else { CommandDeleteReading( undef, $shuttersDev . ' ASC_Time_PrivacyDriveUp' ) if ( ReadingsVal( $shuttersDev, 'ASC_Time_PrivacyDriveUp', 'none' ) ); } ## Abfrage für die Sichtschutzfahrt am Abend vor dem eigentlichen kompletten schließen if ( $shutters->getPrivacyDownTime > 0 ) { $shuttersSunsetUnixtime = PrivacyDownTime( $shuttersDevHash, $shuttersSunsetUnixtime ); } else { CommandDeleteReading( undef, $shuttersDev . ' ASC_Time_PrivacyDriveDown' ) if ( ReadingsVal( $shuttersDev, 'ASC_Time_PrivacyDriveDown', 'none' ) ); } ## kleine Hilfe für InternalTimer damit ich alle benötigten Variablen an die Funktion übergeben kann welche von Internal Timer aufgerufen wird. %funcHash = ( hash => $hash, shuttersdevice => $shuttersDev, sunsettime => $shuttersSunsetUnixtime, sunrisetime => $shuttersSunriseUnixtime ); ## Ich brauche beim löschen des InternalTimer den Hash welchen ich mitgegeben habe,dieser muss gesichert werden $shutters->setInTimerFuncHash( \%funcHash ); InternalTimer( $shuttersSunsetUnixtime, 'FHEM::AutoShuttersControl::SunSetShuttersAfterTimerFn', \%funcHash ); InternalTimer( $shuttersSunriseUnixtime, 'FHEM::AutoShuttersControl::SunRiseShuttersAfterTimerFn', \%funcHash ); $ascDev->setStateReading('created new drive timer'); } ## Funktion zum neu setzen der Timer und der Readings für Sunset/Rise sub RenewSunRiseSetShuttersTimer($) { my $hash = shift; foreach ( @{ $hash->{helper}{shuttersList} } ) { my $name = $_; my $dhash = $defs{$name}; $shutters->setShuttersDev($name); RemoveInternalTimer( $shutters->getInTimerFuncHash ); $shutters->setInTimerFuncHash(undef); CreateSunRiseSetShuttersTimer( $hash, $name ); #### Temporär angelegt damit die neue Attributs Parameter Syntax verteilt werden kann #### Gleichlautende Attribute wo lediglich die Parameter geändert werden sollen müssen bereits in der Funktion ShuttersDeviceScan gelöscht werden #### vorher empfiehlt es sich die dort vergebenen Parameter aus zu lesen um sie dann hier wieder neu zu setzen. Dazu wird das shutters Objekt um einen Eintrag #### 'AttrUpdateChanges' erweitert if ( ( int( gettimeofday() ) - $::fhem_started ) < 60 and ReadingsVal( $name, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, 0 ) == 0 ) { $attr{$name}{'ASC_Up'} = $shutters->getAttrUpdateChanges('ASC_Up') if ( $shutters->getAttrUpdateChanges('ASC_Up') ne 'none' ); $attr{$name}{'ASC_Down'} = $shutters->getAttrUpdateChanges('ASC_Down') if ( $shutters->getAttrUpdateChanges('ASC_Down') ne 'none' ); $attr{$name}{'ASC_Self_Defense_Mode'} = $shutters->getAttrUpdateChanges('ASC_Self_Defense_Mode') if ( $shutters->getAttrUpdateChanges('ASC_Self_Defense_Mode') ne 'none' ); $attr{$name}{'ASC_Self_Defense_Mode'} = 'off' if ( $shutters->getAttrUpdateChanges('ASC_Self_Defense_Exclude') eq 'on' ); CommandDeleteReading( undef, $name . ' .ASC_AttrUpdateChanges_.*' ) if ( ReadingsVal( $name, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, 'none' ) eq 'none' ); readingsSingleUpdate( $dhash, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, 1, 0 ); } $attr{$name}{ASC_Drive_Delay} = AttrVal( $name, 'ASC_Drive_Offset', 'none' ) if ( AttrVal( $name, 'ASC_Drive_Offset', 'none' ) ne 'none' ); delFromDevAttrList( $name, 'ASC_Drive_Offset' ); $attr{$name}{ASC_Drive_DelayStart} = AttrVal( $name, 'ASC_Drive_OffsetStart', 'none' ) if ( AttrVal( $name, 'ASC_Drive_OffsetStart', 'none' ) ne 'none' ); delFromDevAttrList( $name, 'ASC_Drive_OffsetStart' ); $attr{$name}{ASC_Shading_StateChange_SunnyCloudy} = AttrVal( $name, 'ASC_Shading_StateChange_Sunny', 'none' ) . ':' . AttrVal( $name, 'ASC_Shading_StateChange_Cloudy', 'none' ) if ( AttrVal( $name, 'ASC_Shading_StateChange_Sunny', 'none' ) ne 'none' and AttrVal( $name, 'ASC_Shading_StateChange_Cloudy', 'none' ) ne 'none' ); delFromDevAttrList( $name, 'ASC_Shading_StateChange_Sunny' ); delFromDevAttrList( $name, 'ASC_Shading_StateChange_Cloudy' ); $attr{$name}{ASC_Shading_InOutAzimuth} = ( AttrVal( $name, 'ASC_Shading_Direction', 180 ) - AttrVal( $name, 'ASC_Shading_Angle_Left', 85 ) ) . ':' . ( AttrVal( $name, 'ASC_Shading_Direction', 180 ) + AttrVal( $name, 'ASC_Shading_Angle_Right', 85 ) ) if ( AttrVal( $name, 'ASC_Shading_Direction', 'none' ) ne 'none' or AttrVal( $name, 'ASC_Shading_Angle_Left', 'none' ) ne 'none' or AttrVal( $name, 'ASC_Shading_Angle_Right', 'none' ) ne 'none' ); delFromDevAttrList( $name, 'ASC_Shading_Direction' ); delFromDevAttrList( $name, 'ASC_Shading_Angle_Left' ); delFromDevAttrList( $name, 'ASC_Shading_Angle_Right' ); $attr{$name}{ASC_PrivacyDownValue_beforeNightClose} = AttrVal( $name, 'ASC_PrivacyDownTime_beforNightClose', 'none' ) if ( AttrVal( $name, 'ASC_PrivacyDownTime_beforNightClose', 'none' ) ne 'none' ); delFromDevAttrList( $name, 'ASC_PrivacyDownTime_beforNightClose' ); delFromDevAttrList( $name, 'ASC_ExternalTriggerDevice' ); } } ## Funktion zum hardwareseitigen setzen des lock-out oder blocking beim Rolladen selbst sub HardewareBlockForShutters($$) { my ( $hash, $cmd ) = @_; foreach ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($_); $shutters->setHardLockOut($cmd); } } ## Funktion für das wiggle aller Shutters zusammen sub wiggleAll($) { my $hash = shift; foreach ( @{ $hash->{helper}{shuttersList} } ) { wiggle( $hash, $_ ); } } sub wiggle($$) { my ( $hash, $shuttersDev ) = @_; $shutters->setShuttersDev($shuttersDev); $shutters->setNoDelay(1); $shutters->setLastDrive('wiggle begin drive'); my %h = ( shuttersDev => $shutters->getShuttersDev, posValue => $shutters->getStatus, lastDrive => 'wiggle end drive', ); if ( $shutters->getShuttersPosCmdValueNegate ) { if ( $shutters->getStatus >= $shutters->getClosedPos / 2 ) { $shutters->setDriveCmd( $shutters->getStatus - $shutters->getWiggleValue ); } else { $shutters->setDriveCmd( $shutters->getStatus + $shutters->getWiggleValue ); } } else { if ( $shutters->getStatus >= $shutters->getOpenPos / 2 ) { $shutters->setDriveCmd( $shutters->getStatus - $shutters->getWiggleValue ); } else { $shutters->setDriveCmd( $shutters->getStatus + $shutters->getWiggleValue ); } } InternalTimer( gettimeofday() + 60, 'FHEM::AutoShuttersControl::_SetCmdFn', \%h ); } #### ## Funktion welche beim Ablaufen des Timers für Sunset aufgerufen werden soll sub SunSetShuttersAfterTimerFn($) { my $funcHash = shift; my $hash = $funcHash->{hash}; my $shuttersDev = $funcHash->{shuttersdevice}; $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); if ( $shutters->getDown ne 'roommate' and $ascDev->getAutoShuttersControlEvening eq 'on' and IsAfterShuttersManualBlocking($shuttersDev) and ( $shutters->getModeDown eq $homemode or ( $shutters->getModeDown eq 'absent' and $homemode eq 'gone' ) or $shutters->getModeDown eq 'always' ) and ( $ascDev->getSelfDefense eq 'off' or $shutters->getSelfDefenseMode eq 'off' or ( $ascDev->getSelfDefense eq 'on' and $ascDev->getResidentsStatus ne 'gone' ) ) and ( $shutters->getDown ne 'brightness' or ( $shutters->getDown eq 'brightness' and not $shutters->getSunset ) ) ) { if ( $shutters->getPrivacyDownStatus == 1 ) { $shutters->setPrivacyDownStatus(2); $shutters->setLastDrive('timer privacy night close'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getPrivacyDownPos ) unless ( $shutters->getQueryShuttersPos( $shutters->getPrivacyDownPos ) ); } else { $shutters->setPrivacyDownStatus(0) if ( $shutters->getPrivacyDownStatus == 2 ); $shutters->setLastDrive('night close'); ShuttersCommandSet( $hash, $shuttersDev, PositionValueWindowRec( $shuttersDev, ( $shutters->getSleepPos > 0 ? $shutters->getSleepPos : $shutters->getClosedPos ) ) ); } } unless ( $shutters->getPrivacyDownStatus == 2 ) { $shutters->setSunrise(0); $shutters->setSunset(1); } CreateSunRiseSetShuttersTimer( $hash, $shuttersDev ); } ## Funktion welche beim Ablaufen des Timers für Sunrise aufgerufen werden soll sub SunRiseShuttersAfterTimerFn($) { my $funcHash = shift; my $hash = $funcHash->{hash}; my $shuttersDev = $funcHash->{shuttersdevice}; $shutters->setShuttersDev($shuttersDev); my $homemode = $shutters->getRoommatesStatus; $homemode = $ascDev->getResidentsStatus if ( $homemode eq 'none' ); if ( $shutters->getUp ne 'roommate' and $ascDev->getAutoShuttersControlMorning eq 'on' and ( $shutters->getModeUp eq $homemode or ( $shutters->getModeUp eq 'absent' and $homemode eq 'gone' ) or $shutters->getModeUp eq 'always' ) and ( $ascDev->getSelfDefense eq 'off' or $shutters->getSelfDefenseMode eq 'off' or ( $ascDev->getSelfDefense eq 'on' and ( $shutters->getSelfDefenseMode eq 'gone' or $shutters->getSelfDefenseMode eq 'absent' ) and $ascDev->getResidentsStatus ne 'gone' ) or ( $ascDev->getSelfDefense eq 'on' and $shutters->getSelfDefenseMode eq 'absent' and $ascDev->getResidentsStatus ne 'absent' ) ) and ( $shutters->getUp ne 'brightness' or ( $shutters->getUp eq 'brightness' and not $shutters->getSunrise ) ) ) { if ( ( $shutters->getRoommatesStatus eq 'home' or $shutters->getRoommatesStatus eq 'awoken' or $shutters->getRoommatesStatus eq 'absent' or $shutters->getRoommatesStatus eq 'gone' or $shutters->getRoommatesStatus eq 'none' ) and ( $ascDev->getSelfDefense eq 'off' or ( $ascDev->getSelfDefense eq 'on' and CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) or ( $ascDev->getSelfDefense eq 'on' and CheckIfShuttersWindowRecOpen($shuttersDev) != 0 and ( $ascDev->getResidentsStatus ne 'absent' and $ascDev->getResidentsStatus ne 'gone' ) ) ) ) { if ( not $shutters->getIfInShading ) { if ( $shutters->getPrivacyUpStatus == 1 ) { $shutters->setPrivacyUpStatus(2); $shutters->setLastDrive('timer privacy day open'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getPrivacyUpPos ) unless ( not $shutters->getQueryShuttersPos( $shutters->getPrivacyUpPos ) ); } else { $shutters->setLastDrive('day open'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getOpenPos ); $shutters->setPrivacyUpStatus(0) if ( $shutters->getPrivacyUpStatus == 2 ); } } elsif ( $shutters->getIfInShading ) { $shutters->setLastDrive('shading in'); ShuttersCommandSet( $hash, $shuttersDev, $shutters->getShadingPos ); $shutters->setPrivacyUpStatus(0) if ( $shutters->getPrivacyUpStatus == 2 ); } } } unless ( $shutters->getPrivacyUpStatus == 2 ) { $shutters->setSunrise(1); $shutters->setSunset(0); } CreateSunRiseSetShuttersTimer( $hash, $shuttersDev ); } sub CreateNewNotifyDev($) { my $hash = shift; my $name = $hash->{NAME}; $hash->{NOTIFYDEV} = "global," . $name; delete $hash->{monitoredDevs}; CommandDeleteReading( undef, $name . ' .monitoredDevs' ); my $shuttersList = ''; foreach ( @{ $hash->{helper}{shuttersList} } ) { AddNotifyDev( $hash, AttrVal( $_, 'ASC_Roommate_Device', 'none' ), $_, 'ASC_Roommate_Device' ) if ( AttrVal( $_, 'ASC_Roommate_Device', 'none' ) ne 'none' ); AddNotifyDev( $hash, AttrVal( $_, 'ASC_WindowRec', 'none' ), $_, 'ASC_WindowRec' ) if ( AttrVal( $_, 'ASC_WindowRec', 'none' ) ne 'none' ); AddNotifyDev( $hash, AttrVal( $_, 'ASC_BrightnessSensor', 'none' ), $_, 'ASC_BrightnessSensor' ) if ( AttrVal( $_, 'ASC_BrightnessSensor', 'none' ) ne 'none' ); AddNotifyDev( $hash, AttrVal( $_, 'ASC_ExternalTrigger', 'none' ), $_, 'ASC_ExternalTrigger' ) if ( AttrVal( $_, 'ASC_ExternalTrigger', 'none' ) ne 'none' ); $shuttersList = $shuttersList . ',' . $_; } 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; } sub ShuttersInformation($@) { my ( $FW_wname, $d, $room, $pageHash ) = @_; my $hash = $defs{$d}; my $ret = '

ASC Configuration and Information Summary

'; $ret .= '
'; $ret .= ''; $ret .= ''; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ''; my $linecount = 1; foreach my $shutter ( @{ $hash->{helper}{shuttersList} } ) { $shutters->setShuttersDev($shutter); if ( $linecount % 2 == 0 ) { $ret .= ''; } else { $ret .= ''; } $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ''; $linecount++; } $ret .= '
Shutters Next DriveUp Next DriveDown ASC Up ASC Down ASC Mode Up ASC Mode Down Partymode Lock-Out Last Drive Position Last Position Shading Info
$shutter " . strftime( "%e.%m.%Y - %H:%M:%S", localtime( $shutters->getSunriseUnixTime ) ) . " " . strftime( "%e.%m.%Y - %H:%M:%S", localtime( $shutters->getSunsetUnixTime ) ) . " " . $shutters->getUp . " " . $shutters->getDown . " " . $shutters->getModeUp . " " . $shutters->getModeDown . " " . $shutters->getPartyMode . " " . $shutters->getLockOut . " " . ReadingsVal( $shutter, 'ASC_ShuttersLastDrive', 'none' ) . " " . $shutters->getStatus . " " . $shutters->getLastPos . " " . $shutters->getShadingStatus . ' - ' . strftime( "%H:%M:%S", localtime( $shutters->getShadingStatusTimestamp ) ) . "


'; return $ret; } sub GetMonitoredDevs($) { my $hash = shift; my $notifydevs = eval { decode_json( ReadingsVal( $hash->{NAME}, '.monitoredDevs', 'none' ) ); }; my $ret = ''; $ret .= '
'; $ret .= ''; $ret .= ''; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ''; if ( ref($notifydevs) eq "HASH" ) { my $linecount = 1; foreach my $notifydev ( sort keys( %{$notifydevs} ) ) { if ( ref( $notifydevs->{$notifydev} ) eq "HASH" ) { foreach my $shutters ( sort keys( %{ $notifydevs->{$notifydev} } ) ) { if ( $linecount % 2 == 0 ) { $ret .= ''; } else { $ret .= ''; } $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ''; $linecount++; } } } } $ret .= '
Shutters/ASC-Device NOTIFYDEV Attribut
$shutters $notifydev $notifydevs->{$notifydev}{$shutters}
'; return $ret; } ################################# ## my little helper ################################# sub PositionValueWindowRec($$) { my ( $shuttersDev, $posValue ) = @_; if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 1 and $shutters->getVentilateOpen eq 'on' ) { $posValue = $shutters->getVentilatePos; } elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and $shutters->getSubTyp eq 'threestate' and $ascDev->getAutoShuttersControlComfort eq 'on' ) { $posValue = $shutters->getComfortOpenPos; } elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 and ( $shutters->getSubTyp eq 'threestate' or $shutters->getSubTyp eq 'twostate' ) and $shutters->getVentilateOpen eq 'on' ) { $posValue = $shutters->getVentilatePos; } if ( $shutters->getQueryShuttersPos($posValue) ) { $posValue = $shutters->getStatus; } return $posValue; } sub AutoSearchTwilightDev($) { my $hash = shift; my $name = $hash->{NAME}; if ( devspec2array('TYPE=(Astro|Twilight)') > 0 ) { CommandAttr( undef, $name . ' ASC_twilightDevice ' . ( devspec2array('TYPE=(Astro|Twilight)') )[0] ) if ( AttrVal( $name, 'ASC_twilightDevice', 'none' ) eq 'none' ); } } 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 ) = @_; my %notifyDevs; while ( my $notifyDev = each %{ $hash->{monitoredDevs} } ) { Log3( $hash->{NAME}, 4, "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - NotifyDev: " . $notifyDev ); Log3( $hash->{NAME}, 5, "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDev: " . $shuttersDev ); if ( defined( $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} ) and $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} eq $shuttersAttr ) { Log3( $hash->{NAME}, 4, "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDevHash: " . $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} ); Log3( $hash->{NAME}, 5, "AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - return ShuttersDev: " . $notifyDev ); $notifyDevs{$notifyDev} = $shuttersDev; } } return \%notifyDevs; } ## Ist Tag oder Nacht für den entsprechende Rolladen sub _IsDay($) { my ($shuttersDev) = @_; $shutters->setShuttersDev($shuttersDev); my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) > ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 ); my $respIsDay = $isday; ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay ); if ( ( $shutters->getModeDown eq 'brightness' or $shutters->getModeUp eq 'brightness' ) or ( ( ( ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) and not IsWe() ) or ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) and IsWe() and $ascDev->getSunriseTimeWeHoliday eq 'on' ) ) 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; } ##### Nach Sonnenuntergang / Abends $respIsDay = ( ( ( $shutters->getBrightness > $brightnessMinVal and $isday and not $shutters->getSunset ) or not $shutters->getSunset ) ? 1 : 0 ) if ( $shutters->getDown eq 'brightness' ); ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' getDownBrightness: ' . $respIsDay . ' Brightness: ' . $shutters->getBrightness . ' BrightnessMin: ' . $brightnessMinVal . ' Sunset: ' . $shutters->getSunset ); ##### Nach Sonnenauf / Morgens $respIsDay = ( ( ( $shutters->getBrightness > $brightnessMaxVal and not $isday and not $shutters->getSunrise ) or $respIsDay or $shutters->getSunrise ) ? 1 : 0 ) if ( $shutters->getUp eq 'brightness' ); ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' getUpBrightness: ' . $respIsDay . ' Brightness: ' . $shutters->getBrightness . ' BrightnessMax: ' . $brightnessMaxVal . ' Sunrise: ' . $shutters->getSunrise ); } return $respIsDay; } sub ShuttersSunrise($$) { my ( $shuttersDev, $tm ) = @_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit my $autoAstroMode; $shutters->setShuttersDev($shuttersDev); if ( $shutters->getAutoAstroModeMorning ne 'none' ) { $autoAstroMode = $shutters->getAutoAstroModeMorning; $autoAstroMode = $autoAstroMode . '=' . $shutters->getAutoAstroModeMorningHorizon if ( $autoAstroMode eq 'HORIZON' ); } else { $autoAstroMode = $ascDev->getAutoAstroModeMorning; $autoAstroMode = $autoAstroMode . '=' . $ascDev->getAutoAstroModeMorningHorizon if ( $autoAstroMode eq 'HORIZON' ); } my $oldFuncHash = $shutters->getInTimerFuncHash; my $shuttersSunriseUnixtime = computeAlignTime( '24:00', sunrise( 'REAL', 0, '4:30', '8:30' ) ); if ( $tm eq 'unix' ) { if ( $shutters->getUp eq 'astro' ) { if ( ( IsWe() or IsWeTomorrow() ) and $ascDev->getSunriseTimeWeHoliday eq 'on' ) { if ( not IsWeTomorrow() ) { if ( IsWe() and 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->getTimeUpWeHoliday ) ) + 1 ); } else { $shuttersSunriseUnixtime = ( computeAlignTime( '24:00', sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpEarly, $shutters->getTimeUpLate ) ) + 1 ); } } else { if ( IsWe() and ( int( gettimeofday() / 86400 ) == int( ( computeAlignTime( '24:00', sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpWeHoliday ) ) + 1 ) / 86400 ) 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 { $shuttersSunriseUnixtime = ( computeAlignTime( '24:00', sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpEarly, $shutters->getTimeUpLate ) ) + 1 ); } if ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' and ( IsWe() or IsWeTomorrow() ) and $ascDev->getSunriseTimeWeHoliday eq 'on' ) { if ( not IsWeTomorrow() ) { if ( int( gettimeofday() / 86400 ) == int( ( computeAlignTime( '24:00', sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpEarly, $shutters->getTimeUpLate ) ) + 1 ) / 86400 ) ) { $shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 ) if ( $shuttersSunriseUnixtime < ( $oldFuncHash->{sunrisetime} + 180 ) and $oldFuncHash->{sunrisetime} < gettimeofday() ); } } } elsif ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' ) { $shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 ) if ( $shuttersSunriseUnixtime < ( $oldFuncHash->{sunrisetime} + 180 ) and $oldFuncHash->{sunrisetime} < gettimeofday() ); } } elsif ( $shutters->getUp eq 'time' ) { if ( ( IsWe() or IsWeTomorrow() ) and $ascDev->getSunriseTimeWeHoliday eq 'on' ) { if ( not IsWeTomorrow() ) { if ( int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ); } elsif ( int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) and $shutters->getSunrise ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpEarly ) + 86400; } else { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpEarly ); } } else { if ( IsWe() and int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ); } elsif ( int( gettimeofday() / 86400 ) == int( computeAlignTime( '24:00', $shutters->getTimeUpEarly ) / 86400 ) ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpEarly ); } elsif ( int( gettimeofday() / 86400 ) != int( computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) / 86400 ) ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ); } else { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpWeHoliday ) + 86400; } } } else { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpEarly ); } } elsif ( $shutters->getUp eq 'brightness' ) { $shuttersSunriseUnixtime = computeAlignTime( '24:00', $shutters->getTimeUpLate ); } return $shuttersSunriseUnixtime; } elsif ( $tm eq 'real' ) { return sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpEarly, $shutters->getTimeUpLate ) if ( $shutters->getUp eq 'astro' ); return $shutters->getTimeUpEarly if ( $shutters->getUp eq 'time' ); } } sub IsAfterShuttersTimeBlocking($) { my ($shuttersDev) = @_; $shutters->setShuttersDev($shuttersDev); if ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < $shutters->getBlockingTimeAfterManual or ( not $shutters->getIsDay and defined( $shutters->getSunriseUnixTime ) and $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) < $shutters->getBlockingTimeBeforDayOpen ) or ( $shutters->getIsDay and defined( $shutters->getSunriseUnixTime ) and $shutters->getSunsetUnixTime - ( int( gettimeofday() ) ) < $shutters->getBlockingTimeBeforNightClose ) ) { return 0; } else { return 1 } } sub IsAfterShuttersManualBlocking($) { my $shuttersDev = shift; $shutters->setShuttersDev($shuttersDev); 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; } else { return 1 } } sub ShuttersSunset($$) { my ( $shuttersDev, $tm ) = @_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit my $autoAstroMode; $shutters->setShuttersDev($shuttersDev); if ( $shutters->getAutoAstroModeEvening ne 'none' ) { $autoAstroMode = $shutters->getAutoAstroModeEvening; $autoAstroMode = $autoAstroMode . '=' . $shutters->getAutoAstroModeEveningHorizon if ( $autoAstroMode eq 'HORIZON' ); } else { $autoAstroMode = $ascDev->getAutoAstroModeEvening; $autoAstroMode = $autoAstroMode . '=' . $ascDev->getAutoAstroModeEveningHorizon if ( $autoAstroMode eq 'HORIZON' ); } my $oldFuncHash = $shutters->getInTimerFuncHash; my $shuttersSunsetUnixtime = computeAlignTime( '24:00', sunset( 'REAL', 0, '15:30', '21:30' ) ); if ( $tm eq 'unix' ) { if ( $shutters->getDown eq 'astro' ) { $shuttersSunsetUnixtime = ( computeAlignTime( '24:00', sunset_abs( $autoAstroMode, 0, $shutters->getTimeDownEarly, $shutters->getTimeDownLate ) ) + 1 ); if ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' ) { $shuttersSunsetUnixtime += 86400 if ( $shuttersSunsetUnixtime < ( $oldFuncHash->{sunsettime} + 180 ) and $oldFuncHash->{sunsettime} < gettimeofday() ); } } elsif ( $shutters->getDown eq 'time' ) { $shuttersSunsetUnixtime = computeAlignTime( '24:00', $shutters->getTimeDownEarly ); } elsif ( $shutters->getDown eq 'brightness' ) { $shuttersSunsetUnixtime = computeAlignTime( '24:00', $shutters->getTimeDownLate ); } return $shuttersSunsetUnixtime; } elsif ( $tm eq 'real' ) { return sunset_abs( $autoAstroMode, 0, $shutters->getTimeDownEarly, $shutters->getTimeDownLate ) if ( $shutters->getDown eq 'astro' ); return $shutters->getTimeDownEarly if ( $shutters->getDown eq 'time' ); } } ## Kontrolliert ob das Fenster von einem bestimmten Rolladen offen ist sub CheckIfShuttersWindowRecOpen($) { my $shuttersDev = shift; $shutters->setShuttersDev($shuttersDev); if ( $shutters->getWinStatus =~ /[Oo]pen|false/ ) # CK: covers: open|opened { return 2; } elsif ( $shutters->getWinStatus =~ /tilt/ and $shutters->getSubTyp eq 'threestate' ) # CK: covers: tilt|tilted { return 1; } elsif ( $shutters->getWinStatus =~ /[Cc]lose|true/ ) { return 0; } # CK: covers: close|closed } sub makeReadingName($) { my ($rname) = @_; my %charHash = ( chr(0xe4) => "ae", # ä chr(0xc4) => "Ae", # Ä chr(0xfc) => "ue", # ü chr(0xdc) => "Ue", # Ü chr(0xf6) => "oe", # ö chr(0xd6) => "Oe", # Ö chr(0xdf) => "ss" # ß ); my $charHashkeys = join( "", keys(%charHash) ); return $rname if ( $rname =~ m/^\./ ); $rname =~ s/([$charHashkeys])/$charHash{$1}/gi; $rname =~ s/[^a-z0-9._\-\/]/_/gi; return $rname; } sub TimeMin2Sec($) { my $min = shift; my $sec; $sec = $min * 60; return $sec; } sub IsWe() { my $we = main::IsWe(); return $we; } sub IsWeTomorrow() { my $we = main::IsWe('tomorrow'); return $we; } sub _SetCmdFn($) { my $h = shift; my $shuttersDev = $h->{shuttersDev}; my $posValue = $h->{posValue}; $shutters->setShuttersDev($shuttersDev); $shutters->setLastDrive( $h->{lastDrive} ) if ( defined( $h->{lastDrive} ) ); my $idleDetectionValue = $shutters->getIdleDetectionValue; my $idleDetection = $shutters->getIdleDetection; return unless ( $shutters->getASCenable eq 'on' and $ascDev->getASCenable eq 'on' and ( $idleDetection =~ /^$idleDetectionValue$/ or $idleDetection eq 'none' ) ); if ( $shutters->getStatus != $posValue ) { $shutters->setLastPos( $shutters->getStatus ); } 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 . ' - Rollo wird gefahren, aktuelle Position: ' . $shutters->getStatus . ', Zielposition: ' . $posValue . '. Grund der Fahrt: ' . $shutters->getLastDrive ); CommandSet( undef, $shuttersDev . ':FILTER=' . $shutters->getPosCmd . '!=' . $posValue . ' ' . $shutters->getPosSetCmd . ' ' . $posValue ); $shutters->setSelfDefenseAbsent( 0, 0 ) if ( not $shutters->getSelfDefenseAbsent and $shutters->getSelfDefenseAbsentTimerrun ); } sub _setShuttersLastDriveDelayed($) { my $h = shift; my $shuttersDevHash = $h->{devHash}; my $lastDrive = $h->{lastDrive}; readingsSingleUpdate( $shuttersDevHash, 'ASC_ShuttersLastDrive', $lastDrive, 1 ); } sub ASC_Debug($) { return unless ( AttrVal( $ascDev->getName, 'ASC_debug', 0 ) ); my $debugMsg = shift; my $debugTimestamp = strftime( "%Y.%m.%e %T", localtime(time) ); print( encode_utf8( "\n" . 'ASC_DEBUG!!! ' . $debugTimestamp . ' - ' . $debugMsg . "\n" ) ); } sub _averageBrightness(@) { my @input = @_; use List::Util qw(sum); return int( sum(@input) / @input ); } sub _perlCodeCheck($) { my $exec = shift; my $val = undef; if ( $exec =~ /^\{(.+)\}$/ ) { $val = main::AnalyzePerlCommand( undef, $1 ); } return $val; } sub PrivacyUpTime($$) { my ( $shuttersDevHash, $shuttersSunriseUnixtime ) = @_; my $privacyUpUnixtime; if ( ( $shuttersSunriseUnixtime - $shutters->getPrivacyUpTime ) > ( gettimeofday() + 1 ) or $shutters->getPrivacyUpStatus == 2 ) { $privacyUpUnixtime = $shuttersSunriseUnixtime - $shutters->getPrivacyUpTime; $privacyUpUnixtime += 86400 if ( $shutters->getPrivacyUpStatus == 2 ); readingsSingleUpdate( $shuttersDevHash, 'ASC_Time_PrivacyDriveUp', strftime( "%e.%m.%Y - %H:%M", localtime($privacyUpUnixtime) ), 1 ); ## Setzt den PrivacyUp Modus für die Sichtschutzfahrt auf den Status 1 ## und gibt die Unixtime für die nächste Fahrt korrekt zurück unless ( $shutters->getPrivacyUpStatus == 2 ) { $shutters->setPrivacyUpStatus(1); $shuttersSunriseUnixtime = $privacyUpUnixtime; } } else { readingsSingleUpdate( $shuttersDevHash, 'ASC_Time_PrivacyDriveUp', strftime( "%e.%m.%Y - %H:%M", localtime( ( $shuttersSunriseUnixtime - $shutters->getPrivacyUpTime ) + 86400 ) ), 1 ); } return $shuttersSunriseUnixtime; } sub PrivacyDownTime($$) { my ( $shuttersDevHash, $shuttersSunsetUnixtime ) = @_; my $privacyDownUnixtime; if ( ( $shuttersSunsetUnixtime - $shutters->getPrivacyDownTime ) > ( gettimeofday() + 1 ) or $shutters->getPrivacyDownStatus == 2 ) { $privacyDownUnixtime = $shuttersSunsetUnixtime - $shutters->getPrivacyDownTime; $privacyDownUnixtime += 86400 if ( $shutters->getPrivacyDownStatus == 2 ); readingsSingleUpdate( $shuttersDevHash, 'ASC_Time_PrivacyDriveDown', strftime( "%e.%m.%Y - %H:%M", localtime($privacyDownUnixtime) ), 1 ); ## Setzt den PrivacyDown Modus für die Sichtschutzfahrt auf den Status 1 ## und gibt die Unixtime für die nächste Fahrt korrekt zurück unless ( $shutters->getPrivacyDownStatus == 2 ) { $shutters->setPrivacyDownStatus(1); $shuttersSunsetUnixtime = $privacyDownUnixtime; } } else { readingsSingleUpdate( $shuttersDevHash, 'ASC_Time_PrivacyDriveDown', strftime( "%e.%m.%Y - %H:%M", localtime( ( $shuttersSunsetUnixtime - $shutters->getPrivacyDownTime ) + 86400 ) ), 1 ); } return $shuttersSunsetUnixtime; } sub _IsAdv { my ( undef, undef, undef, $monthday, $month, $year, undef, undef, undef ) = localtime( gettimeofday() ); my $adv = 0; $year += 1900; if ( $month < 1 ) { if ( $monthday < 7 ) { $adv = 1; } } else { my $time = HTTP::Date::str2time( $year . '-12-25' ); my $wday = ( localtime($time) )[6]; $wday = $wday ? $wday : 7; $time -= ( $wday + 21 ) * 86400; $adv = 1 if ( $time < time ); } return $adv; } sub DevStateIcon($) { my ($hash) = @_; $hash = $defs{$hash} if ( ref($hash) ne 'HASH' ); return undef if ( !$hash ); my $name = $hash->{NAME}; if ( ReadingsVal( $name, 'state', undef ) eq 'created new drive timer' ) { return '.*:clock'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'selfDefense terrace' ) { return '.*:fts_door_tilt'; } elsif ( ReadingsVal( $name, 'state', undef ) =~ /.*asleep$/ ) { return '.*:scene_sleeping'; } elsif ( ReadingsVal( $name, 'state', undef ) =~ /^roommate(.come)?.(awoken|home)$/ ) { return '.*:user_available'; } elsif ( ReadingsVal( $name, 'state', undef ) =~ /^residents.(home|awoken)$/ ) { return '.*:status_available'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'manual' ) { return '.*:fts_shutter_manual'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'selfDefense inactive' ) { return '.*:status_open'; } elsif ( ReadingsVal( $name, 'state', undef ) =~ /^selfDefense.*.active$/ ) { return '.*:status_locked'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'day open' ) { return '.*:scene_day'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'night close' ) { return '.*:scene_night'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'shading in' ) { return '.*:fts_shutter_shadding_run'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'shading out' ) { return '.*:fts_shutter_shadding_stop'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'active' ) { return '.*:hourglass'; } elsif ( ReadingsVal( $name, 'state', undef ) =~ /.*privacy.*/ ) { return '.*:fts_shutter_50'; } elsif ( ReadingsVal( $name, 'state', undef ) eq 'adv delay close' ) { return '.*:christmas_tree'; } return undef; } ###################################### ###################################### ########## 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); use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( defs ReadingsVal readingsSingleUpdate gettimeofday InternalTimer CommandSet Log3) ); } sub new { my $class = shift; my $self = { shuttersDev => undef, defaultarg => undef, roommate => undef, }; bless $self, $class; return $self; } sub setShuttersDev { my ( $self, $shuttersDev ) = @_; $self->{shuttersDev} = $shuttersDev if ( defined($shuttersDev) ); return $self->{shuttersDev}; } sub getShuttersDev { my $self = shift; return $self->{shuttersDev}; } sub setAttrUpdateChanges { my ( $self, $attr, $value ) = @_; $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} = $value; return 0; } sub setHardLockOut { my ( $self, $cmd ) = @_; if ( $shutters->getLockOut eq 'hard' and $shutters->getLockOutCmd ne 'none' ) { CommandSet( undef, $self->{shuttersDev} . ' inhibit ' . $cmd ) if ( $shutters->getLockOutCmd eq 'inhibit' ); CommandSet( undef, $self->{shuttersDev} . ' ' . ( $cmd eq 'on' ? 'blocked' : 'unblocked' ) ) if ( $shutters->getLockOutCmd eq 'blocked' ); CommandSet( undef, $self->{shuttersDev} . ' ' . ( $cmd eq 'on' ? 'protectionOn' : 'protectionOff' ) ) if ( $shutters->getLockOutCmd eq 'protected' ); } return 0; } sub setNoDelay { my ( $self, $noDelay ) = @_; $self->{ $self->{shuttersDev} }{noDelay} = $noDelay; return 0; } sub setSelfDefenseAbsent { my ( $self, $timerrun, $active, $timerhash ) = @_; $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun} = $timerrun; $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active} = $active; $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} = $timerhash if ( defined($timerhash) ); return 0; } sub setDriveCmd { my ( $self, $posValue ) = @_; my $offSet; my $offSetStart; if ( ( $shutters->getPartyMode eq 'on' and $ascDev->getPartyMode eq 'on' ) or ( $shutters->getAdv and not $shutters->getQueryShuttersPos($posValue) and not $shutters->getAdvDelay and not $shutters->getExternalTriggerState and not $shutters->getSelfDefenseState ) ) { $shutters->setDelayCmd($posValue); $ascDev->setDelayCmdReading; $shutters->setNoDelay(0); $shutters->setExternalTriggerState(0) if ( $shutters->getExternalTriggerState ); FHEM::AutoShuttersControl::ASC_Debug( 'setDriveCmd: ' . $shutters->getShuttersDev . ' - Die Fahrt wird zurückgestellt. Grund kann ein geöffnetes Fenster sein oder ein aktivierter Party Modus oder Weihnachtszeit' ); } else { $shutters->setAdvDelay(0) if ( $shutters->getAdvDelay ); $shutters->setDelayCmd('none') if ( $shutters->getDelayCmd ne 'none' ) ; # setzt den Wert auf none da der Rolladen nun gesteuert werden kann. $shutters->setExternalTriggerState(0) if ( $shutters->getExternalTriggerState ); ### antifreeze Routine if ( $shutters->getFreezeStatus > 0 ) { if ( $shutters->getFreezeStatus != 1 ) { $posValue = $shutters->getStatus; $shutters->setLastDrive('no drive - antifreeze defense'); $shutters->setLastDriveReading; $ascDev->setStateReading; } elsif ( $posValue == $shutters->getClosedPos ) { $posValue = $shutters->getAntiFreezePos; $shutters->setLastDrive( $shutters->getLastDrive . ' - antifreeze mode' ); } } my %h = ( shuttersDev => $self->{shuttersDev}, posValue => $posValue, ); $offSet = $shutters->getDelay if ( $shutters->getDelay > -1 ); $offSet = $ascDev->getShuttersOffset if ( $shutters->getDelay < 0 ); $offSetStart = $shutters->getDelayStart; if ( $shutters->getSelfDefenseAbsent and not $shutters->getSelfDefenseAbsentTimerrun and $shutters->getSelfDefenseMode ne 'off' and $shutters->getSelfDefenseState and $ascDev->getSelfDefense eq 'on' ) { InternalTimer( gettimeofday() + $shutters->getSelfDefenseAbsentDelay, 'FHEM::AutoShuttersControl::_SetCmdFn', \%h ); $shutters->setSelfDefenseAbsent( 1, 0, \%h ); } elsif ( $offSetStart > 0 and not $shutters->getNoDelay ) { InternalTimer( gettimeofday() + int( rand($offSet) + $shutters->getDelayStart ), 'FHEM::AutoShuttersControl::_SetCmdFn', \%h ); FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' . $shutters->getShuttersDev . ' - versetztes fahren' ); } elsif ( $offSetStart < 1 or $shutters->getNoDelay ) { FHEM::AutoShuttersControl::_SetCmdFn( \%h ); FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' . $shutters->getShuttersDev . ' - NICHT versetztes fahren' ); } FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' . $shutters->getShuttersDev . ' - NoDelay: ' . ( $shutters->getNoDelay ? 'JA' : 'NEIN' ) ); $shutters->setNoDelay(0); return 0; } } sub setSunsetUnixTime { my ( $self, $unixtime ) = @_; $self->{ $self->{shuttersDev} }{sunsettime} = $unixtime; return 0; } sub setSunset { my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }{sunset} = $value; return 0; } sub setSunriseUnixTime { my ( $self, $unixtime ) = @_; $self->{ $self->{shuttersDev} }{sunrisetime} = $unixtime; return 0; } sub setSunrise { my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }{sunrise} = $value; return 0; } sub setDelayCmd { my ( $self, $posValue ) = @_; $self->{ $self->{shuttersDev} }{delayCmd} = $posValue; return 0; } sub setLastDrive { my ( $self, $lastDrive ) = @_; $self->{ $self->{shuttersDev} }{lastDrive} = $lastDrive; return 0; } sub setPosSetCmd { my ( $self, $posSetCmd ) = @_; $self->{ $self->{shuttersDev} }{posSetCmd} = $posSetCmd; return 0; } sub setLastDriveReading { my $self = shift; my $shuttersDevHash = $defs{ $self->{shuttersDev} }; my %h = ( devHash => $shuttersDevHash, lastDrive => $shutters->getLastDrive, ); InternalTimer( gettimeofday() + 0.1, 'FHEM::AutoShuttersControl::_setShuttersLastDriveDelayed', \%h ); return 0; } sub setLastPos { # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde my ( $self, $position ) = @_; $self->{ $self->{shuttersDev} }{lastPos}{VAL} = $position if ( defined($position) ); $self->{ $self->{shuttersDev} }{lastPos}{TIME} = int( gettimeofday() ) if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) ); return 0; } sub setLastManPos { my ( $self, $position ) = @_; $self->{ $self->{shuttersDev} }{lastManPos}{VAL} = $position if ( defined($position) ); $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( gettimeofday() ) if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) and defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( gettimeofday() ) - 86400 if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) and not defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); return 0; } sub setDefault { my ( $self, $defaultarg ) = @_; $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); return $self->{defaultarg}; } sub setRoommate { my ( $self, $roommate ) = @_; $self->{roommate} = $roommate if ( defined($roommate) ); return $self->{roommate}; } sub setInTimerFuncHash { my ( $self, $inTimerFuncHash ) = @_; $self->{ $self->{shuttersDev} }{inTimerFuncHash} = $inTimerFuncHash if ( defined($inTimerFuncHash) ); return 0; } sub setPrivacyDownStatus { my ( $self, $statusValue ) = @_; $self->{ $self->{shuttersDev} }->{privacyDownStatus} = $statusValue; return 0; } sub setPrivacyUpStatus { my ( $self, $statusValue ) = @_; $self->{ $self->{shuttersDev} }->{privacyUpStatus} = $statusValue; return 0; } sub setSelfDefenseState { my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }{selfDefenseState} = $value; return 0; } sub setAdvDelay { my ( $self, $advDelay ) = @_; $self->{ $self->{shuttersDev} }->{AdvDelay} = $advDelay; return 0; } sub getAdvDelay { my $self = shift; return ( defined( $self->{ $self->{shuttersDev} }->{AdvDelay} ) ? $self->{ $self->{shuttersDev} }->{AdvDelay} : 0 ); } sub getPrivacyDownStatus { my $self = shift; return ( defined( $self->{ $self->{shuttersDev} }->{privacyDownStatus} ) ? $self->{ $self->{shuttersDev} }->{privacyDownStatus} : undef ); } sub getPrivacyUpStatus { my $self = shift; return ( defined( $self->{ $self->{shuttersDev} }->{privacyUpStatus} ) ? $self->{ $self->{shuttersDev} }->{privacyUpStatus} : undef ); } sub getAttrUpdateChanges { my ( $self, $attr ) = @_; return $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} if ( defined( $self->{ $self->{shuttersDev} }{AttrUpdateChanges} ) and defined( $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} ) ); } sub getIsDay { my $self = shift; return FHEM::AutoShuttersControl::_IsDay( $self->{shuttersDev} ); } sub getFreezeStatus { use POSIX qw(strftime); my $self = shift; my $daytime = strftime( "%P", localtime() ); $daytime = ( defined($daytime) and $daytime ? $daytime : ( strftime( "%k", localtime() ) < 12 ? 'pm' : 'am' ) ); my $outTemp = $ascDev->getOutTemp; $outTemp = $shutters->getOutTemp if ( $shutters->getOutTemp != -100 ); if ( $shutters->getAntiFreeze ne 'off' and $outTemp <= $ascDev->getFreezeTemp ) { if ( $shutters->getAntiFreeze eq 'soft' ) { return 1; } elsif ( $shutters->getAntiFreeze eq $daytime ) { return 2; } elsif ( $shutters->getAntiFreeze eq 'hard' ) { return 3; } } else { return 0; } } sub getShuttersPosCmdValueNegate { my $self = shift; return ( $shutters->getOpenPos < $shutters->getClosedPos ? 1 : 0 ); } sub getQueryShuttersPos { # Es wird geschaut ob die aktuelle Position des Rollos unterhalb der Zielposition ist my ( $self, $posValue ) = @_; # wenn dem so ist wird 1 zurück gegeben ansonsten 0 return ( $shutters->getShuttersPosCmdValueNegate ? $shutters->getStatus > $posValue : $shutters->getStatus < $posValue ); } sub getPosSetCmd { my $self = shift; return ( defined( $self->{ $self->{shuttersDev} }{posSetCmd} ) ? $self->{ $self->{shuttersDev} }{posSetCmd} : $shutters->getPosCmd ); } sub getNoDelay { my $self = shift; return $self->{ $self->{shuttersDev} }{noDelay}; } sub getSelfDefenseState { my $self = shift; return $self->{ $self->{shuttersDev} }{selfDefenseState} if ( defined( $self->{ $self->{shuttersDev} }{selfDefenseState} ) ); } sub getSelfDefenseAbsent { my $self = shift; return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active}; } sub getSelfDefenseAbsentTimerrun { my $self = shift; return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun}; } sub getSelfDefenseAbsentTimerhash { my $self = shift; return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} if ( defined( $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} ) ); } sub getLastDrive { my $self = shift; $self->{ $self->{shuttersDev} }{lastDrive} = ReadingsVal( $self->{shuttersDev}, 'ASC_ShuttersLastDrive', 'none' ) if ( not defined( $self->{ $self->{shuttersDev} }{lastDrive} ) ); return $self->{ $self->{shuttersDev} }{lastDrive}; } sub getLastPos { # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde my $self = shift; return $self->{ $self->{shuttersDev} }{lastPos}{VAL} if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) and defined( $self->{ $self->{shuttersDev} }{lastPos}{VAL} ) ); } sub getLastPosTimestamp { my $self = shift; return $self->{ $self->{shuttersDev} }{lastPos}{TIME} if ( defined( $self->{ $self->{shuttersDev} } ) and defined( $self->{ $self->{shuttersDev} }{lastPos} ) and defined( $self->{ $self->{shuttersDev} }{lastPos}{TIME} ) ); } sub getLastManPos { # letzte ermittelte Position bevor die Position des Rolladen manuell (nicht über ASC) geändert wurde my $self = shift; return $self->{ $self->{shuttersDev} }{lastManPos}{VAL} if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) and defined( $self->{ $self->{shuttersDev} }{lastManPos}{VAL} ) ); } sub getLastManPosTimestamp { my $self = shift; return $self->{ $self->{shuttersDev} }{lastManPos}{TIME} if ( defined( $self->{ $self->{shuttersDev} } ) and defined( $self->{ $self->{shuttersDev} }{lastManPos} ) and defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); } sub getInTimerFuncHash { my $self = shift; return $self->{ $self->{shuttersDev} }{inTimerFuncHash}; } sub getSunsetUnixTime { my $self = shift; 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; my @roState; my %statePrio = ( 'asleep' => 1, 'gotosleep' => 2, 'awoken' => 3, 'home' => 4, 'absent' => 5, 'gone' => 6, 'none' => 7 ); my $minPrio = 10; foreach my $ro ( split( ",", $shutters->getRoommates ) ) { $shutters->setRoommate($ro); my $currentPrio = $statePrio{ $shutters->_getRoommateStatus }; $minPrio = $currentPrio if ( $minPrio > $currentPrio ); } my %revStatePrio = reverse %statePrio; return $revStatePrio{$minPrio}; } sub getRoommatesLastStatus { my $self = shift; my $loop = 0; my @roState; my %statePrio = ( 'asleep' => 1, 'gotosleep' => 2, 'awoken' => 3, 'home' => 6, 'absent' => 5, 'gone' => 4, 'none' => 7 ); my $minPrio = 10; foreach my $ro ( split( ",", $shutters->getRoommates ) ) { $shutters->setRoommate($ro); my $currentPrio = $statePrio{ $shutters->_getRoommateLastStatus }; $minPrio = $currentPrio if ( $minPrio > $currentPrio ); } my %revStatePrio = reverse %statePrio; return $revStatePrio{$minPrio}; } sub getOutTemp { my $self = shift; return ReadingsVal( $shutters->_getTempSensor, $shutters->getTempSensorReading, -100 ); } sub getIdleDetection { my $self = shift; return ReadingsVal( $self->{shuttersDev}, $shutters->_getIdleDetectionReading, 'none' ); } ### Begin Beschattung Objekt mit Daten befüllen sub setShadingStatus { my ( $self, $value ) = @_; ### Werte für value = in, out, in reserved, out reserved $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value if ( defined($value) ); $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = int( gettimeofday() ) if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) ); return 0; } sub setShadingLastStatus { my ( $self, $value ) = @_; ### Werte für value = in, out $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} = $value if ( defined($value) ); $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} = int( gettimeofday() ) if ( defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) ); $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = 0 if ( $value eq 'out' ); return 0; } sub setShadingManualDriveStatus { my ( $self, $value ) = @_; ### Werte für value = in, out $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = $value if ( defined($value) ); return 0; } sub setWindProtectionStatus { # Werte protected, unprotected my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value if ( defined($value) ); return 0; } sub setRainProtectionStatus { # Werte protected, unprotected my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} = $value if ( defined($value) ); return 0; } sub setExternalTriggerState { my ( $self, $value ) = @_; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} = $value if ( defined($value) ); return 0; } sub setPushBrightnessInArray { my ( $self, $value ) = @_; unshift( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} }, $value ); pop( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) if ( scalar( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) > 3 ); } sub getBrightnessAverage { my $self = shift; return &FHEM::AutoShuttersControl::_averageBrightness( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) if ( ref( $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} ) eq 'ARRAY' and scalar( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) > 0 ); } sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved my $self = shift; return $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) ); } sub getShadingLastStatus { # Werte für value = in, out my $self = shift; return $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} if ( defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) ); } sub getShadingManualDriveStatus { # Werte für value = in, out my $self = shift; return ( defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus} ) and defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} ) ? $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} : 0 ); } sub getIfInShading { my $self = shift; return ( ( $shutters->getShadingMode ne 'off' and $shutters->getShadingLastStatus eq 'out' ) ? 1 : 0 ); } sub getWindProtectionStatus { # Werte protected, unprotected my $self = shift; return ( ( defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} ) and defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} ) ) ? $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} : 'unprotected' ); } sub getRainProtectionStatus { # Werte protected, unprotected my $self = shift; return ( ( defined( $self->{ $self->{shuttersDev} }->{RainProtection} ) and defined( $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} ) ) ? $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} : 'unprotected' ); } sub getShadingStatusTimestamp { my $self = shift; return $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} if ( defined( $self->{ $self->{shuttersDev} } ) and defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) ); } sub getShadingLastStatusTimestamp { my $self = shift; return $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} if ( defined( $self->{ $self->{shuttersDev} } ) and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} ) ); } ### Ende Beschattung ## Subklasse Attr von ASC_Shutters## package ASC_Shutters::Attr; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( AttrVal gettimeofday) ); } sub getAntiFreezePos { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze_Pos', $userAttrList{ 'ASC_Antifreeze_Pos:5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100' }[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : $userAttrList{ 'ASC_Antifreeze_Pos:5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100' }[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getShuttersPlace { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_ShuttersPlace', 'window' ); } sub getPrivacyUpTime { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{uptime} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{LASTGETTIME} = int( gettimeofday() ); my ( $upTime, $upBrightnessVal ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_PrivacyUpValue_beforeDayOpen', '-1:-1' ); ## Erwartetes Ergebnis # upTime:upBrightnessVal $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{uptime} = $upTime; $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{upbrightnessval} = ( $upBrightnessVal ne 'none' ? $upBrightnessVal : -1 ); $shutters->setPrivacyUpStatus(0) if ( defined( $shutters->getPrivacyUpStatus ) and $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{uptime} == -1 ); return $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{uptime}; } sub getPrivacyUpBrightnessVal { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{upbrightnessval} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{LASTGETTIME} ) < 2 ); $shutters->getPrivacyUpTime; return ( defined( $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{upbrightnessval} ) ? $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} ->{upbrightnessval} : -1 ); } sub getPrivacyDownTime { my $self = shift; return $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downtime} if ( exists( $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_PrivacyDownValue_beforeNightClose} ->{LASTGETTIME} = int( gettimeofday() ); my ( $downTime, $downBrightnessVal ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_PrivacyDownValue_beforeNightClose', '-1:-1' ); ## Erwartetes Ergebnis # downTime:downBrightnessVal $self->{ $self->{shuttersDev} }->{ASC_PrivacyDownValue_beforeNightClose} ->{downtime} = $downTime; $self->{ $self->{shuttersDev} }->{ASC_PrivacyDownValue_beforeNightClose} ->{downbrightnessval} = ( $downBrightnessVal ne 'none' ? $downBrightnessVal : -1 ); $shutters->setPrivacyDownStatus(0) if ( defined( $shutters->getPrivacyDownStatus ) and $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downtime} == -1 ); return $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downtime}; } sub getPrivacyDownBrightnessVal { my $self = shift; return $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downbrightnessval} if ( exists( $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) < 2 ); $shutters->getPrivacyDownTime; return ( defined( $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downbrightnessval} ) ? $self->{ $self->{shuttersDev} } ->{ASC_PrivacyDownValue_beforeNightClose}->{downbrightnessval} : -1 ); } sub getPrivacyUpPos { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_PrivacyUp_Pos', 50 ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : 50 ); } sub getPrivacyDownPos { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_PrivacyDown_Pos', 50 ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : 50 ); } sub getSelfDefenseMode { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Self_Defense_Mode', 'gone' ); } sub getSelfDefenseAbsentDelay { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Self_Defense_AbsentDelay', 300 ); } sub getWiggleValue { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_WiggleValue', 5 ); } sub getAdv { my $self = shift; return ( AttrVal( $self->{shuttersDev}, 'ASC_Adv', 'off' ) eq 'on' ? ( FHEM::AutoShuttersControl::_IsAdv == 1 ? 1 : 0 ) : 0 ); } ### Begin Beschattung sub getShadingPos { my $self = shift; my $val = 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 ) ] ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : $userAttrList{'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100'} [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getShadingMode { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Mode', 'off' ); } sub _getTempSensor { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} = int( gettimeofday() ); my ( $device, $reading ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_TempSensor', 'none' ); ### erwartetes Ergebnis # DEVICE:READING $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device} = $device; $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} = ( $reading ne 'none' ? $reading : 'temperature' ); return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device}; } sub getTempSensorReading { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) < 2 ); $shutters->_getTempSensor; return ( defined( $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} ) ? $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} : 'temperature' ); } sub _getIdleDetectionReading { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{reading} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{LASTGETTIME} = int( gettimeofday() ); my ( $reading, $value ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_Shutter_IdleDetection', 'none' ); ### erwartetes Ergebnis # READING:VALUE $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{reading} = $reading; $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{value} = $value; return $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{reading}; } sub getIdleDetectionValue { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{value} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{LASTGETTIME} ) < 2 ); $shutters->_getIdleDetectionReading; return ( defined( $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} ->{value} ) ? $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{value} : 'none' ); } sub _getBrightnessSensor { my $self = shift; 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 $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; 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 getShadingAzimuthLeft { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{leftVal} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{LASTGETTIME} ) < 2 ); $shutters->getShadingAzimuthRight; return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{leftVal}; } sub getShadingAzimuthRight { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{rightVal} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth}->{LASTGETTIME} = int( gettimeofday() ); my ( $left, $right ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_Shading_InOutAzimuth', '95:265' ); ### erwartetes Ergebnis # MIN:MAX $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth}->{leftVal} = $left; $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth}->{rightVal} = $right; return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} ->{rightVal}; } sub getShadingMinOutsideTemperature { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_OutsideTemperature', 18 ); } sub getShadingMinElevation { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{minVal} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{LASTGETTIME} = int( gettimeofday() ); my ( $min, $max ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_Shading_MinMax_Elevation', '25.0:100.0' ); ### erwartetes Ergebnis # MIN:MAX $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}->{minVal} = $min; $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}->{maxVal} = ( $max ne 'none' ? $max : 100 ); return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{minVal}; } sub getShadingMaxElevation { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{maxVal} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{LASTGETTIME} ) < 2 ); $shutters->getShadingMinElevation; return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} ->{maxVal}; } sub getShadingStateChangeSunny { my $self = shift; return $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{sunny} if ( exists( $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} ->{LASTGETTIME} = int( gettimeofday() ); my ( $sunny, $cloudy ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_Shading_StateChange_SunnyCloudy', '35000:20000' ); ### erwartetes Ergebnis # SUNNY:CLOUDY $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} ->{sunny} = $sunny; $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} ->{cloudy} = $cloudy; return $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{sunny}; } sub getShadingStateChangeCloudy { my $self = shift; return $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{cloudy} if ( exists( $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 ); $shutters->getShadingStateChangeSunny; return $self->{ $self->{shuttersDev} } ->{ASC_Shading_StateChange_SunnyCloudy}->{cloudy}; } sub getShadingWaitingPeriod { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Shading_WaitingPeriod', 1200 ); } ### Ende Beschattung sub getExternalTriggerDevice { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{device} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{LASTGETTIME} = int( gettimeofday() ); my ( $device, $reading, $valueActive, $valueInactive, $posActive, $posInactive ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_ExternalTrigger', 'none' ); ### erwartetes Ergebnis # DEVICE:READING VALUEACTIVE:VALUEINACTIVE POSACTIVE:POSINACTIVE $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{device} = $device; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{reading} = $reading; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{valueactive} = $valueActive; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{valueinactive} = $valueInactive; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive} = $posActive; $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posinactive} = ( $posInactive ne 'none' ? $posInactive : $shutters->getLastPos ); return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{device}; } sub getExternalTriggerReading { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{reading} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $shutters->getExternalTriggerDevice; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{reading}; } sub getExternalTriggerValueActive { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{valueactive} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $shutters->getExternalTriggerDevice; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{valueactive}; } sub getExternalTriggerValueInactive { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{valueinactive} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $shutters->getExternalTriggerDevice; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{valueinactive}; } sub getExternalTriggerPosActive { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $shutters->getExternalTriggerDevice; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive}; } sub getExternalTriggerPosInactive { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posinactive} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{LASTGETTIME} ) < 2 ); $shutters->getExternalTriggerDevice; return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} ->{posinactive}; } sub getExternalTriggerState { my $self = shift; return ( ( defined( $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} ) and $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} ) ? 1 : 0 ); } sub getDelay { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_Delay', -1 ); return ( $val =~ /^\d+$/ ? $val : -1 ); } sub getDelayStart { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_DelayStart', -1 ); return ( ( $val > 0 and $val =~ /^\d+$/ ) ? $val : -1 ); } sub getBlockingTimeAfterManual { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_afterManual', 1200 ); } sub getBlockingTimeBeforNightClose { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforNightClose', 3600 ); } sub getBlockingTimeBeforDayOpen { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforDayOpen', 3600 ); } sub getPosCmd { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Pos_Reading', 'pct' ); } sub getOpenPos { my $self = shift; 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; my $val = 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 ) ] ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : $userAttrList{'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100'} [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getVentilatePosAfterDayClosed { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_PosAfterDayClosed', 'open' ); } sub getClosedPos { my $self = shift; 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 getSleepPos { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Sleep_Pos', -1 ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : -1 ); } sub getVentilateOpen { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', 'on' ); } sub getComfortOpenPos { my $self = shift; my $val = 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 ) ] ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^\d+(\.\d+)?$/ ? $val : $userAttrList{'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100'} [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ); } sub getPartyMode { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Partymode', 'off' ); } sub getRoommates { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Device', 'none' ); } sub getRoommatesReading { my $self = shift; 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 ne 'none' ? $max - $hyst : $max - 20 ); $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 getWindProtection { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_WindProtection', 'on' ); } sub getRainProtection { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_RainProtection', 'on' ); } sub getModeUp { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Up', 'always' ); } sub getModeDown { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Down', 'always' ); } sub getLockOut { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_LockOut', 'off' ); } sub getLockOutCmd { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_LockOut_Cmd', 'none' ); } sub getAntiFreeze { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze', 'off' ); } sub getAutoAstroModeMorning { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', 'none' ); } sub getAutoAstroModeEvening { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', 'none' ); } sub getAutoAstroModeMorningHorizon { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorningHorizon', 'none' ); } sub getAutoAstroModeEveningHorizon { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon', 'none' ); } sub getUp { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Up', 'astro' ); } sub getDown { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_Down', 'astro' ); } sub getTimeUpEarly { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Early', '05:00' ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$/ ? $val : '05:00' ); } sub getTimeUpLate { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Late', '08:30' ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$/ ? $val : '08:30' ); } sub getTimeDownEarly { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Early', '16:00' ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$/ ? $val : '16:00' ); } sub getTimeDownLate { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Late', '22:00' ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$/ ? $val : '22:00' ); } sub getTimeUpWeHoliday { my $self = shift; my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', '08:00' ); if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); } return ( $val =~ /^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$/ ? $val : '08:00' ); } sub getBrightnessMinVal { my $self = shift; 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 $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 ## package ASC_Shutters::Readings; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( ReadingsVal ReadingsNum) ); } sub getBrightness { my $self = shift; return ReadingsNum( $shutters->_getBrightnessSensor, $shutters->getBrightnessReading, -1 ); } sub getWindStatus { my $self = shift; return ReadingsVal( $ascDev->_getWindSensor, $ascDev->getWindSensorReading, -1 ); } sub getStatus { my $self = shift; return ReadingsNum( $self->{shuttersDev}, $shutters->getPosCmd, 0 ); } sub getDelayCmd { my $self = shift; return $self->{ $self->{shuttersDev} }{delayCmd}; } sub getASCenable { my $self = shift; return ReadingsVal( $self->{shuttersDev}, 'ASC_Enable', 'on' ); } ## Klasse Fenster (Window) und die Subklassen Attr und Readings ## package ASC_Window; our @ISA = qw(ASC_Window::Attr ASC_Window::Readings); ## Subklasse Attr von Klasse ASC_Window ## package ASC_Window::Attr; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( AttrVal gettimeofday) ); } sub getSubTyp { my $self = shift; return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', 'twostate' ); } sub _getWinDev { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < 2 ); $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} = int( gettimeofday() ); my ( $device, $reading ) = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, 'ASC_WindowRec', 'none' ); ### erwartetes Ergebnis # DEVICE:READING VALUEACTIVE:VALUEINACTIVE POSACTIVE:POSINACTIVE $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device} = $device; $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading} = ( $reading ne 'none' ? $reading : 'state' ); return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device}; } sub getWinDevReading { my $self = shift; return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading} if ( exists( $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < 2 ); $shutters->_getWinDev; return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading}; } ## Subklasse Readings von Klasse ASC_Window ## package ASC_Window::Readings; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( ReadingsVal) ); } sub getWinStatus { my $self = shift; return ReadingsVal( $shutters->_getWinDev, $shutters->getWinDevReading, 'closed' ); } ## Klasse ASC_Roommate ## package ASC_Roommate; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( ReadingsVal) ); } sub _getRoommateStatus { my $self = shift; my $roommate = $self->{roommate}; return ReadingsVal( $roommate, $shutters->getRoommatesReading, 'none' ); } sub _getRoommateLastStatus { my $self = shift; my $roommate = $self->{roommate}; my $default = $self->{defaultarg}; $default = 'none' if ( not defined($default) ); return ReadingsVal( $roommate, 'lastState', $default ); } ## Klasse ASC_Dev plus Subklassen ASC_Attr_Dev und ASC_Readings_Dev## package ASC_Dev; our @ISA = qw(ASC_Dev::Readings ASC_Dev::Attr); use strict; use warnings; sub new { my $class = shift; my $self = { name => undef, }; bless $self, $class; return $self; } sub setName { my ( $self, $name ) = @_; $self->{name} = $name if ( defined($name) ); return $self->{name}; } sub setDefault { my ( $self, $defaultarg ) = @_; $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); return $self->{defaultarg}; } sub getName { my $self = shift; return $self->{name}; } ## Subklasse Readings ## package ASC_Dev::Readings; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( readingsSingleUpdate ReadingsVal defs) ); } sub setDelayCmdReading { my $self = shift; my $name = $self->{name}; my $hash = $defs{$name}; readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_lastDelayPosValue', $shutters->getDelayCmd, 1 ); return 0; } sub setStateReading { my $self = shift; my $value = shift; my $name = $self->{name}; my $hash = $defs{$name}; readingsSingleUpdate( $hash, 'state', ( defined($value) ? $value : $shutters->getLastDrive ), 1 ); return 0; } sub setPosReading { my $self = shift; my $name = $self->{name}; my $hash = $defs{$name}; readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_PosValue', $shutters->getStatus, 1 ); return 0; } sub setLastPosReading { my $self = shift; my $name = $self->{name}; my $hash = $defs{$name}; readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_lastPosValue', $shutters->getLastPos, 1 ); return 0; } sub getPartyMode { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'partyMode', 'off' ); } sub getHardLockOut { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'hardLockOut', 'none' ); } sub getSunriseTimeWeHoliday { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'sunriseTimeWeHoliday', 'none' ); } sub getMonitoredDevs { my $self = shift; my $name = $self->{name}; $self->{monitoredDevs} = ReadingsVal( $name, '.monitoredDevs', 'none' ); return $self->{monitoredDevs}; } sub getOutTemp { my $self = shift; return ReadingsVal( $ascDev->_getTempSensor, $ascDev->getTempSensorReading, -100 ); } sub getResidentsStatus { my $self = shift; my $val = ReadingsVal( $ascDev->_getResidentsDev, $ascDev->getResidentsReading, 'none' ); if ( $val =~ m/^(?:(.+)_)?(.+)$/ ) { return ( $1, $2 ) if (wantarray); return $1 && $1 eq 'pet' ? 'absent' : $2; } elsif ( ReadingsVal( $ascDev->_getResidentsDev, 'homealoneType', '-' ) eq 'PET' ) { return ( 'pet', 'absent' ) if (wantarray); return 'absent'; } else { return ( undef, $val ) if (wantarray); return $val; } } sub getResidentsLastStatus { my $self = shift; my $val = ReadingsVal( $ascDev->_getResidentsDev, 'lastState', 'none' ); if ( $val =~ m/^(?:(.+)_)?(.+)$/ ) { return ( $1, $2 ) if (wantarray); return $1 && $1 eq 'pet' ? 'absent' : $2; } elsif ( ReadingsVal( $ascDev->_getResidentsDev, 'lastHomealoneType', '-' ) eq 'PET' ) { return ( 'pet', 'absent' ) if (wantarray); return 'absent'; } else { return ( undef, $val ) if (wantarray); return $val; } } sub getAutoShuttersControlShading { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'controlShading', 'none' ); } sub getSelfDefense { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'selfDefense', 'none' ); } sub getAzimuth { my $self = shift; my $azimuth; $azimuth = ReadingsVal( $ascDev->_getTwilightDevice, 'azimuth', -1 ) if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Twilight' ); $azimuth = ReadingsVal( $ascDev->_getTwilightDevice, 'SunAz', -1 ) if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Astro' ); return $azimuth; } sub getElevation { my $self = shift; my $elevation; $elevation = ReadingsVal( $ascDev->_getTwilightDevice, 'elevation', -1 ) if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Twilight' ); $elevation = ReadingsVal( $ascDev->_getTwilightDevice, 'SunAlt', -1 ) if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Astro' ); return $elevation; } sub getASCenable { my $self = shift; my $name = $self->{name}; return ReadingsVal( $name, 'ascEnable', 'none' ); } ## Subklasse Attr ## package ASC_Dev::Attr; use strict; use warnings; use GPUtils qw(GP_Import); ## Import der FHEM Funktionen BEGIN { GP_Import( qw( AttrVal gettimeofday) ); } sub getShuttersOffset { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_shuttersDriveDelay', -1 ); } sub getBrightnessMinVal { my $self = shift; my $name = $self->{name}; 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}; 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 { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_twilightDevice', 'none' ); } sub getAutoAstroModeEvening { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoAstroModeEvening', 'REAL' ); } sub getAutoAstroModeEveningHorizon { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoAstroModeEveningHorizon', 0 ); } sub getAutoAstroModeMorning { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoAstroModeMorning', 'REAL' ); } sub getAutoAstroModeMorningHorizon { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoAstroModeMorningHorizon', 0 ); } sub getAutoShuttersControlMorning { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoShuttersControlMorning', 'on' ); } sub getAutoShuttersControlEvening { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoShuttersControlEvening', 'on' ); } sub getAutoShuttersControlComfort { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_autoShuttersControlComfort', 'off' ); } sub getFreezeTemp { my $self = shift; my $name = $self->{name}; return AttrVal( $name, 'ASC_freezeTemp', 3 ); } sub _getTempSensor { my $self = shift; my $name = $self->{name}; 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 getTempSensorReading { my $self = shift; my $name = $self->{name}; 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}; 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}; 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}; 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, $wait ) = 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 : ( $self->{ASC_rainSensor}->{triggermax} * 0 ) ); $self->{ASC_rainSensor}->{shuttersClosedPos} = ( $pos ne 'none' ? $pos : $shutters->getClosedPos ); $self->{ASC_rainSensor}->{waitingTime} = ( $pos ne 'none' ? $wait : 900 ); return $self->{ASC_rainSensor}->{device}; } sub getRainSensorReading { my $self = shift; my $name = $self->{name}; 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 $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 getRainWaitingTime { my $self = shift; my $name = $self->{name}; return $self->{ASC_rainSensor}->{waitingTime} if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} ) and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); $ascDev->_getRainSensor; return $self->{ASC_rainSensor}->{waitingTime}; } 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 Module for controlling shutters depending on various conditions =item summary_DE Modul zur automatischen Rolladensteuerung auf Basis bestimmter Ereignisse =begin html

AutoShuttersControl

=end html =begin html_DE

AutoShuttersControl

=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": "testing", "license": "GPL_2", "version": "v0.8.15", "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, "Date::Parse": 0 }, "recommends": { }, "suggests": { } } } } =end :application/json;q=META.json =cut