diff --git a/73_AutoShuttersControl.pm b/73_AutoShuttersControl.pm deleted file mode 100644 index 58a10c3..0000000 --- a/73_AutoShuttersControl.pm +++ /dev/null @@ -1,8490 +0,0 @@ -############################################################################### -# -# 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: 73_AutoShuttersControl.pm 21670 2020-04-14 10:09:09Z CoolTux $ -# -############################################################################### - -### 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 qw(strftime); -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', -); - -## 2 Objekte werden erstellt -my $shutters = ASC_Shutters->new(); -my $ascDev = ASC_Dev->new(); - -sub ascAPIget { - my ( $getCommand, $shutterDev, $value ) = @_; - - my $getter = 'get' . $getCommand; - - if ( defined($value) && $value ) { - $shutters->setShuttersDev($shutterDev); - return $shutters->$getter($value); - } - elsif ( defined($shutterDev) && $shutterDev ) { - $shutters->setShuttersDev($shutterDev); - return $shutters->$getter; - } - else { - return $ascDev->$getter; - } -} - -sub Initialize { - my $hash = shift; - -## 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} = \&Set; - $hash->{GetFn} = \&Get; - $hash->{DefFn} = \&Define; - $hash->{NotifyFn} = \&Notify; - $hash->{UndefFn} = \&Undef; - $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} = \&ShuttersInformation; - $hash->{parseParams} = 1; - - return FHEM::Meta::InitMod( __FILE__, $hash ); -} - -sub Define { - my $hash = shift; - my $a = shift; - - 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 ( scalar( @{$a} ) != 2 ); - - my $name = shift @$a; - $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; -} - -sub Undef { - my $hash = shift; - my $name = shift; - - 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; -} - -sub Notify { - my $hash = shift; - my $dev = shift; - - 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 m{^DEFINED.$name$}xms, - @{$events} and $devname eq 'global' and $init_done - ) - or ( - grep m{^INITIALIZED$}xms, - @{$events} or grep m{^REREADCFG$}xms, - @{$events} or grep m{^MODIFIED.$name$}xms, - @{$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 m{^userAttrList:.rolled.out$}xms, @{$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 m{^partyMode:.off$}xms, @{$events} ) { - EventProcessingPartyMode($hash); - } - elsif ( grep m{^sunriseTimeWeHoliday:.(on|off)$}xms, @{$events} ) { - RenewSunRiseSetShuttersTimer($hash); - } - } - elsif ( $devname eq "global" ) - { # Kommt ein globales Event und beinhaltet folgende Syntax wird die Funktion zur Verarbeitung aufgerufen - if ( - grep -m{^(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.*|$)}xms, - @{$events} - ) - { - EventProcessingGeneral( $hash, undef, join( ' ', @{$events} ) ); - } - } - elsif ( grep m{^($posReading):\s\d+$}xms, @{$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) && ($devname) ) - { # es wird lediglich der Devicename der Funktion mitgegeben wenn es sich nicht um global handelt daher hier die Unterscheidung - 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' - && ( $shutters->getDown eq 'brightness' - || $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(.*)$}xms - ) - { # 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) - $}xms - ) - { # 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) - (.*)?}xms - ) - { - CreateSunRiseSetShuttersTimer( $hash, $2 ) - if ( - $3 ne 'ASC_Time_Up_WE_Holiday' - || ( $3 eq 'ASC_Time_Up_WE_Holiday' - && $ascDev->getSunriseTimeWeHoliday eq 'on' ) - ); - } - elsif ( - $events =~ m{^(DELETEATTR|ATTR) - \s(.*)\s(ASC_autoAstroModeMorning|ASC_autoAstroModeMorningHorizon - |ASC_autoAstroModeEvening|ASC_autoAstroModeEveningHorizon) - (.*)?}xms - ) - { - RenewSunRiseSetShuttersTimer($hash); - } - } - - return; -} - -sub Set { - my $hash = shift; - my $a = shift; - - my $name = shift @$a; - my $cmd = shift @$a // return qq{"set $name" needs at least one argument}; - - if ( lc $cmd eq 'renewalltimer' ) { - return "usage: $cmd" if ( scalar( @{$a} ) != 0 ); - RenewSunRiseSetShuttersTimer($hash); - } - elsif ( lc $cmd eq 'renewtimer' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - CreateSunRiseSetShuttersTimer( $hash, $a->[0] ); - } - elsif ( lc $cmd eq 'scanforshutters' ) { - return "usage: $cmd" if ( scalar( @{$a} ) != 0 ); - ShuttersDeviceScan($hash); - } - elsif ( lc $cmd eq 'createnewnotifydev' ) { - return "usage: $cmd" if ( scalar( @{$a} ) != 0 ); - CreateNewNotifyDev($hash); - } - elsif ( lc $cmd eq 'partymode' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ) - if ( $a->[0] ne ReadingsVal( $name, 'partyMode', 0 ) ); - } - elsif ( lc $cmd eq 'hardlockout' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ); - HardewareBlockForShutters( $hash, $a->[0] ); - } - elsif ( lc $cmd eq 'sunrisetimeweholiday' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ); - } - elsif ( lc $cmd eq 'controlshading' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ); - } - elsif ( lc $cmd eq 'selfdefense' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ); - } - elsif ( lc $cmd eq 'ascenable' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( $hash, $cmd, $a->[0], 1 ); - } - elsif ( lc $cmd eq 'advdrivedown' ) { - return "usage: $cmd" if ( scalar( @{$a} ) != 0 ); - EventProcessingAdvShuttersClose($hash); - } - elsif ( lc $cmd eq 'shutterascenabletoggle' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - readingsSingleUpdate( - $defs{ $a->[0] }, - 'ASC_Enable', - ( - ReadingsVal( $a->[0], 'ASC_Enable', 'off' ) eq 'on' - ? 'off' - : 'on' - ), - 1 - ); - } - elsif ( lc $cmd eq 'wiggle' ) { - return "usage: $cmd" if ( scalar( @{$a} ) > 1 ); - - ( $a->[0] eq 'all' ? wiggleAll($hash) : wiggle( $hash, $a->[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' - && defined( $hash->{helper}{shuttersList} ) - && scalar( @{ $hash->{helper}{shuttersList} } ) > 0 ); - $list .= ' createNewNotifyDev:noArg' - if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' - && AttrVal( $name, 'ASC_expert', 0 ) == 1 ); - - return "Unknown argument $cmd,choose one of $list"; - } - return; -} - -sub Get { - my $hash = shift; - my $a = shift; - - my $name = shift @$a; - my $cmd = shift @$a // return qq{"set $name" needs at least one argument}; - - if ( lc $cmd eq 'shownotifydevsinformations' ) { - return "usage: $cmd" if ( scalar( @{$a} ) != 0 ); - my $ret = GetMonitoredDevs($hash); - return $ret; - } - else { - my $list = ""; - $list .= " showNotifyDevsInformations:noArg" - if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' - && 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 = ''; - for (@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 ); - - return; -} - -## 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); - for ( @{ $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 ); - - return; -} - -sub UserAttributs_Readings_ForShutters { - my $hash = shift; - my $cmd = shift; - - my $name = $hash->{NAME}; - - while ( my ( $attrib, $attribValue ) = each %{userAttrList} ) { - for ( @{ $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 ( !defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) - && $attribValue ne '-' ); - } - else { - $attr{$_}{ ( split( ':', $attrib ) )[0] } = - $attribValue->[ AttrVal( $_, 'ASC', 2 ) ] - if ( !defined( $attr{$_}{ ( split( ':', $attrib ) )[0] } ) - && $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{ $_ }xms } - split( ',', "$associatedString,$name" ); - - if ( keys %hash > 1 ) { - readingsSingleUpdate( $defs{$_}, - 'associatedWith', join( ',', sort keys %hash ), 0 ); - } - else { CommandDeleteReading( undef, $_ . ' associatedWith' ); } - ################################### - } - } - } - - return; -} - -## 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 ); - for (@devs) { - $hash->{monitoredDevs}{$_}{$shuttersDev} = $shuttersAttr; - } - - readingsSingleUpdate( $hash, '.monitoredDevs', - eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); - - return; -} - -## 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 ); - - for 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{ $_ }xms } - split( ',', "$notifyDevString,$notifyDev" ); - - $hash->{NOTIFYDEV} = join( ',', sort keys %hash ); - } - } - readingsSingleUpdate( $hash, '.monitoredDevs', - eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); - - return; -} - -## 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)}xms - && 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 =~ m{[Cc]lose|true}xms - && $shutters->getShuttersPlace eq 'terrace' ); - $shutters->setHardLockOut('on') - if ( $match =~ m{[Oo]pen|false}xms - && $shutters->getShuttersPlace eq 'terrace' ); - - ASC_Debug( 'EventProcessingWindowRec: ' - . $shutters->getShuttersDev - . ' - HOMEMODE: ' - . $homemode - . ' QueryShuttersPosWinRecTilted:' - . $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) - . ' QueryShuttersPosWinRecComfort: ' - . $shutters->getQueryShuttersPos( $shutters->getComfortOpenPos ) - ); - - if ( - $match =~ m{[Cc]lose|true}xms - && IsAfterShuttersTimeBlocking($shuttersDev) - && ( - $shutters->getStatus == $shutters->getVentilatePos - || $shutters->getStatus == $shutters->getComfortOpenPos - || $shutters->getStatus == $shutters->getOpenPos - || ( $shutters->getStatus == $shutters->getPrivacyDownPos - && $shutters->getPrivacyDownStatus == 1 - && !$shutters->getIsDay ) - ) - && ( $shutters->getVentilateOpen eq 'on' - || $ascDev->getAutoShuttersControlComfort eq 'on' ) - ) - { - ASC_Debug( 'EventProcessingWindowRec: ' - . $shutters->getShuttersDev - . ' Event Closed' ); - - if ( - $shutters->getIsDay - && ( ( $homemode ne 'asleep' && $homemode ne 'gotosleep' ) - || $homemode eq 'none' ) - && $shutters->getModeUp ne 'absent' - && $shutters->getModeUp ne 'off' - ) - { - if ( $shutters->getIfInShading - && $shutters->getShadingPos != $shutters->getStatus - && $shutters->getShadingMode ne 'absent' ) - { - $shutters->setLastDrive('shading in'); - $shutters->setNoDelay(1); - $shutters->setDriveCmd( $shutters->getShadingPos ); - } - elsif ( - !$shutters->getIfInShading - && ( $shutters->getStatus != $shutters->getOpenPos - || $shutters->getStatus != $shutters->getLastManPos ) - ) - { - if ( $shutters->getPrivacyDownStatus == 2 ) { - $shutters->setLastDrive( - 'window closed at privacy night close'); - $shutters->setNoDelay(1); - $shutters->setDriveCmd( $shutters->getPrivacyDownPos ); - } - 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' - && $shutters->getModeDown ne 'off' - && ( !$shutters->getIsDay - || $homemode eq 'asleep' - || $homemode eq 'gotosleep' ) - && $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 =~ m{tilt}xms || ( $match =~ m{[Oo]pen|false}xms - && $shutters->getSubTyp eq 'twostate' ) - ) - && $shutters->getVentilateOpen eq 'on' - && $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) - ) - { - $shutters->setLastDrive('ventilate - window open'); - $shutters->setNoDelay(1); - $shutters->setDriveCmd( - ( - ( - $shutters->getShuttersPlace eq 'terrace' - && $shutters->getSubTyp eq 'twostate' - ) ? $shutters->getOpenPos : $shutters->getVentilatePos - ) - ); - } - elsif ($match =~ m{[Oo]pen|false}xms - && $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 ) - && $shutters->getVentilateOpen eq 'on' ) - { - $posValue = $shutters->getVentilatePos; - $setLastDrive = 'ventilate - window open'; - } - - if ( defined($posValue) && $posValue ) { - $shutters->setLastDrive($setLastDrive); - $shutters->setNoDelay(1); - $shutters->setDriveCmd($posValue); - } - } - } - - return; -} - -## 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)}xms ) { - 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' || $1 eq 'awoken' ) - && ( $getRoommatesStatus eq 'home' - || $getRoommatesStatus eq 'awoken' ) - && ( $ascDev->getAutoShuttersControlMorning eq 'on' - || $shutters->getUp eq 'roommate' ) - && IsAfterShuttersManualBlocking($shuttersDev) - ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate_1: $shuttersDev und Events $events" - ); - if ( - ( - $getRoommatesLastStatus eq 'asleep' - || $getRoommatesLastStatus eq 'awoken' - ) - && ( $shutters->getIsDay - || $shutters->getUp eq 'roommate' ) - && ( IsAfterShuttersTimeBlocking($shuttersDev) - || $shutters->getUp eq 'roommate' ) - ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate_2: $shuttersDev und Events $events" - ); - - if ( $shutters->getIfInShading - && !$shutters->getShadingManualDriveStatus - && $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' - || $getRoommatesLastStatus eq 'gone' - ) - && $getRoommatesStatus eq 'home' - ) - { - if ( - !$shutters->getIsDay - && IsAfterShuttersTimeBlocking($shuttersDev) - && ( $getModeDown eq 'home' - || $getModeDown eq 'always' ) - && $shutters->getDown ne 'roommate' - ) - { - $shutters->setLastDrive('roommate come home'); - - if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 - || $shutters->getVentilateOpen eq 'off' ) - { - $posValue = ( - $shutters->getSleepPos > 0 ? $shutters->getSleepPos - : ( - $shutters->getSleepPos > 0 - ? $shutters->getSleepPos - : $shutters->getClosedPos - ) - ); - } - else { - $posValue = $shutters->getVentilatePos; - $shutters->setLastDrive( - $shutters->getLastDrive . ' - ventilate mode' ); - } - - ShuttersCommandSet( $hash, $shuttersDev, $posValue ); - } - elsif ( - ( $shutters->getIsDay || $shutters->getUp eq 'roommate' ) - && IsAfterShuttersTimeBlocking($shuttersDev) - && ( $getModeUp eq 'home' - || $getModeUp eq 'always' ) - ) - { - if ( $shutters->getIfInShading - && !$shutters->getShadingManualDriveStatus - && $shutters->getStatus == $shutters->getOpenPos - && $shutters->getShadingMode eq 'home' ) - { - $shutters->setLastDrive('shading in'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getShadingPos ); - } - elsif ( - ( - !$shutters->getIfInShading - || $shutters->getShadingMode eq 'absent' - ) - && ( $shutters->getStatus == $shutters->getClosedPos - || $shutters->getStatus == $shutters->getSleepPos - || $shutters->getStatus == - $shutters->getShadingPos ) - ) - { - $shutters->setLastDrive( - ( - ( - $shutters->getStatus == - $shutters->getClosedPos - || $shutters->getStatus == - $shutters->getSleepPos - ) - ? 'roommate come home' - : 'shading out' - ) - ); - - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getOpenPos ); - } - } - } - } - elsif ( - ( $1 eq 'gotosleep' || $1 eq 'asleep' ) - && ( $ascDev->getAutoShuttersControlEvening eq 'on' - || $shutters->getDown eq 'roommate' ) - && ( IsAfterShuttersManualBlocking($shuttersDev) - || $shutters->getDown eq 'roommate' ) - ) - { - $shutters->setLastDrive('roommate asleep'); - - if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 - || $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' - && ( !$shutters->getIsDay - || $shutters->getDown eq 'roommate' - || $shutters->getShadingMode eq 'absent' - || $shutters->getModeUp eq 'absent' - || $shutters->getModeDown eq 'absent' ) - ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate absent: $shuttersDev" - ); - - if ( ( $shutters->getIsDay || $shutters->getUp eq 'roommate' ) - && $shutters->getIfInShading - && !$shutters->getQueryShuttersPos( $shutters->getShadingPos ) - && $shutters->getShadingMode eq 'absent' ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate Shading: $shuttersDev" - ); - - $shutters->setLastDrive('shading in'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getShadingPos ); - } - elsif (( !$shutters->getIsDay || $shutters->getDown eq 'roommate' ) - && $getModeDown eq 'absent' - && $getRoommatesStatus eq 'absent' ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate Down: $shuttersDev" - ); - - $shutters->setLastDrive('roommate absent'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getClosedPos ); - } - elsif ($shutters->getIsDay - && $shutters->getModeUp eq 'absent' - && $getRoommatesStatus eq 'absent' ) - { - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate Up: $shuttersDev" - ); - - $shutters->setLastDrive('roommate absent'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getOpenPos ); - } - - Log3( $name, 4, -"AutoShuttersControl ($name) - EventProcessingRoommate NICHTS: $shuttersDev" - ); - } - } - - return; -} - -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))}xms ) { - for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($shuttersDev); - my $getModeUp = $shutters->getModeUp; - my $getModeDown = $shutters->getModeDown; - $shutters->setHardLockOut('off'); - if ( - $ascDev->getSelfDefense eq 'on' - && $shutters->getSelfDefenseMode ne 'off' - || ( $getModeDown eq 'absent' - || $getModeDown eq 'always' ) - ) - { - if ( - $ascDev->getSelfDefense eq 'on' - && ( - $shutters->getSelfDefenseMode eq 'absent' - || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getSelfDefenseMode eq 'gone' - && $shutters->getShuttersPlace eq 'terrace' - && $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' || $getModeDown eq 'always' ) - && !$shutters->getIsDay - && IsAfterShuttersTimeBlocking($shuttersDev) - && $shutters->getRoommatesStatus eq 'none' ) - { - $shutters->setLastDrive('residents absent'); - $shutters->setDriveCmd( $shutters->getClosedPos ); - } - } - } - } - elsif ($events =~ m{$reading:\s(gone)}xms - && $ascDev->getSelfDefense eq 'on' ) - { - for 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)}xms - && ( $getResidentsLastStatus eq 'absent' - || $getResidentsLastStatus eq 'gone' - || $getResidentsLastStatus eq 'asleep' - || $getResidentsLastStatus eq 'awoken' ) - ) - { - for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($shuttersDev); - my $getModeUp = $shutters->getModeUp; - my $getModeDown = $shutters->getModeDown; - - if ( - ( - $shutters->getStatus != $shutters->getClosedPos - || $shutters->getStatus != $shutters->getSleepPos - ) - && !$shutters->getIsDay - && $shutters->getRoommatesStatus eq 'none' - && ( $getModeDown eq 'home' - || $getModeDown eq 'always' ) - && $getResidentsLastStatus ne 'asleep' - && $getResidentsLastStatus ne 'awoken' - && IsAfterShuttersTimeBlocking($shuttersDev) - && !$shutters->getSelfDefenseState - ) - { - $shutters->setLastDrive('residents come home'); - $shutters->setDriveCmd( - ( - $shutters->getSleepPos > 0 - ? $shutters->getSleepPos - : $shutters->getClosedPos - ) - ); - } - elsif ( - ( - $shutters->getShadingMode eq 'home' - || $shutters->getShadingMode eq 'always' - ) - && $shutters->getIsDay - && $shutters->getIfInShading - && $shutters->getRoommatesStatus eq 'none' - && $shutters->getStatus != $shutters->getShadingPos - && !$shutters->getShadingManualDriveStatus - && !( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getShuttersPlace eq 'terrace' - ) - && !$shutters->getSelfDefenseState - ) - { - $shutters->setLastDrive('shading in'); - $shutters->setDriveCmd( $shutters->getShadingPos ); - } - elsif ( - $shutters->getShadingMode eq 'absent' - && $shutters->getIsDay - && $shutters->getIfInShading - && $shutters->getStatus == $shutters->getShadingPos - && $shutters->getRoommatesStatus eq 'none' - && !$shutters->getShadingManualDriveStatus - && !( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getShuttersPlace eq 'terrace' - ) - && !$shutters->getSelfDefenseState - ) - { - $shutters->setLastDrive('shading out'); - $shutters->setDriveCmd( $shutters->getLastPos ); - } - elsif ( - $ascDev->getSelfDefense eq 'on' - && $shutters->getSelfDefenseMode ne 'off' - && !$shutters->getIfInShading - && ( $getResidentsLastStatus eq 'gone' - || $getResidentsLastStatus eq 'absent' ) - && $shutters->getSelfDefenseState - ) - { - RemoveInternalTimer( $shutters->getSelfDefenseAbsentTimerhash ) - if ( $getResidentsLastStatus eq 'absent' - && $ascDev->getSelfDefense eq 'on' - && $shutters->getSelfDefenseMode ne 'off' - && !$shutters->getSelfDefenseAbsent - && $shutters->getSelfDefenseAbsentTimerrun ); - - if ( - ( - $shutters->getStatus == $shutters->getClosedPos - || $shutters->getStatus == $shutters->getSleepPos - ) - && $shutters->getIsDay - ) - { - $shutters->setHardLockOut('on') - if ( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getShuttersPlace eq 'terrace' - && ( $getModeUp eq 'absent' - || $getModeUp eq 'off' ) - ); - - $shutters->setSelfDefenseState(0); - $shutters->setLastDrive('selfDefense inactive'); - $shutters->setDriveCmd( - ( - $shutters->getPrivacyDownStatus == 2 - ? $shutters->getPrivacyDownPos - : $shutters->getOpenPos - ) - ); - } - } - elsif ( - ( - $shutters->getStatus == $shutters->getClosedPos - || $shutters->getStatus == $shutters->getSleepPos - ) - && $shutters->getIsDay - && $shutters->getRoommatesStatus eq 'none' - && ( $getModeUp eq 'home' - || $getModeUp eq 'always' ) - && IsAfterShuttersTimeBlocking($shuttersDev) - && !$shutters->getIfInShading - && !$shutters->getSelfDefenseState - ) - { - if ( $getResidentsLastStatus eq 'asleep' - || $getResidentsLastStatus eq 'awoken' ) - { - $shutters->setLastDrive('residents awoken'); - } - else { $shutters->setLastDrive('residents home'); } - $shutters->setDriveCmd( $shutters->getOpenPos ); - } - } - } - - return; -} - -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)}xms ) { - 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 ); - } - - return; -} - -sub RainProtection { - my ( $hash, $val, $triggerMax, $closedPos ) = @_; - - for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($shuttersDev); - - next - if ( $shutters->getRainProtection eq 'off' ); - - if ( $val > $triggerMax - && $shutters->getStatus != $closedPos - && IsAfterShuttersManualBlocking($shuttersDev) - && $shutters->getRainProtectionStatus eq 'unprotected' ) - { - $shutters->setLastDrive('rain protected'); - $shutters->setDriveCmd($closedPos); - $shutters->setRainProtectionStatus('protected'); - } - elsif (( $val == 0 || $val < $triggerMax ) - && $shutters->getStatus == $closedPos - && IsAfterShuttersManualBlocking($shuttersDev) - && $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'); - } - } - - return; -} - -sub EventProcessingWind { - my ( $hash, $shuttersDev, $events ) = @_; - - my $name = $hash->{NAME}; - $shutters->setShuttersDev($shuttersDev); - - my $reading = $ascDev->getWindSensorReading; - if ( $events =~ m{$reading:\s(\d+(\.\d+)?)}xms ) { - for 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 - && $shutters->getShuttersPlace eq 'terrace' - ) - || $shutters->getWindProtection eq 'off' - ); - - if ( $1 > $shutters->getWindMax - && $shutters->getWindProtectionStatus eq 'unprotected' ) - { - $shutters->setLastDrive('wind protected'); - $shutters->setDriveCmd( $shutters->getWindPos ); - $shutters->setWindProtectionStatus('protected'); - } - elsif ($1 < $shutters->getWindMin - && $shutters->getWindProtectionStatus eq 'protected' ) - { - $shutters->setLastDrive('wind un-protected'); - $shutters->setDriveCmd( - ( - $shutters->getIsDay ? $shutters->getLastPos - : ( - $shutters->getPrivacyDownStatus == 2 - ? $shutters->getPrivacyDownPos - : ( - $shutters->getSleepPos > 0 - ? $shutters->getSleepPos - : $shutters->getClosedPos - ) - ) - ) - ); - $shutters->setWindProtectionStatus('unprotected'); - } - - ASC_Debug( 'EventProcessingWind: ' - . $shutters->getShuttersDev - . ' - WindProtection2: ' - . $shutters->getWindProtectionStatus - . ' WindMax2: ' - . $shutters->getWindMax - . ' WindMin2: ' - . $shutters->getWindMin - . ' Bekommender Wert2: ' - . $1 ); - } - } - - return; -} -########## - -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' - || $shutters->getUp eq 'brightness' - ) - || ( - ( - ( - ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', - $shutters->getTimeUpEarly ) / 86400 - ) - && ( - !IsWe() - || ( IsWe() - && $ascDev->getSunriseTimeWeHoliday eq 'off' ) - ) - ) - || ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ) / 86400 - ) - && IsWe() - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday eq '01:25' - ) - ) - && int( gettimeofday() / 86400 ) == int( - computeAlignTime( '24:00', $shutters->getTimeUpLate ) / - 86400 - ) - ) - || ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / - 86400 - ) - && 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+)?)}xms ) { - 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 - ) - && ( - !IsWe() - || ( - IsWe() - && $ascDev->getSunriseTimeWeHoliday eq 'off' - || ( $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday eq - '01:25' ) - ) - ) - ) - || ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ) / 86400 - ) - && IsWe() - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' - ) - ) - && int( gettimeofday() / 86400 ) == int( - computeAlignTime( '24:00', $shutters->getTimeUpLate ) / - 86400 - ) - ) - && ( - $1 > $brightnessMaxVal - || ( $1 > $brightnessPrivacyUpVal - && $shutters->getPrivacyUpStatus == 1 ) - ) - && $shutters->getUp eq 'brightness' - && !$shutters->getSunrise - && $ascDev->getAutoShuttersControlMorning eq 'on' - && ( - $ascDev->getSelfDefense eq 'off' - || $shutters->getSelfDefenseMode eq 'off' - || ( $ascDev->getSelfDefense eq 'on' - && $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 - || ( $shutters->getModeUp eq 'absent' - && $homemode eq 'gone' ) - || $shutters->getModeUp eq 'always' - ) - { - my $roommatestatus = $shutters->getRoommatesStatus; - - if ( - $roommatestatus eq 'home' - || $roommatestatus eq 'awoken' - || $roommatestatus eq 'absent' - || $roommatestatus eq 'gone' - || $roommatestatus eq 'none' - && ( - $ascDev->getSelfDefense eq 'off' - || ( $ascDev->getSelfDefense eq 'on' - && CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) - || ( $ascDev->getSelfDefense eq 'on' - && CheckIfShuttersWindowRecOpen($shuttersDev) != 0 - && $ascDev->getResidentsStatus eq 'home' ) - ) - ) - { - - if ( $brightnessPrivacyUpVal > 0 - && $1 < $brightnessMaxVal - && $1 > $brightnessPrivacyUpVal ) - { - $shutters->setPrivacyUpStatus(2); - $shutters->setLastDrive('brightness privacy day open'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getPrivacyUpPos ) - unless ( - !$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 - ) - && int( gettimeofday() / 86400 ) == int( - computeAlignTime( '24:00', $shutters->getTimeDownLate ) / 86400 - ) - && ( - $1 < $brightnessMinVal - || ( $1 < $brightnessPrivacyDownVal - && $shutters->getPrivacyDownStatus == 1 ) - ) - && $shutters->getDown eq 'brightness' - && !$shutters->getSunset - && IsAfterShuttersManualBlocking($shuttersDev) - && $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 - || ( $shutters->getModeDown eq 'absent' - && $homemode eq 'gone' ) - || $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 - - if ( $brightnessPrivacyDownVal > 0 - && $1 > $brightnessMinVal - && $1 < $brightnessPrivacyDownVal ) - { - $lastDrive = 'brightness privacy night close'; - $posValue = ( - ( - !$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 - && $shutters->getSubTyp eq 'threestate' - && $ascDev->getAutoShuttersControlComfort eq 'on' ) - { - $posValue = $shutters->getComfortOpenPos; - $lastDrive = 'minimum brightness threshold fell below'; - $shutters->setPrivacyDownStatus(0) - if ( $shutters->getPrivacyDownStatus == 2 ); - } - elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 - || $shutters->getVentilateOpen eq 'off' ) - { - $posValue = ( - $shutters->getSleepPos > 0 - ? $shutters->getSleepPos - : $shutters->getClosedPos - ); - $lastDrive = 'minimum brightness threshold fell below'; - $shutters->setPrivacyDownStatus(0) - if ( $shutters->getPrivacyDownStatus == 2 ); - } - else { - $posValue = $shutters->getVentilatePos; - $lastDrive = 'minimum brightness threshold fell below'; - $shutters->setPrivacyDownStatus(0) - if ( $shutters->getPrivacyDownStatus == 2 ); - } - - $shutters->setLastDrive($lastDrive); - - if ( - $shutters->getPrivacyDownStatus != 2 - && ( $posValue != $shutters->getStatus - || $shutters->getSelfDefenseState ) - ) - { - $shutters->setSunrise(0); - $shutters->setSunset(1); - } - - ShuttersCommandSet( $hash, $shuttersDev, $posValue ); - - ASC_Debug( 'EventProcessingBrightness: ' - . $shutters->getShuttersDev - . ' - Verarbeitung für Sunset. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Zielposition: ' - . $posValue - . ' Grund des fahrens: ' - . $shutters->getLastDrive ); - } - else { - EventProcessingShadingBrightness( $hash, $shuttersDev, $events ) - 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' - ); - } - - return; -} - -sub EventProcessingShadingBrightness { - my ( $hash, $shuttersDev, $events ) = @_; - - my $name = $hash->{NAME}; - $shutters->setShuttersDev($shuttersDev); - my $reading = $shutters->getBrightnessReading; - my $outTemp = - ( $shutters->getOutTemp != -100 - ? $shutters->getOutTemp - : $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+)?)}xms ) { - 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' - && $shutters->getRainProtectionStatus eq 'unprotected' - && $shutters->getWindProtectionStatus eq 'unprotected' ) - { - 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' - ); - } - } - - return; -} - -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+)}xms ) { - my $name = $device; - my ( $azimuth, $elevation ); - my $outTemp = $ascDev->getOutTemp; - - $azimuth = $2 if ( $1 eq 'azimuth' || $1 eq 'SunAz' ); - $elevation = $2 if ( $1 eq 'elevation' || $1 eq 'SunAlt' ); - - $azimuth = $ascDev->getAzimuth - if ( !defined($azimuth) && !$azimuth ); - $elevation = $ascDev->getElevation - if ( !defined($elevation) && !$elevation ); - - ASC_Debug( 'EventProcessingTwilightDevice: ' - . $name - . ' - Passendes Event wurde erkannt. Verarbeitung über alle Rollos beginnt' - ); - - for 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' - && $shutters->getRainProtectionStatus eq 'unprotected' - && $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' - ); - } - } - } - - return; -} - -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 - || $elevation == -1 - || $brightness == -1 - || $outTemp == -100 - || ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < - ( $shutters->getShadingWaitingPeriod / 2 ) - || $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; - my $homemode = $shutters->getHomemode; - - 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 - 4 - || $azimuth < $azimuthLeft - || $azimuth > $azimuthRight - || !$shutters->getIsDay - ) - && $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 - || $azimuth > $azimuthRight - || $elevation < $shutters->getShadingMinElevation - || $elevation > $shutters->getShadingMaxElevation - || $brightness < $shutters->getShadingStateChangeCloudy - || $outTemp < $shutters->getShadingMinOutsideTemperature - 1 ) - { - $shutters->setShadingStatus('out reserved') - if ( $shutters->getShadingStatus eq 'in' - || $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 - && $azimuth < $azimuthRight - && $elevation > $shutters->getShadingMinElevation - && $elevation < $shutters->getShadingMaxElevation - && $brightness > $shutters->getShadingStateChangeSunny - && $outTemp > $shutters->getShadingMinOutsideTemperature ) - { - $shutters->setShadingStatus('in reserved') - if ( $shutters->getShadingStatus eq 'out' - || $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 ( - IsAfterShuttersTimeBlocking($shuttersDev) - && !$shutters->getShadingManualDriveStatus - && $shutters->getRoommatesStatus ne 'gotosleep' - && $shutters->getRoommatesStatus ne 'asleep' - && ( - ( - $shutters->getShadingStatus eq 'out' - && $shutters->getShadingLastStatus eq 'in' - ) - || ( $shutters->getShadingStatus eq 'in' - && $shutters->getShadingLastStatus eq 'out' ) - ) - && ( $shutters->getShadingMode eq 'always' - || $shutters->getShadingMode eq $homemode ) - && ( - $shutters->getModeUp eq 'always' - || $shutters->getModeUp eq $homemode - || ( $shutters->getModeUp eq 'home' - && $homemode ne 'asleep' ) - || $shutters->getModeUp eq 'off' - ) - && ( - ( - ( - int( gettimeofday() ) - - $shutters->getShadingStatusTimestamp - ) < 2 - && $shutters->getStatus != $shutters->getClosedPos - ) - || ( !$shutters->getQueryShuttersPos( $shutters->getShadingPos ) - && $shutters->getIfInShading ) - || ( !$shutters->getIfInShading - && $shutters->getStatus == $shutters->getShadingPos ) - ) - ); - - return; -} - -sub ShadingProcessingDriveCommand { - my $hash = shift; - my $shuttersDev = shift; - - 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' - || $shutters->getShadingMode eq $homemode ) - { - $shutters->setShadingStatus( $shutters->getShadingStatus ); - - if ( - $shutters->getShadingStatus eq 'in' - && $getShadingPos != $getStatus - && ( CheckIfShuttersWindowRecOpen($shuttersDev) != 2 - || $shutters->getShuttersPlace ne 'terrace' ) - ) - { - $shutters->setLastDrive('shading in'); - ShuttersCommandSet( $hash, $shuttersDev, $getShadingPos ); - - ASC_Debug( 'ShadingProcessingDriveCommand: ' - . $shutters->getShuttersDev - . ' - Der aktuelle Beschattungsstatus ist: ' - . $shutters->getShadingStatus - . ' und somit wird nun in die Position: ' - . $getShadingPos - . ' zum Beschatten gefahren' ); - } - elsif ($shutters->getShadingStatus eq 'out' - && $getShadingPos == $getStatus ) - { - $shutters->setLastDrive('shading out'); - - ShuttersCommandSet( - $hash, - $shuttersDev, - ( - $getShadingPos == $shutters->getLastPos - ? $shutters->getOpenPos - : ( - $shutters->getQueryShuttersPos( $shutters->getLastPos ) - ? ( - $shutters->getLastPos == $shutters->getSleepPos - ? $shutters->getOpenPos - : $shutters->getLastPos - ) - : $shutters->getOpenPos - ) - ) - ); - - ASC_Debug( 'ShadingProcessingDriveCommand: ' - . $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( - 'ShadingProcessingDriveCommand: ' - . $shutters->getShuttersDev - . ' - Der aktuelle Beschattungsstatus ist: ' - . $shutters->getShadingStatus - . ', Beschattungsstatus Zeitstempel: ' - . strftime( - "%Y.%m.%e %T", localtime( $shutters->getShadingStatusTimestamp ) - ) - ); - } - - return; -} - -sub EventProcessingPartyMode { - my $hash = shift; - - my $name = $hash->{NAME}; - - for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($shuttersDev); - next - if ( $shutters->getPartyMode eq 'off' ); - - if ( !$shutters->getIsDay - && $shutters->getModeDown ne 'off' - && IsAfterShuttersManualBlocking($shuttersDev) ) - { - if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $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' - && $shutters->getIsDay - && IsAfterShuttersManualBlocking($shuttersDev) ) - { - $shutters->setLastDrive('drive after party mode'); - ShuttersCommandSet( $hash, $shuttersDev, $shutters->getDelayCmd ); - } - } - - return; -} - -sub EventProcessingAdvShuttersClose { - my $hash = shift; - - my $name = $hash->{NAME}; - - for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($shuttersDev); - next - if ( !$shutters->getAdv - && !$shutters->getAdvDelay ); - - $shutters->setLastDrive('adv delay close'); - $shutters->setAdvDelay(1); - ShuttersCommandSet( - $hash, - $shuttersDev, - ( - $shutters->getDelayCmd ne 'none' - ? $shutters->getDelayCmd - : $shutters->getClosedPos - ) - ); - } - - return; -} - -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+)}xms ) { - $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 - && ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) > - $shutters->getDriveUpMaxDuration ) - { - $shutters->setLastDrive('manual'); - $shutters->setLastDriveReading; - $ascDev->setStateReading; - $shutters->setLastManPos($1); - - $shutters->setShadingManualDriveStatus(1) - if ( $shutters->getIsDay - && $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. ' - ); - - return; -} - -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 $triggerValActive2 = $shutters->getExternalTriggerValueActive2; - my $triggerValInactive = $shutters->getExternalTriggerValueInactive; - my $triggerPosActive = $shutters->getExternalTriggerPosActive; - my $triggerPosActive2 = $shutters->getExternalTriggerPosActive2; - my $triggerPosInactive = $shutters->getExternalTriggerPosInactive; - - if ( $events =~ m{$reading:\s($triggerValActive|$triggerValActive2)}xms ) { - - # && !$shutters->getQueryShuttersPos($triggerPosActive) - - ASC_Debug( 'EventProcessingExternalTriggerDevice: ' - . ' In der RegEx Schleife Trigger Val Aktiv' - . ' - TriggerVal: ' - . $triggerValActive - . ' - TriggerVal2: ' - . $triggerValActive2 ); - - if ( $1 eq $triggerValActive2 ) { - $shutters->setLastDrive('external trigger2 device active'); - $shutters->setNoDelay(1); - $shutters->setExternalTriggerState(1); - ShuttersCommandSet( $hash, $shuttersDev, $triggerPosActive2 ); - } - else { - $shutters->setLastDrive('external trigger device active'); - $shutters->setNoDelay(1); - $shutters->setExternalTriggerState(1); - ShuttersCommandSet( $hash, $shuttersDev, $triggerPosActive ); - } - } - elsif ( - $events =~ m{$reading:\s($triggerValInactive)}xms - && ( $shutters->getPrivacyDownStatus != 2 - || $shutters->getPrivacyUpStatus != 2 ) - && !$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, - ( - $shutters->getIsDay - ? $triggerPosInactive - : $shutters->getClosedPos - ) - ); - } - - ASC_Debug( - 'EventProcessingExternalTriggerDevice: ' . ' Funktion durchlaufen' ); - - return; -} - -# 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 - && CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getShuttersPlace eq 'terrace' - && ( $shutters->getLockOut eq 'soft' - || $shutters->getLockOut eq 'hard' ) - && !$shutters->getQueryShuttersPos($posValue) - ) - || ( - $posValue != $shutters->getShadingPos - && ( - ( - $shutters->getPartyMode eq 'on' - && $ascDev->getPartyMode eq 'on' - ) - || ( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getSubTyp eq 'threestate' - && ( $ascDev->getAutoShuttersControlComfort eq 'off' - || $shutters->getComfortOpenPos != $posValue ) - && $shutters->getVentilateOpen eq 'on' - && $shutters->getShuttersPlace eq 'window' - && $shutters->getLockOut ne 'off' - ) - || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getSubTyp eq 'threestate' - && $ascDev->getAutoShuttersControlComfort eq 'on' - && $shutters->getVentilateOpen eq 'off' - && $shutters->getShuttersPlace eq 'window' - && $shutters->getLockOut ne 'off' ) - || ( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && ( $shutters->getLockOut eq 'soft' - || $shutters->getLockOut eq 'hard' ) - && !$shutters->getQueryShuttersPos($posValue) - ) - || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getShuttersPlace eq 'terrace' - && !$shutters->getQueryShuttersPos($posValue) ) - || ( $shutters->getRainProtectionStatus eq 'protected' - && $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' - ); - } - - return; -} - -## Sub welche die InternalTimer nach entsprechenden Sunset oder Sunrise zusammen stellt -sub CreateSunRiseSetShuttersTimer { - my $hash = shift; - my $shuttersDev = shift; - - 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 ( !defined( $shutters->getPrivacyUpStatus ) ); - $shutters->setPrivacyDownStatus(0) - if ( !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' ) ne - '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' ) ne - '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, \&SunSetShuttersAfterTimerFn, - \%funcHash ); - InternalTimer( $shuttersSunriseUnixtime, \&SunRiseShuttersAfterTimerFn, - \%funcHash ); - - $ascDev->setStateReading('created new drive timer'); - - return; -} - -## Funktion zum neu setzen der Timer und der Readings für Sunset/Rise -sub RenewSunRiseSetShuttersTimer { - my $hash = shift; - - for ( @{ $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' -# && 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' -# || AttrVal( $name, 'ASC_Shading_Angle_Left', 'none' ) ne 'none' -# || 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' ); - } - - return; -} - -## Funktion zum hardwareseitigen setzen des lock-out oder blocking beim Rolladen selbst -sub HardewareBlockForShutters { - my $hash = shift; - my $cmd = shift; - - for ( @{ $hash->{helper}{shuttersList} } ) { - $shutters->setShuttersDev($_); - $shutters->setHardLockOut($cmd); - } - - return; -} - -## Funktion für das wiggle aller Shutters zusammen -sub wiggleAll { - my $hash = shift; - - for ( @{ $hash->{helper}{shuttersList} } ) { - wiggle( $hash, $_ ); - } - - return; -} - -sub wiggle { - my $hash = shift; - my $shuttersDev = shift; - - $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, \&_SetCmdFn, \%h ); - - return; -} -#### - -## 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' - && $ascDev->getAutoShuttersControlEvening eq 'on' - && IsAfterShuttersManualBlocking($shuttersDev) - && ( - $shutters->getModeDown eq $homemode - || ( $shutters->getModeDown eq 'absent' - && $homemode eq 'gone' ) - || $shutters->getModeDown eq 'always' - ) - && ( - $ascDev->getSelfDefense eq 'off' - || $shutters->getSelfDefenseMode eq 'off' - || ( $ascDev->getSelfDefense eq 'on' - && $ascDev->getResidentsStatus ne 'gone' ) - ) - && ( - $shutters->getDown ne 'brightness' - || ( $shutters->getDown eq 'brightness' - && !$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 ); - - return; -} - -## 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' - && $ascDev->getAutoShuttersControlMorning eq 'on' - && ( - $shutters->getModeUp eq $homemode - || ( $shutters->getModeUp eq 'absent' - && $homemode eq 'gone' ) - || $shutters->getModeUp eq 'always' - ) - && ( - $ascDev->getSelfDefense eq 'off' - || $shutters->getSelfDefenseMode eq 'off' - || ( - $ascDev->getSelfDefense eq 'on' - && ( $shutters->getSelfDefenseMode eq 'gone' - || $shutters->getSelfDefenseMode eq 'absent' ) - && $ascDev->getResidentsStatus ne 'gone' - ) - || ( $ascDev->getSelfDefense eq 'on' - && $shutters->getSelfDefenseMode eq 'absent' - && $ascDev->getResidentsStatus ne 'absent' ) - ) - && ( - $shutters->getUp ne 'brightness' - || ( $shutters->getUp eq 'brightness' - && !$shutters->getSunrise ) - ) - ) - { - - if ( - ( - $shutters->getRoommatesStatus eq 'home' - || $shutters->getRoommatesStatus eq 'awoken' - || $shutters->getRoommatesStatus eq 'absent' - || $shutters->getRoommatesStatus eq 'gone' - || $shutters->getRoommatesStatus eq 'none' - ) - && ( - $ascDev->getSelfDefense eq 'off' - || ( $ascDev->getSelfDefense eq 'on' - && CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) - || ( - $ascDev->getSelfDefense eq 'on' - && CheckIfShuttersWindowRecOpen($shuttersDev) != 0 - && ( $ascDev->getResidentsStatus ne 'absent' - && $ascDev->getResidentsStatus ne 'gone' ) - ) - ) - ) - { - if ( !$shutters->getIfInShading ) { - if ( $shutters->getPrivacyUpStatus == 1 ) { - $shutters->setPrivacyUpStatus(2); - $shutters->setLastDrive('timer privacy day open'); - ShuttersCommandSet( $hash, $shuttersDev, - $shutters->getPrivacyUpPos ) - unless ( - !$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 ); - - return; -} - -sub CreateNewNotifyDev { - my $hash = shift; - - my $name = $hash->{NAME}; - - $hash->{NOTIFYDEV} = "global," . $name; - delete $hash->{monitoredDevs}; - - CommandDeleteReading( undef, $name . ' .monitoredDevs' ); - my $shuttersList = ''; - for ( @{ $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; - - return; -} - -sub ShuttersInformation { - my ( $FW_wname, $d, $room, $pageHash ) = @_; - - my $hash = $defs{$d}; - - return - if ( !exists( $hash->{helper} ) - || !defined( $hash->{helper}->{shuttersList} ) - || ref( $hash->{helper}->{shuttersList} ) ne 'ARRAY' - || scalar( @{ $hash->{helper}->{shuttersList} } ) == 0 - || !defined( $shutters->getSunriseUnixTime ) - || !defined( $shutters->getSunsetUnixTime ) ); - - 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; - for 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; - for my $notifydev ( sort keys( %{$notifydevs} ) ) { - if ( ref( $notifydevs->{$notifydev} ) eq "HASH" ) { - for 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 = shift; - my $posValue = shift; - - if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 1 - && $shutters->getVentilateOpen eq 'on' ) - { - $posValue = $shutters->getVentilatePos; - } - elsif (CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && $shutters->getSubTyp eq 'threestate' - && $ascDev->getAutoShuttersControlComfort eq 'on' ) - { - $posValue = $shutters->getComfortOpenPos; - } - elsif ( - CheckIfShuttersWindowRecOpen($shuttersDev) == 2 - && ( $shutters->getSubTyp eq 'threestate' - || $shutters->getSubTyp eq 'twostate' ) - && $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' ); - } - - return; -} - -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, $value5, $value6, $value7, $value8 ); - ( $value3, $value4 ) = split( ':', $values[1] ) - if ( defined( $values[1] ) ); - ( $value5, $value6 ) = split( ':', $values[2] ) - if ( defined( $values[2] ) ); - ( $value7, $value8 ) = split( ':', $values[3] ) - 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} ) - && $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 = shift; - - $shutters->setShuttersDev($shuttersDev); - - my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) > - ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 ); - my $respIsDay = $isday; - - ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay ); - - if ( - ( - $shutters->getDown eq 'brightness' - || $shutters->getUp eq 'brightness' - ) - || ( - ( - ( - ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', - $shutters->getTimeUpEarly ) / 86400 - ) - && !IsWe() - ) - || ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ) / 86400 - ) - && IsWe() - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' - ) - ) - && int( gettimeofday() / 86400 ) == int( - computeAlignTime( '24:00', $shutters->getTimeUpLate ) / - 86400 - ) - ) - || ( - int( gettimeofday() / 86400 ) != int( - computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / - 86400 - ) - && 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 - && $isday - && !$shutters->getSunset - ) - || !$shutters->getSunset - ) ? 1 : 0 - ) if ( $shutters->getDown eq 'brightness' ); - - ASC_Debug( 'FnIsDay nach Sonnenuntergang / Abends: ' - . $shuttersDev - . ' getDownBrightness: ' - . $respIsDay - . ' Brightness: ' - . $shutters->getBrightness - . ' BrightnessMin: ' - . $brightnessMinVal - . ' Sunset: ' - . $shutters->getSunset - . ' isday: ' - . $isday ); - - ##### Nach Sonnenauf / Morgens - $respIsDay = ( - ( - ( - $shutters->getBrightness > $brightnessMaxVal - && !$isday - && $shutters->getSunrise - ) - || $respIsDay - || $shutters->getSunrise - ) ? 1 : 0 - ) if ( $shutters->getUp eq 'brightness' ); - - ASC_Debug( 'FnIsDay nach Sonnenaufgang / Morgens: ' - . $shuttersDev - . ' getUpBrightness: ' - . $respIsDay - . ' Brightness: ' - . $shutters->getBrightness - . ' BrightnessMax: ' - . $brightnessMaxVal - . ' Sunrise: ' - . $shutters->getSunrise - . ' isday: ' - . $isday ); - } - - return $respIsDay; -} - -sub ShuttersSunrise { - my $shuttersDev = shift; - my $tm = shift; # 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() || IsWe('tomorrow') ) - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' ) - { - if ( !IsWe('tomorrow') ) { - if ( - IsWe() - && 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() - && ( - int( gettimeofday() / 86400 ) == int( - ( - computeAlignTime( - '24:00', - sunrise_abs( - $autoAstroMode, 0, - $shutters->getTimeUpWeHoliday - ) - ) + 1 - ) / 86400 - ) - || 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) - && ref($oldFuncHash) eq 'HASH' - && ( IsWe() || IsWe('tomorrow') ) - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' ) - { - if ( !IsWe('tomorrow') ) { - 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 ) - && $oldFuncHash->{sunrisetime} < gettimeofday() ); - } - } - } - elsif ( defined($oldFuncHash) && ref($oldFuncHash) eq 'HASH' ) { - $shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 ) - if ( $shuttersSunriseUnixtime < - ( $oldFuncHash->{sunrisetime} + 180 ) - && $oldFuncHash->{sunrisetime} < gettimeofday() ); - } - } - elsif ( $shutters->getUp eq 'time' ) { - if ( ( IsWe() || IsWe('tomorrow') ) - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' ) - { - if ( !IsWe('tomorrow') ) { - 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 - ) - && $shutters->getSunrise - ) - { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', $shutters->getTimeUpEarly ) - + 86400; - } - else { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', - $shutters->getTimeUpEarly ); - } - } - else { - if ( - IsWe() - && 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' ) { - if ( ( IsWe() || IsWe('tomorrow') ) - && $ascDev->getSunriseTimeWeHoliday eq 'on' - && $shutters->getTimeUpWeHoliday ne '01:25' ) - { - if ( !IsWe('tomorrow') ) { - if ( - IsWe() - && 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->getTimeUpLate - ) - ) / 86400 - ) - ) - { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ); - } - else { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', $shutters->getTimeUpLate ); - } - } - else { - if ( - IsWe() - && ( - int( gettimeofday() / 86400 ) == int( - ( - computeAlignTime( - '24:00', $shutters->getTimeUpWeHoliday - ) - ) / 86400 - ) - || 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->getTimeUpLate - ) - ) / 86400 - ) - ) - { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', $shutters->getTimeUpLate ); - } - else { - if ( - int( gettimeofday() / 86400 ) == int( - ( - computeAlignTime( - '24:00', $shutters->getTimeUpWeHoliday - ) - ) / 86400 - ) - ) - { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ); - } - else { - $shuttersSunriseUnixtime = - computeAlignTime( '24:00', - $shutters->getTimeUpWeHoliday ); - } - } - } - } - else { - - $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' ); - } - - return; -} - -sub IsAfterShuttersTimeBlocking { - my $shuttersDev = shift; - - $shutters->setShuttersDev($shuttersDev); - - if ( - ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < - $shutters->getBlockingTimeAfterManual - || ( !$shutters->getIsDay - && defined( $shutters->getSunriseUnixTime ) - && $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) < - $shutters->getBlockingTimeBeforDayOpen ) - || ( $shutters->getIsDay - && defined( $shutters->getSunriseUnixTime ) - && $shutters->getSunsetUnixTime - ( int( gettimeofday() ) ) < - $shutters->getBlockingTimeBeforNightClose ) - ) - { - return 0; - } - - else { return 1 } -} - -sub IsAfterShuttersManualBlocking { - my $shuttersDev = shift; - $shutters->setShuttersDev($shuttersDev); - - if ( $ascDev->getBlockAscDrivesAfterManual - && $shutters->getStatus != $shutters->getOpenPos - && $shutters->getStatus != $shutters->getClosedPos - && $shutters->getStatus != $shutters->getWindPos - && $shutters->getStatus != $shutters->getShadingPos - && $shutters->getStatus != $shutters->getComfortOpenPos - && $shutters->getStatus != $shutters->getVentilatePos - && $shutters->getStatus != $shutters->getAntiFreezePos - && $shutters->getLastDrive eq 'manual' ) - { - return 0; - } - elsif ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < - $shutters->getBlockingTimeAfterManual ) - { - return 0; - } - - else { return 1 } -} - -sub ShuttersSunset { - my $shuttersDev = shift; - my $tm = shift; # 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) && ref($oldFuncHash) eq 'HASH' ) { - $shuttersSunsetUnixtime += 86400 - if ( $shuttersSunsetUnixtime < - ( $oldFuncHash->{sunsettime} + 180 ) - && $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' ); - } - - return; -} - -## Kontrolliert ob das Fenster von einem bestimmten Rolladen offen ist -sub CheckIfShuttersWindowRecOpen { - my $shuttersDev = shift; - $shutters->setShuttersDev($shuttersDev); - - if ( $shutters->getWinStatus =~ - m{[Oo]pen|false}xms ) # CK: covers: open|opened - { - return 2; - } - elsif ($shutters->getWinStatus =~ m{tilt}xms - && $shutters->getSubTyp eq 'threestate' ) # CK: covers: tilt|tilted - { - return 1; - } - elsif ( $shutters->getWinStatus =~ m{[Cc]lose|true}xms ) { - return 0; - } # CK: covers: close|closed -} - -sub makeReadingName { - my ($rname) = shift; - 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{^\./}xms ); - $rname =~ s/([$charHashkeys])/$charHash{$1}/xgi; - $rname =~ s/[^a-z0-9._\-\/]/_/xgi; - return $rname; -} - -sub TimeMin2Sec { - my $min = shift; - my $sec; - - $sec = $min * 60; - return $sec; -} - -sub IsWe { - return main::IsWe( shift, shift ); -} - -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' - && $ascDev->getASCenable eq 'on' - && ( $idleDetection =~ m{^$idleDetectionValue$}xms - || $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 (!$shutters->getSelfDefenseAbsent - && $shutters->getSelfDefenseAbsentTimerrun ); - - return; -} - -sub _setShuttersLastDriveDelayed { - my $h = shift; - - my $shuttersDevHash = $h->{devHash}; - my $lastDrive = $h->{lastDrive}; - - readingsSingleUpdate( $shuttersDevHash, 'ASC_ShuttersLastDrive', - $lastDrive, 1 ); - - return; -} - -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" - ) - ); - - return; -} - -sub _averageBrightness { - my @input = @_; - use List::Util qw(sum); - - return int( sum(@input) / @input ); -} - -sub _perlCodeCheck { - my $exec = shift; - my $val = undef; - - if ( $exec =~ m{^\{(.+)\}$}xms ) { - $val = main::AnalyzePerlCommand( undef, $1 ); - } - - return $val; -} - -sub PrivacyUpTime { - my $shuttersDevHash = shift; - my $shuttersSunriseUnixtime = shift; - - my $privacyUpUnixtime; - - if ( ( $shuttersSunriseUnixtime - $shutters->getPrivacyUpTime ) > - ( gettimeofday() + 1 ) - || $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 = shift; - my $shuttersSunsetUnixtime = shift; - - my $privacyDownUnixtime; - - if ( ( $shuttersSunsetUnixtime - $shutters->getPrivacyDownTime ) > - ( gettimeofday() + 1 ) - || $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 = shift; - - $hash = $defs{$hash} if ( ref($hash) ne 'HASH' ); - - return 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 ) =~ m{.*asleep$}xms ) { - return '.*:scene_sleeping'; - } - elsif ( ReadingsVal( $name, 'state', undef ) =~ - m{^roommate(.come)?.(awoken|home)$}xms ) - { - return '.*:user_available'; - } - elsif ( ReadingsVal( $name, 'state', undef ) =~ - m{^residents.(home|awoken)$}xms ) - { - 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 ) =~ m{^selfDefense.*.active$}xms ) - { - 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 ) =~ m{.*privacy.*}xms ) { - return '.*:fts_shutter_50'; - } - elsif ( ReadingsVal( $name, 'state', undef ) eq 'adv delay close' ) { - return '.*:christmas_tree'; - } - - return; -} - -###################################### -###################################### -########## 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 utf8; - -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 = shift; - my $shuttersDev = shift; - - $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; -} - -sub setHardLockOut { - my $self = shift; - my $cmd = shift; - - if ( $shutters->getLockOut eq 'hard' - && $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; -} - -sub setNoDelay { - my $self = shift; - my $noDelay = shift; - - $self->{ $self->{shuttersDev} }{noDelay} = $noDelay; - return; -} - -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; -} - -sub setDriveCmd { - my $self = shift; - my $posValue = shift; - - my $offSet; - my $offSetStart; - - if ( - ( $shutters->getPartyMode eq 'on' && $ascDev->getPartyMode eq 'on' ) - || ( $shutters->getAdv - && !$shutters->getQueryShuttersPos($posValue) - && !$shutters->getAdvDelay - && !$shutters->getExternalTriggerState - && !$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 - && !$shutters->getSelfDefenseAbsentTimerrun - && $shutters->getSelfDefenseMode ne 'off' - && $shutters->getSelfDefenseState - && $ascDev->getSelfDefense eq 'on' ) - { - InternalTimer( - gettimeofday() + $shutters->getSelfDefenseAbsentDelay, - \&FHEM::AutoShuttersControl::_SetCmdFn, \%h ); - $shutters->setSelfDefenseAbsent( 1, 0, \%h ); - } - elsif ( $offSetStart > 0 && !$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 || $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; -} - -sub setSunsetUnixTime { - my $self = shift; - my $unixtime = shift; - - $self->{ $self->{shuttersDev} }{sunsettime} = $unixtime; - return; -} - -sub setSunset { - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }{sunset} = $value; - return; -} - -sub setSunriseUnixTime { - my $self = shift; - my $unixtime = shift; - - $self->{ $self->{shuttersDev} }{sunrisetime} = $unixtime; - return; -} - -sub setSunrise { - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }{sunrise} = $value; - return; -} - -sub setDelayCmd { - my $self = shift; - my $posValue = shift; - - $self->{ $self->{shuttersDev} }{delayCmd} = $posValue; - return; -} - -sub setLastDrive { - my $self = shift; - my $lastDrive = shift; - - $self->{ $self->{shuttersDev} }{lastDrive} = $lastDrive; - return; -} - -sub setPosSetCmd { - my $self = shift; - my $posSetCmd = shift; - - $self->{ $self->{shuttersDev} }{posSetCmd} = $posSetCmd; - return; -} - -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; -} - -sub setLastPos { - -# letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde - my $self = shift; - my $position = shift; - - $self->{ $self->{shuttersDev} }{lastPos}{VAL} = $position - if ( defined($position) ); - $self->{ $self->{shuttersDev} }{lastPos}{TIME} = int( gettimeofday() ) - if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) ); - return; -} - -sub setLastManPos { - my $self = shift; - my $position = shift; - - $self->{ $self->{shuttersDev} }{lastManPos}{VAL} = $position - if ( defined($position) ); - $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( gettimeofday() ) - if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) - && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); - $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = - int( gettimeofday() ) - 86400 - if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) - && !defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); - return; -} - -sub setDefault { - my $self = shift; - my $defaultarg = shift; - - $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); - return $self->{defaultarg}; -} - -sub setRoommate { - my $self = shift; - my $roommate = shift; - - $self->{roommate} = $roommate if ( defined($roommate) ); - return $self->{roommate}; -} - -sub setInTimerFuncHash { - my $self = shift; - my $inTimerFuncHash = shift; - - $self->{ $self->{shuttersDev} }{inTimerFuncHash} = $inTimerFuncHash - if ( defined($inTimerFuncHash) ); - return; -} - -sub setPrivacyDownStatus { - my $self = shift; - my $statusValue = shift; - - $self->{ $self->{shuttersDev} }->{privacyDownStatus} = $statusValue; - return; -} - -sub setPrivacyUpStatus { - my $self = shift; - my $statusValue = shift; - - $self->{ $self->{shuttersDev} }->{privacyUpStatus} = $statusValue; - return; -} - -sub setSelfDefenseState { - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }{selfDefenseState} = $value; - return; -} - -sub setAdvDelay { - my $self = shift; - my $advDelay = shift; - - $self->{ $self->{shuttersDev} }->{AdvDelay} = $advDelay; - return; -} - -sub getHomemode { - my $self = shift; - - my $homemode = $shutters->getRoommatesStatus; - $homemode = $ascDev->getResidentsStatus - if ( $homemode eq 'none' ); - return $homemode; -} - -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 = shift; - my $attr = shift; - - return ( - defined( $self->{ $self->{shuttersDev} }{AttrUpdateChanges} ) - && defined( - $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} ) - ? $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} - : 'none' - ); -} - -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) && $daytime - ? $daytime - : ( strftime( "%k", localtime() ) < 12 ? 'am' : 'pm' ) - ); - my $outTemp = $ascDev->getOutTemp; - $outTemp = $shutters->getOutTemp if ( $shutters->getOutTemp != -100 ); - - if ( $shutters->getAntiFreeze ne 'off' - && $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 = shift; - my $posValue = shift; # 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 ( - defined( $self->{ $self->{shuttersDev} }{selfDefenseState} ) - ? $self->{ $self->{shuttersDev} }{selfDefenseState} - : 0 - ); -} - -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 ( - defined( - $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} - ) - ? $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} - : undef - ); -} - -sub getLastDrive { - my $self = shift; - - $self->{ $self->{shuttersDev} }{lastDrive} = - ReadingsVal( $self->{shuttersDev}, 'ASC_ShuttersLastDrive', 'none' ) - if ( !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 ( - defined( $self->{ $self->{shuttersDev} }{lastPos} ) - && defined( $self->{ $self->{shuttersDev} }{lastPos}{VAL} ) - ? $self->{ $self->{shuttersDev} }{lastPos}{VAL} - : 50 - ); -} - -sub getLastPosTimestamp { - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} } ) - && defined( $self->{ $self->{shuttersDev} }{lastPos} ) - && defined( $self->{ $self->{shuttersDev} }{lastPos}{TIME} ) - ? $self->{ $self->{shuttersDev} }{lastPos}{TIME} - : 0 - ); -} - -sub getLastManPos -{ # letzte ermittelte Position bevor die Position des Rolladen manuell (nicht über ASC) geändert wurde - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} }{lastManPos} ) - && defined( $self->{ $self->{shuttersDev} }{lastManPos}{VAL} ) - ? $self->{ $self->{shuttersDev} }{lastManPos}{VAL} - : 50 - ); -} - -sub getLastManPosTimestamp { - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} } ) - && defined( $self->{ $self->{shuttersDev} }{lastManPos} ) - && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) - ? $self->{ $self->{shuttersDev} }{lastManPos}{TIME} - : 0 - ); -} - -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; - - for 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; - - for 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 = shift; - my $value = shift; ### Werte für value = in, out, in reserved, out reserved - - return - if ( defined($value) - && exists( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) - && $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} eq $value ); - - $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value - if ( defined($value) ); - $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = int( gettimeofday() ) - if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) ); - - return; -} - -sub setShadingLastStatus { - my $self = shift; - my $value = shift; ### Werte für value = in, out - - return - if ( defined($value) - && exists( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) - && $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} eq $value ); - - $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; -} - -sub setShadingManualDriveStatus { - my $self = shift; - my $value = shift; ### Werte für value = in, out - - $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = $value - if ( defined($value) ); - - return; -} - -sub setWindProtectionStatus { # Werte protected, unprotected - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value - if ( defined($value) ); - - return; -} - -sub setRainProtectionStatus { # Werte protected, unprotected - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} = $value - if ( defined($value) ); - return; -} - -sub setExternalTriggerState { - my $self = shift; - my $value = shift; - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} = $value - if ( defined($value) ); - - return; -} - -sub setPushBrightnessInArray { - my $self = shift; - my $value = shift; - - unshift( - @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} }, - $value - ); - pop( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) - if ( - scalar( - @{ - $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} - } - ) > $shutters->getMaxBrightnessAverageArrayObjects - ); - - return; -} - -sub getBrightnessAverage { - my $self = shift; - - return FHEM::AutoShuttersControl::_averageBrightness( - @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) - if ( - ref( $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} ) - eq 'ARRAY' - && scalar( - @{ - $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} - } - ) > 0 - ); - - return; -} - -sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) - && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) - ? $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} - : 'out' - ); -} - -sub getShadingLastStatus { # Werte für value = in, out - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) - && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) - ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} - : 'out' - ); -} - -sub getShadingManualDriveStatus { # Werte für value = 0, 1 - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus} ) - && defined( - $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} - ) - ? $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} - : 0 - ); -} - -sub getIfInShading { - my $self = shift; - - return ( - ( - $shutters->getShadingMode ne 'off' - && $shutters->getShadingLastStatus eq 'out' - ) ? 1 : 0 - ); -} - -sub getWindProtectionStatus { # Werte protected, unprotected - my $self = shift; - - return ( - ( - defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} ) - && 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} ) - && defined( - $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} - ) - ) - ? $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} - : 'unprotected' - ); -} - -sub getShadingStatusTimestamp { - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} } ) - && defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) - && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) - ? $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} - : 0 - ); -} - -sub getShadingLastStatusTimestamp { - my $self = shift; - - return ( - defined( $self->{ $self->{shuttersDev} } ) - && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) - && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} ) - ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} - : 0 - ); -} -### Ende Beschattung - -## Subklasse Attr von ASC_Shutters## -package ASC_Shutters::Attr; - -use strict; -use warnings; -use utf8; - -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 =~ m{^\d+(\.\d+)?$}xms ? $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} - ) - && ( 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 ) - && $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} - ) - && ( 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} - ) - && ( 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 ) - && $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} - ) - && ( 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 =~ m{^\d+(\.\d+)?$}xms ? $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 =~ m{^\d+(\.\d+)?$}xms ? $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 =~ m{^\d+(\.\d+)?$}xms - ? $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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} } - ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 - ); - $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} - ->{LASTGETTIME} = int( gettimeofday() ); - my ( $sunny, $cloudy, $maxBrightnessAverageArrayObjects ) = - FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, - 'ASC_Shading_StateChange_SunnyCloudy', - '35000:20000' ); - - ### erwartetes Ergebnis - # SUNNY:CLOUDY [BrightnessAverage] - - $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} - ->{sunny} = $sunny; - $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} - ->{cloudy} = $cloudy; - $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{MAXOBJECT} = ( - defined($maxBrightnessAverageArrayObjects) - && $maxBrightnessAverageArrayObjects ne 'none' - ? $maxBrightnessAverageArrayObjects - : 3 - ); - - 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} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} } - ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 - ); - $shutters->getShadingStateChangeSunny; - - return $self->{ $self->{shuttersDev} } - ->{ASC_Shading_StateChange_SunnyCloudy}->{cloudy}; -} - -sub getMaxBrightnessAverageArrayObjects { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{BrightnessAverageArray} - ->{MAXOBJECT} - if ( - exists( - $self->{ $self->{shuttersDev} } - ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} } - ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 - ); - $shutters->getShadingStateChangeSunny; - - return $self->{ $self->{shuttersDev} }->{BrightnessAverageArray} - ->{MAXOBJECT}; -} - -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} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} ) < 2 - ); - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{LASTGETTIME} = - int( gettimeofday() ); - my ( $device, $reading, $valueActive, $valueInactive, $posActive, - $posInactive, $valueActive2, $posActive2 ) - = FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev}, - 'ASC_ExternalTrigger', 'none' ); - - ### erwartetes Ergebnis -# DEVICE:READING VALUEACTIVE:VALUEINACTIVE POSACTIVE:POSINACTIVE VALUEACTIVE2:POSACTIVE2 - - $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 ); - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{valueactive2} = - $valueActive2; - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2} = - $posActive2; - - 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} - ) - && ( 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} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} ) < 2 - ); - $shutters->getExternalTriggerDevice; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{valueactive}; -} - -sub getExternalTriggerValueActive2 { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{valueactive2} - if ( - exists( - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} ) < 2 - ); - $shutters->getExternalTriggerDevice; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{valueactive2}; -} - -sub getExternalTriggerValueInactive { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{valueinactive} - if ( - exists( - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} - ) - && ( 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} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} ) < 2 - ); - $shutters->getExternalTriggerDevice; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive}; -} - -sub getExternalTriggerPosActive2 { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2} - if ( - exists( - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} - ) - && ( gettimeofday() - - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} ) < 2 - ); - $shutters->getExternalTriggerDevice; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2}; -} - -sub getExternalTriggerPosInactive { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posinactive} - if ( - exists( - $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} - ->{LASTGETTIME} - ) - && ( 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 =~ m{^\d+$}xms ? $val : -1 ); -} - -sub getDelayStart { - my $self = shift; - - my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_DelayStart', -1 ); - return ( ( $val > 0 && $val =~ m{^\d+$}xms ) ? $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 =~ m{^\d+(\.\d+)?$}xms - ? $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 =~ m{^\d+(\.\d+)?$}xms ? $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 =~ m{^\d+(\.\d+)?$}xms - ? $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} - ) - && ( 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} - ) - && ( 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} - ) - && ( 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', 'off' ); -} - -sub getRainProtection { - my $self = shift; - - return AttrVal( $self->{shuttersDev}, 'ASC_RainProtection', 'off' ); -} - -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', - 0 ); -} - -sub getAutoAstroModeEveningHorizon { - my $self = shift; - - return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon', - 0 ); -} - -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 =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms - ? $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 =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms - ? $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 =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms - ? $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 =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms - ? $val - : '22:00' - ); -} - -sub getTimeUpWeHoliday { - my $self = shift; - - my $val = - AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', '01:25' ); - - if ( defined( FHEM::AutoShuttersControl::_perlCodeCheck($val) ) ) { - $val = FHEM::AutoShuttersControl::_perlCodeCheck($val); - } - - return ( - $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms - ? $val - : '01:25' - ); -} - -sub getBrightnessMinVal { - my $self = shift; - - return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} - if ( - exists( - $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} - ->{LASTGETTIME} - ) - && ( 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} - ) - && ( 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 utf8; - -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 utf8; - -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} - ) - && ( 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} - ) - && ( 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 utf8; - -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 utf8; - -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 ( !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; -use utf8; - -sub new { - my $class = shift; - - my $self = { name => undef, }; - - bless $self, $class; - return $self; -} - -sub setName { - my $self = shift; - my $name = shift; - - $self->{name} = $name if ( defined($name) ); - return $self->{name}; -} - -sub setDefault { - my $self = shift; - my $defaultarg = shift; - - $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 utf8; - -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; -} - -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; -} - -sub setPosReading { - my $self = shift; - - my $name = $self->{name}; - my $hash = $defs{$name}; - - readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_PosValue', - $shutters->getStatus, 1 ); - return; -} - -sub setLastPosReading { - my $self = shift; - - my $name = $self->{name}; - my $hash = $defs{$name}; - - readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_lastPosValue', - $shutters->getLastPos, 1 ); - return; -} - -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{^(?:(.+)_)?(.+)$}xms ) { - 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{^(?:(.+)_)?(.+)$}xms ) { - 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 utf8; - -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} ) - && ( 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} ) - && ( 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} ) - && ( 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 - $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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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} ) - && ( 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.32", - "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 diff --git a/FHEM/73_AutoShuttersControl.pm b/FHEM/73_AutoShuttersControl.pm new file mode 100644 index 0000000..5b063dc --- /dev/null +++ b/FHEM/73_AutoShuttersControl.pm @@ -0,0 +1,1303 @@ +############################################################################### +# +# 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 FHEM::AutoShuttersControl; + +use strict; +use warnings; +use utf8; + +use FHEM::Automation::ShuttersControl; +use GPUtils qw(GP_Import GP_Export); + +## Import der FHEM Funktionen +#-- Run before package compilation +BEGIN { + # Import from main context + GP_Import( + qw( + readingFnAttributes + ) + ); + + #-- Export to main context with different name + GP_Export( + qw( + Initialize + ) + ); +} + +sub Initialize { + my $hash = shift; + +## 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::Automation::ShuttersControl::Set; + $hash->{GetFn} = \&FHEM::Automation::ShuttersControl::Get; + $hash->{DefFn} = \&FHEM::Automation::ShuttersControl::Define; + $hash->{NotifyFn} = \&FHEM::Automation::ShuttersControl::Notify; + $hash->{UndefFn} = \&FHEM::Automation::ShuttersControl::Undef; + $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 ' + . 'ASC_slatDriveCmdInverse:0,1 ' + . $readingFnAttributes; + $hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn + $hash->{FW_detailFn} = + \&FHEM::Automation::ShuttersControl::ShuttersInformation; + $hash->{parseParams} = 1; + + return FHEM::Meta::InitMod( __FILE__, $hash ); +} + +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.9.25", + "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 diff --git a/controls_AutoShuttersControl.txt b/controls_AutoShuttersControl.txt new file mode 100644 index 0000000..9a96fdd --- /dev/null +++ b/controls_AutoShuttersControl.txt @@ -0,0 +1,12 @@ +UPD 2020-06-22_09:41:40 97568 FHEM/73_AutoShuttersControl.pm +UPD 2020-06-22_09:41:40 187057 lib/FHEM/Automation/ShuttersControl.pm +UPD 2020-06-22_09:41:40 2657 lib/FHEM/Automation/ShuttersControl/Dev.pm +UPD 2020-06-22_09:41:40 2493 lib/FHEM/Automation/ShuttersControl/Roommate.pm +UPD 2020-06-22_09:41:40 29833 lib/FHEM/Automation/ShuttersControl/Shutters.pm +UPD 2020-06-22_09:41:40 2175 lib/FHEM/Automation/ShuttersControl/Window.pm +UPD 2020-06-22_09:41:40 11454 lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm +UPD 2020-06-22_09:41:40 7251 lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm +UPD 2020-06-22_09:41:40 52661 lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm +UPD 2020-06-22_09:41:40 2903 lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm +UPD 2020-06-22_09:41:40 3972 lib/FHEM/Automation/ShuttersControl/Window/Attr.pm +UPD 2020-06-22_09:41:40 2288 lib/FHEM/Automation/ShuttersControl/Window/Readings.pm diff --git a/lib/FHEM/Automation/ShuttersControl.pm b/lib/FHEM/Automation/ShuttersControl.pm new file mode 100644 index 0000000..87e7377 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl.pm @@ -0,0 +1,5021 @@ +############################################################################### +# +# Developed with Kate +# +# (c) 2018-2020 Copyright: Marko Oldenburg (fhemsupport@cooltux.net) +# 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; +use utf8; + +sub ascAPIget { + my ( $getCommand, $shutterDev, $value ) = @_; + + return ShuttersControl_ascAPIget( $getCommand, $shutterDev, $value ); +} + +sub ascAPIset { + my ( $setCommand, $shutterDev, $value ) = @_; + + return ShuttersControl_ascAPIset( $setCommand, $shutterDev, $value ); +} + +## unserer packagename +package FHEM::Automation::ShuttersControl; + +use strict; +use warnings; +use POSIX qw(strftime); +use utf8; + +use Encode; +use FHEM::Meta; +use GPUtils qw(GP_Import GP_Export); +use Data::Dumper; #only for Debugging +use Date::Parse; + +use FHEM::Automation::ShuttersControl::Shutters; +use FHEM::Automation::ShuttersControl::Dev; + +require Exporter; +our @ISA = qw(Exporter); +our @Export = qw($shutters $ascDev %userAttrList); + +# 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( + ascAPIget + ascAPIset + DevStateIcon + ) + ); +} + +## Die Attributsliste welche an die Rolläden verteilt wird. Zusammen mit Default Werten +our %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' => [ '', -1, -1 ], + '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' => [ '', 50, 50 ], + 'ASC_PrivacyDown_Pos' => [ '', 50, 50 ], + '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' => '-', + 'ASC_SlatPosCmd_SlatDevice' => '-', +); + +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', +); + +## 2 Objekte werden erstellt +our $shutters = FHEM::Automation::ShuttersControl::Shutters->new(); +our $ascDev = FHEM::Automation::ShuttersControl::Dev->new(); + +sub ascAPIget { + my ( $getCommand, $shutterDev, $value ) = @_; + + my $getter = 'get' . $getCommand; + + if ( defined($value) && $value ) { + $shutters->setShuttersDev($shutterDev); + return $shutters->$getter($value); + } + elsif ( defined($shutterDev) && $shutterDev ) { + $shutters->setShuttersDev($shutterDev); + return $shutters->$getter; + } + else { + return $ascDev->$getter; + } + + return; +} + +sub ascAPIset { + my ( $setCommand, $shutterDev, $value ) = @_; + + my $setter = 'set' . $setCommand; + + if ( defined($shutterDev) + && $shutterDev + && defined($value) + && $value ) + { + $shutters->setShuttersDev($shutterDev); + $shutters->$setter($value); + } + + return; +} + +sub Define { + my $hash = shift // return; + my $aArg = shift // return; + + 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 ( scalar( @{$aArg} ) != 2 ); + + my $name = shift @$aArg; + $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 { ShuttersControl_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; +} + +sub Undef { + my $hash = shift; + my $name = shift; + + 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; +} + +sub Notify { + my $hash = shift // return; + my $dev = shift // return; + + 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 m{^DEFINED.$name$}xms, + @{$events} && $devname eq 'global' && $init_done + ) + || ( + grep m{^INITIALIZED$}xms, + @{$events} or grep m{^REREADCFG$}xms, + @{$events} or grep m{^MODIFIED.$name$}xms, + @{$events} + ) + && $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 { ShuttersControl_DevStateIcon($name) }' ) + unless ( + AttrVal( + $name, 'devStateIcon', + '{ ShuttersControl_DevStateIcon($name) }' + ) eq '{ ShuttersControl_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' + && scalar( @{ $hash->{helper}{shuttersList} } ) > 0 ); + + my $posReading = $shutters->getPosCmd; + + if ( $devname eq $name ) { + if ( grep m{^userAttrList:.rolled.out$}xms, @{$events} ) { + unless ( scalar( @{ $hash->{helper}{shuttersList} } ) == 0 ) { + WriteReadingsShuttersList($hash); + UserAttributs_Readings_ForShutters( $hash, 'add' ); + InternalTimer( + gettimeofday() + 3, +'FHEM::Automation::ShuttersControl::RenewSunRiseSetShuttersTimer', + $hash + ); + InternalTimer( + gettimeofday() + 5, + 'FHEM::Automation::ShuttersControl::AutoSearchTwilightDev', + $hash + ); + InternalTimer( + gettimeofday() + 5, + sub() { CommandSet( undef, $name . ' controlShading on' ) }, + $hash + ) + if ( ReadingsVal( $name, 'controlShading', 'off' ) ne 'off' ); + } + } + elsif ( grep m{^partyMode:.off$}xms, @{$events} ) { + EventProcessingPartyMode($hash); + } + elsif ( grep m{^sunriseTimeWeHoliday:.(on|off)$}xms, @{$events} ) { + RenewSunRiseSetShuttersTimer($hash); + } + } + elsif ( $devname eq "global" ) + { # Kommt ein globales Event und beinhaltet folgende Syntax wird die Funktion zur Verarbeitung aufgerufen + if ( + grep +m{^(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_tempSensor|.*ASC_BrightnessSensor|.*ASC_twilightDevice|.*ASC_ExternalTrigger)(\s.*|$)}xms, + @{$events} + ) + { + EventProcessingGeneral( $hash, undef, join( ' ', @{$events} ) ); + } + } + elsif ( grep m{^($posReading):\s\d{1,3}$}xms, @{$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) && ($devname) ) + { # es wird lediglich der Devicename der Funktion mitgegeben wenn es sich nicht um global handelt daher hier die Unterscheidung + 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' + && ( $shutters->getDown eq 'brightness' + || $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(.*)$}xms + ) + { # 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) + $}xms + ) + { # 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) + (.*)?}xms + ) + { + CreateSunRiseSetShuttersTimer( $hash, $2 ) + if ( + $3 ne 'ASC_Time_Up_WE_Holiday' + || ( $3 eq 'ASC_Time_Up_WE_Holiday' + && $ascDev->getSunriseTimeWeHoliday eq 'on' ) + ); + } + elsif ( + $events =~ m{^(DELETEATTR|ATTR) + \s(.*)\s(ASC_autoAstroModeMorning|ASC_autoAstroModeMorningHorizon + |ASC_autoAstroModeEvening|ASC_autoAstroModeEveningHorizon) + (.*)?}xms + ) + { + RenewSunRiseSetShuttersTimer($hash); + } + + if ( + $events =~ +m{^(DELETEATTR|ATTR) #global ATTR myASC ASC_tempSensor Cellar + \s(.*)\s(ASC_tempSensor + |ASC_Shading_Mode + |ASC_BrightnessSensor + |ASC_TempSensor) + (.*)?}xms + ) + { + CommandSet( undef, $name . ' controlShading on' ) + if ( ReadingsVal( $name, 'controlShading', 'off' ) ne 'off' ); + } + } + + return; +} + +sub Set { + my $hash = shift // return; + my $aArg = shift // return; + + my $name = shift @$aArg; + my $cmd = shift @$aArg + // return qq{"set $name" needs at least one argument}; + + if ( lc $cmd eq 'renewalltimer' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 ); + RenewSunRiseSetShuttersTimer($hash); + } + elsif ( lc $cmd eq 'renewtimer' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + CreateSunRiseSetShuttersTimer( $hash, $aArg->[0] ); + } + elsif ( lc $cmd eq 'scanforshutters' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 ); + ShuttersDeviceScan($hash); + } + elsif ( lc $cmd eq 'createnewnotifydev' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 ); + CreateNewNotifyDev($hash); + } + elsif ( lc $cmd eq 'partymode' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( $hash, $cmd, $aArg->[0], 1 ) + if ( $aArg->[0] ne ReadingsVal( $name, 'partyMode', 0 ) ); + } + elsif ( lc $cmd eq 'hardlockout' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( $hash, $cmd, $aArg->[0], 1 ); + HardewareBlockForShutters( $hash, $aArg->[0] ); + } + elsif ( lc $cmd eq 'sunrisetimeweholiday' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( $hash, $cmd, $aArg->[0], 1 ); + } + elsif ( lc $cmd eq 'controlshading' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + + my $response = _CheckASC_ConditionsForShadingFn($hash); + readingsSingleUpdate( + $hash, $cmd, + ( + $aArg->[0] eq 'off' ? $aArg->[0] + : ( + $response eq 'none' ? $aArg->[0] + : $response + ) + ), + 1 + ); + } + elsif ( lc $cmd eq 'selfdefense' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( $hash, $cmd, $aArg->[0], 1 ); + } + elsif ( lc $cmd eq 'ascenable' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( $hash, $cmd, $aArg->[0], 1 ); + } + elsif ( lc $cmd eq 'advdrivedown' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 ); + EventProcessingAdvShuttersClose($hash); + } + elsif ( lc $cmd eq 'shutterascenabletoggle' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + readingsSingleUpdate( + $defs{ $aArg->[0] }, + 'ASC_Enable', + ( + ReadingsVal( $aArg->[0], 'ASC_Enable', 'off' ) eq 'on' + ? 'off' + : 'on' + ), + 1 + ); + } + elsif ( lc $cmd eq 'wiggle' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) > 1 ); + + ( + $aArg->[0] eq 'all' + ? wiggleAll($hash) + : wiggle( $hash, $aArg->[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' + && defined( $hash->{helper}{shuttersList} ) + && scalar( @{ $hash->{helper}{shuttersList} } ) > 0 ); + $list .= ' createNewNotifyDev:noArg' + if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' + && AttrVal( $name, 'ASC_expert', 0 ) == 1 ); + + return "Unknown argument $cmd,choose one of $list"; + } + return; +} + +sub Get { + my $hash = shift // return; + my $aArg = shift // return; + + my $name = shift @$aArg // return; + my $cmd = shift @$aArg + // return qq{"get $name" needs at least one argument}; + + if ( lc $cmd eq 'shownotifydevsinformations' ) { + return "usage: $cmd" if ( scalar( @{$aArg} ) != 0 ); + my $ret = GetMonitoredDevs($hash); + return $ret; + } + else { + my $list = ""; + $list .= " showNotifyDevsInformations:noArg" + if ( ReadingsVal( $name, 'userAttrList', 'none' ) eq 'rolled out' + && 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 = ''; + for my $shuttersDev (@list) { + push( @{ $hash->{helper}{shuttersList} }, $shuttersDev ) + ; ## einem Hash wird ein Array zugewiesen welches die Liste der erkannten Rollos beinhaltet + + $shutters->setShuttersDev($shuttersDev); + + #### 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( + $shuttersDev, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, + 0 + ) == 0 + ) + { +# $shutters->setAttrUpdateChanges( 'ASC_Up', +# AttrVal( $shuttersDev, 'ASC_Up', 'none' ) ); +# delFromDevAttrList( $shuttersDev, 'ASC_Up' ); +# $shutters->setAttrUpdateChanges( 'ASC_Down', +# AttrVal( $shuttersDev, 'ASC_Down', 'none' ) ); +# delFromDevAttrList( $shuttersDev, 'ASC_Down' ); +# $shutters->setAttrUpdateChanges( 'ASC_Self_Defense_Mode', +# AttrVal( $shuttersDev, 'ASC_Self_Defense_Mode', 'none' ) ); +# delFromDevAttrList( $shuttersDev, 'ASC_Self_Defense_Mode' ); +# $shutters->setAttrUpdateChanges( 'ASC_Self_Defense_Exclude', +# AttrVal( $shuttersDev, 'ASC_Self_Defense_Exclude', 'none' ) ); +# delFromDevAttrList( $shuttersDev, 'ASC_Self_Defense_Exclude' ); + } + + #### + #### + + $shuttersList = $shuttersList . ',' . $shuttersDev; + $shutters->setLastManPos( $shutters->getStatus ); + $shutters->setLastPos( $shutters->getStatus ); + $shutters->setDelayCmd('none'); + $shutters->setNoDelay(0); + $shutters->setSelfDefenseAbsent( 0, 0 ); + $shutters->setPosSetCmd( $posSetCmds{ $defs{$shuttersDev}->{TYPE} } ); + $shutters->setShadingStatus( + ( $shutters->getStatus != $shutters->getShadingPos ? 'out' : 'in' ) + ); + +# $shutters->setShadingLastStatus( +# ( $shutters->getStatus != $shutters->getShadingPos ? 'in' : 'out' ) +# ); + $shutters->setPushBrightnessInArray( $shutters->getBrightness ); + readingsSingleUpdate( $defs{$shuttersDev}, 'ASC_Enable', 'on', 0 ) + if ( ReadingsVal( $shuttersDev, '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 ( my $shuttersDev = each %{ $hash->{monitoredDevs} } ) { + $notifyDevString .= ',' . $shuttersDev; + } + $hash->{NOTIFYDEV} = $notifyDevString; + } + + readingsSingleUpdate( $hash, 'userAttrList', 'rolled out', 1 ); + + return; +} + +## 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); + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + readingsBulkUpdate( + $hash, + 'room_' + . makeReadingName( AttrVal( $shuttersDev, 'room', 'unsorted' ) ), + ReadingsVal( + $name, + 'room_' + . makeReadingName( + AttrVal( $shuttersDev, 'room', 'unsorted' ) + ), + '' + ) + . ',' + . $shuttersDev + ) + if ( + ReadingsVal( + $name, + 'room_' + . makeReadingName( + AttrVal( $shuttersDev, 'room', 'unsorted' ) + ), + 'none' + ) ne 'none' + ); + + readingsBulkUpdate( + $hash, + 'room_' + . makeReadingName( AttrVal( $shuttersDev, 'room', 'unsorted' ) ), + $shuttersDev + ) + if ( + ReadingsVal( + $name, + 'room_' + . makeReadingName( + AttrVal( $shuttersDev, 'room', 'unsorted' ) + ), + 'none' + ) eq 'none' + ); + } + readingsBulkUpdate( $hash, 'state', 'active' ); + readingsEndUpdate( $hash, 0 ); + + return; +} + +sub UserAttributs_Readings_ForShutters { + my $hash = shift; + my $cmd = shift; + + my $name = $hash->{NAME}; + + while ( my ( $attrib, $attribValue ) = each %{userAttrList} ) { + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + addToDevAttrList( $shuttersDev, $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{$shuttersDev}{ ( split( ':', $attrib ) )[0] } = + $attribValue + if ( + !defined( + $attr{$shuttersDev}{ ( split( ':', $attrib ) )[0] } + ) + && $attribValue ne '-' + ); + } + else { + $attr{$shuttersDev}{ ( split( ':', $attrib ) )[0] } = + $attribValue->[ AttrVal( $shuttersDev, 'ASC', 2 ) ] + if ( + !defined( + $attr{$shuttersDev}{ ( split( ':', $attrib ) )[0] } + ) + && $attrib eq 'ASC_Pos_Reading' + ); + } + + ### associatedWith damit man sieht das der Rollladen mit einem ASC Device verbunden ist + my $associatedString = + ReadingsVal( $shuttersDev, 'associatedWith', 'none' ); + if ( $associatedString ne 'none' ) { + my %hash; + %hash = map { ( $_ => 1 ) } + split( ',', "$associatedString,$name" ); + + readingsSingleUpdate( $defs{$shuttersDev}, + 'associatedWith', join( ',', sort keys %hash ), 0 ); + } + else { + readingsSingleUpdate( $defs{$shuttersDev}, + 'associatedWith', $name, 0 ); + } + ####################################### + } + ## Oder das Attribut wird wieder gelöscht. + elsif ( $cmd eq 'del' ) { + $shutters->setShuttersDev($shuttersDev); + + RemoveInternalTimer( $shutters->getInTimerFuncHash ); + CommandDeleteReading( undef, $shuttersDev . ' .?(ASC)_.*' ); + CommandDeleteAttr( undef, $shuttersDev . ' ASC' ); + delFromDevAttrList( $shuttersDev, $attrib ); + + ### associatedWith wird wieder entfernt + my $associatedString = + ReadingsVal( $shuttersDev, 'associatedWith', 'none' ); + my %hash; + %hash = map { ( $_ => 1 ) } + grep { " $name " !~ m{ $shuttersDev }xms } + split( ',', "$associatedString,$name" ); + + if ( keys %hash > 1 ) { + readingsSingleUpdate( $defs{$shuttersDev}, + 'associatedWith', join( ',', sort keys %hash ), 0 ); + } + else { + CommandDeleteReading( undef, + $shuttersDev . ' associatedWith' ); + } + ################################### + } + } + } + + return; +} + +## Fügt dem NOTIFYDEV Hash weitere Devices hinzu +sub AddNotifyDev { + ### Beispielaufruf: AddNotifyDev( $hash, $3, $1, $2 ) if ( $3 ne 'none' ); + my ( $hash, $attrVal, $shuttersDev, $shuttersAttr ) = @_; + + $attrVal = ( split( ':', $attrVal ) )[0]; + my ( $key, $value ) = split( ':', ( split( ' ', $attrVal ) )[0], 2 ) + ; ## Wir versuchen die Device Attribute anders zu setzen. device=DEVICE reading=READING + $attrVal = $key; + + my $name = $hash->{NAME}; + + my $notifyDev = $hash->{NOTIFYDEV}; + $notifyDev = '' if ( !$notifyDev ); + + my %hash; + %hash = map { ( $_ => 1 ) } + split( ',', "$notifyDev,$attrVal" ); + + $hash->{NOTIFYDEV} = join( ',', sort keys %hash ); + + my @devs = split( ',', $attrVal ); + for my $dev (@devs) { + $hash->{monitoredDevs}{$dev}{$shuttersDev} = $shuttersAttr; + } + + readingsSingleUpdate( $hash, '.monitoredDevs', + eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); + + return; +} + +## 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 ); + + for my $notifyDev ( keys( %{$notifyDevs} ) ) { + Log3( $name, 4, + "AutoShuttersControl ($name) - DeleteNotifyDev - NotifyDev: " + . $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{ $_ }xms } + split( ',', "$notifyDevString,$notifyDev" ); + + $hash->{NOTIFYDEV} = join( ',', sort keys %hash ); + } + } + readingsSingleUpdate( $hash, '.monitoredDevs', + eval { encode_json( $hash->{monitoredDevs} ) }, 0 ); + + return; +} + +## 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)}xms + && 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 =~ m{[Cc]lose|true}xms + && $shutters->getShuttersPlace eq 'terrace' ); + $shutters->setHardLockOut('on') + if ( $match =~ m{[Oo]pen|false}xms + && $shutters->getShuttersPlace eq 'terrace' ); + + ASC_Debug( 'EventProcessingWindowRec: ' + . $shutters->getShuttersDev + . ' - HOMEMODE: ' + . $homemode + . ' QueryShuttersPosWinRecTilted:' + . $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) + . ' QueryShuttersPosWinRecComfort: ' + . $shutters->getQueryShuttersPos( $shutters->getComfortOpenPos ) + ); + + if ( + $match =~ m{[Cc]lose|true}xms + && IsAfterShuttersTimeBlocking($shuttersDev) + && ( + $shutters->getStatus == $shutters->getVentilatePos + || $shutters->getStatus == $shutters->getComfortOpenPos + || $shutters->getStatus == $shutters->getOpenPos + || ( $shutters->getStatus == $shutters->getPrivacyDownPos + && $shutters->getPrivacyDownStatus == 1 + && !$shutters->getIsDay ) + ) + && ( $shutters->getVentilateOpen eq 'on' + || $ascDev->getAutoShuttersControlComfort eq 'on' ) + ) + { + ASC_Debug( 'EventProcessingWindowRec: ' + . $shutters->getShuttersDev + . ' Event Closed' ); + + if ( + $shutters->getIsDay + && ( ( $homemode ne 'asleep' && $homemode ne 'gotosleep' ) + || $homemode eq 'none' ) + && $shutters->getModeUp ne 'absent' + && $shutters->getModeUp ne 'off' + ) + { + if ( $shutters->getIfInShading + && $shutters->getShadingPos != $shutters->getStatus + && $shutters->getShadingMode ne 'absent' ) + { + $shutters->setLastDrive('shading in'); + $shutters->setNoDelay(1); + $shutters->setDriveCmd( $shutters->getShadingPos ); + } + elsif ( + !$shutters->getIfInShading + && ( $shutters->getStatus != $shutters->getOpenPos + || $shutters->getStatus != $shutters->getLastManPos ) + ) + { + if ( $shutters->getPrivacyDownStatus == 2 ) { + $shutters->setLastDrive( + 'window closed at privacy night close'); + $shutters->setNoDelay(1); + $shutters->setDriveCmd( $shutters->getPrivacyDownPos ); + } + 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' + && $shutters->getModeDown ne 'off' + && ( + ( + !$shutters->getIsDay + && $shutters->getModeDown ne 'roommate' + ) + || $homemode eq 'asleep' + || $homemode eq 'gotosleep' + ) + && $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 =~ m{tilt}xms || ( $match =~ m{[Oo]pen|false}xms + && $shutters->getSubTyp eq 'twostate' ) + ) + && $shutters->getVentilateOpen eq 'on' + && $shutters->getQueryShuttersPos( $shutters->getVentilatePos ) + ) + { + $shutters->setLastDrive('ventilate - window open'); + $shutters->setNoDelay(1); + $shutters->setDriveCmd( + ( + ( + $shutters->getShuttersPlace eq 'terrace' + && $shutters->getSubTyp eq 'twostate' + ) ? $shutters->getOpenPos : $shutters->getVentilatePos + ) + ); + } + elsif ($match =~ m{[Oo]pen|false}xms + && $shutters->getSubTyp eq 'threestate' ) + { + my $posValue = $shutters->getStatus; + my $setLastDrive; + if ( $ascDev->getAutoShuttersControlComfort eq 'on' + and + $shutters->getQueryShuttersPos( $shutters->getComfortOpenPos ) ) + { + $posValue = $shutters->getComfortOpenPos; + $setLastDrive = 'comfort - window open'; + } + elsif ($shutters->getQueryShuttersPos( $shutters->getVentilatePos ) + && $shutters->getVentilateOpen eq 'on' ) + { + $posValue = $shutters->getVentilatePos; + $setLastDrive = 'ventilate - window open'; + } + + if ( defined($posValue) && $posValue ) { + $shutters->setLastDrive($setLastDrive); + $shutters->setNoDelay(1); + $shutters->setDriveCmd($posValue); + } + } + } + + return; +} + +## 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)}xms ) { + 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 $event = $1; + my $posValue = $shutters->getStatus; + + if ( + ( $event eq 'home' || $event eq 'awoken' ) + && ( $getRoommatesStatus eq 'home' + || $getRoommatesStatus eq 'awoken' ) + && ( $ascDev->getAutoShuttersControlMorning eq 'on' + || $shutters->getUp eq 'roommate' ) + && IsAfterShuttersManualBlocking($shuttersDev) + ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate_1: $shuttersDev und Events $events" + ); + if ( + ( + ( + $getRoommatesLastStatus eq 'asleep' + && ( $shutters->getModeUp eq 'always' + or $shutters->getModeUp eq $event ) + ) + || ( + $getRoommatesLastStatus eq 'awoken' + && ( $shutters->getModeUp eq 'always' + or $shutters->getModeUp eq $event ) + ) + ) + && ( $shutters->getIsDay + || $shutters->getUp eq 'roommate' ) + && ( IsAfterShuttersTimeBlocking($shuttersDev) + || $shutters->getUp eq 'roommate' ) + ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate_2: $shuttersDev und Events $events" + ); + + if ( $shutters->getIfInShading + && !$shutters->getShadingManualDriveStatus + && $shutters->getStatus != $shutters->getShadingPos ) + { + $shutters->setLastDrive('shading in'); + $posValue = $shutters->getShadingPos; + } + elsif ( !$shutters->getIfInShading ) { + $shutters->setLastDrive('roommate awoken'); + $posValue = $shutters->getOpenPos; + } + + ShuttersCommandSet( $hash, $shuttersDev, $posValue ); + } + elsif ( + ( + $getRoommatesLastStatus eq 'absent' + || $getRoommatesLastStatus eq 'gone' + ) + && $getRoommatesStatus eq 'home' + ) + { + if ( + $shutters->getIsDay + && $shutters->getIfInShading + && $shutters->getStatus != $shutters->getShadingPos + && !$shutters->getShadingManualDriveStatus + && !( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + ) + && !$shutters->getSelfDefenseState + ) + { + ShadingProcessingDriveCommand( $hash, $shuttersDev ); + } + elsif ( + !$shutters->getIsDay + && IsAfterShuttersTimeBlocking($shuttersDev) + && ( $getModeDown eq 'home' + || $getModeDown eq 'always' ) + && $shutters->getDown ne 'roommate' + ) + { + $shutters->setLastDrive('roommate come home'); + + if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 + || $shutters->getVentilateOpen eq 'off' ) + { + $posValue = ( + $shutters->getSleepPos > 0 ? $shutters->getSleepPos + : ( + $shutters->getSleepPos > 0 + ? $shutters->getSleepPos + : $shutters->getClosedPos + ) + ); + } + else { + $posValue = $shutters->getVentilatePos; + $shutters->setLastDrive( + $shutters->getLastDrive . ' - ventilate mode' ); + } + + ShuttersCommandSet( $hash, $shuttersDev, $posValue ); + } + elsif ( + ( $shutters->getIsDay || $shutters->getUp eq 'roommate' ) + && IsAfterShuttersTimeBlocking($shuttersDev) + && ( $getModeUp eq 'home' + || $getModeUp eq 'always' ) + && !$shutters->getIfInShading + ) + { + if ( $shutters->getIfInShading + && !$shutters->getShadingManualDriveStatus + && $shutters->getStatus == $shutters->getOpenPos + && $shutters->getShadingMode eq 'home' ) + { + $shutters->setLastDrive('shading in'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getShadingPos ); + } + elsif ( + ( + !$shutters->getIfInShading + || $shutters->getShadingMode eq 'absent' + ) + && ( $shutters->getStatus == $shutters->getClosedPos + || $shutters->getStatus == $shutters->getSleepPos + || $shutters->getStatus == + $shutters->getShadingPos ) + ) + { + $shutters->setLastDrive( + ( + ( + $shutters->getStatus == + $shutters->getClosedPos + || $shutters->getStatus == + $shutters->getSleepPos + ) + ? 'roommate come home' + : 'shading out' + ) + ); + + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getOpenPos ); + } + } + } + } + elsif ( + ( $event eq 'gotosleep' || $event eq 'asleep' ) + && ( $ascDev->getAutoShuttersControlEvening eq 'on' + || $shutters->getDown eq 'roommate' ) + && ( IsAfterShuttersManualBlocking($shuttersDev) + || $shutters->getDown eq 'roommate' ) + ) + { + $shutters->setLastDrive('roommate asleep'); + + if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 + || $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 ( + $event eq 'absent' + && ( !$shutters->getIsDay + || $shutters->getDown eq 'roommate' + || $shutters->getShadingMode eq 'absent' + || $shutters->getModeUp eq 'absent' + || $shutters->getModeDown eq 'absent' ) + ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate absent: $shuttersDev" + ); + + if ( ( $shutters->getIsDay || $shutters->getUp eq 'roommate' ) + && $shutters->getIfInShading + && !$shutters->getQueryShuttersPos( $shutters->getShadingPos ) + && $shutters->getShadingMode eq 'absent' ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate Shading: $shuttersDev" + ); + + $shutters->setLastDrive('shading in'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getShadingPos ); + } + elsif (( !$shutters->getIsDay || $shutters->getDown eq 'roommate' ) + && $getModeDown eq 'absent' + && $getRoommatesStatus eq 'absent' ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate Down: $shuttersDev" + ); + + $shutters->setLastDrive('roommate absent'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getClosedPos ); + } + elsif ($shutters->getIsDay + && $shutters->getModeUp eq 'absent' + && $getRoommatesStatus eq 'absent' ) + { + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate Up: $shuttersDev" + ); + + $shutters->setLastDrive('roommate absent'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getOpenPos ); + } + + Log3( $name, 4, +"AutoShuttersControl ($name) - EventProcessingRoommate NICHTS: $shuttersDev" + ); + } + } + + return; +} + +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))}xms ) { + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; + $shutters->setHardLockOut('off'); + if ( + $ascDev->getSelfDefense eq 'on' + && $shutters->getSelfDefenseMode ne 'off' + || ( $getModeDown eq 'absent' + || $getModeDown eq 'always' ) + || ( $shutters->getShadingMode eq 'absent' + && $shutters->getRoommatesStatus eq 'none' ) + || ( $shutters->getShadingMode eq 'home' + && $shutters->getRoommatesStatus eq 'none' ) + ) + { + if ( + $ascDev->getSelfDefense eq 'on' + && ( + $shutters->getSelfDefenseMode eq 'absent' + || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getSelfDefenseMode eq 'gone' + && $shutters->getShuttersPlace eq 'terrace' + && $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 ($shutters->getIsDay + && $shutters->getIfInShading + && $shutters->getShadingMode eq 'absent' + && $shutters->getRoommatesStatus eq 'none' ) + { + ShadingProcessingDriveCommand( $hash, $shuttersDev ); + } + elsif ( + $shutters->getShadingMode eq 'home' + && $shutters->getIsDay + && $shutters->getIfInShading + && $shutters->getStatus == $shutters->getShadingPos + && $shutters->getRoommatesStatus eq 'none' + && !( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + ) + && !$shutters->getSelfDefenseState + ) + { + $shutters->setLastDrive('shading out'); + $shutters->setDriveCmd( $shutters->getLastPos ); + } + elsif (( $getModeDown eq 'absent' || $getModeDown eq 'always' ) + && !$shutters->getIsDay + && IsAfterShuttersTimeBlocking($shuttersDev) + && $shutters->getRoommatesStatus eq 'none' ) + { + $shutters->setLastDrive('residents absent'); + $shutters->setDriveCmd( $shutters->getClosedPos ); + } + } + } + } + elsif ($events =~ m{$reading:\s(gone)}xms + && $ascDev->getSelfDefense eq 'on' ) + { + for 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)}xms + && ( $getResidentsLastStatus eq 'absent' + || $getResidentsLastStatus eq 'gone' + || $getResidentsLastStatus eq 'asleep' + || $getResidentsLastStatus eq 'awoken' ) + ) + { + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + my $getModeUp = $shutters->getModeUp; + my $getModeDown = $shutters->getModeDown; + + if ( + ( + $shutters->getStatus != $shutters->getClosedPos + || $shutters->getStatus != $shutters->getSleepPos + ) + && !$shutters->getIsDay + && $shutters->getRoommatesStatus eq 'none' + && ( $getModeDown eq 'home' + || $getModeDown eq 'always' ) + && $getResidentsLastStatus ne 'asleep' + && $getResidentsLastStatus ne 'awoken' + && IsAfterShuttersTimeBlocking($shuttersDev) + && !$shutters->getSelfDefenseState + ) + { + $shutters->setLastDrive('residents come home'); + $shutters->setDriveCmd( + ( + $shutters->getSleepPos > 0 + ? $shutters->getSleepPos + : $shutters->getClosedPos + ) + ); + } + elsif ( + ( + $shutters->getShadingMode eq 'home' + || $shutters->getShadingMode eq 'always' + ) + && $shutters->getIsDay + && $shutters->getIfInShading + && $shutters->getRoommatesStatus eq 'none' + && $shutters->getStatus != $shutters->getShadingPos + && !$shutters->getShadingManualDriveStatus + && !( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + ) + && !$shutters->getSelfDefenseState + ) + { + ShadingProcessingDriveCommand( $hash, $shuttersDev ); + } + elsif ( + $shutters->getShadingMode eq 'absent' + && $shutters->getIsDay + && $shutters->getIfInShading + && $shutters->getStatus == $shutters->getShadingPos + && $shutters->getRoommatesStatus eq 'none' + && !$shutters->getShadingManualDriveStatus + && !( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + ) + && !$shutters->getSelfDefenseState + ) + { + $shutters->setLastDrive('shading out'); + $shutters->setDriveCmd( $shutters->getLastPos ); + } + elsif ( + $ascDev->getSelfDefense eq 'on' + && $shutters->getSelfDefenseMode ne 'off' + && !$shutters->getIfInShading + && ( $getResidentsLastStatus eq 'gone' + || $getResidentsLastStatus eq 'absent' ) + && $shutters->getSelfDefenseState + ) + { + RemoveInternalTimer( $shutters->getSelfDefenseAbsentTimerhash ) + if ( $getResidentsLastStatus eq 'absent' + && $ascDev->getSelfDefense eq 'on' + && $shutters->getSelfDefenseMode ne 'off' + && !$shutters->getSelfDefenseAbsent + && $shutters->getSelfDefenseAbsentTimerrun ); + + if ( + ( + $shutters->getStatus == $shutters->getClosedPos + || $shutters->getStatus == $shutters->getSleepPos + ) + && $shutters->getIsDay + ) + { + $shutters->setHardLockOut('on') + if ( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + && ( $getModeUp eq 'absent' + || $getModeUp eq 'off' ) + ); + + $shutters->setSelfDefenseState(0); + $shutters->setLastDrive('selfDefense inactive'); + $shutters->setDriveCmd( + ( + $shutters->getPrivacyDownStatus == 2 + ? $shutters->getPrivacyDownPos + : $shutters->getOpenPos + ) + ); + } + } + elsif ( + ( + $shutters->getStatus == $shutters->getClosedPos + || $shutters->getStatus == $shutters->getSleepPos + ) + && $shutters->getIsDay + && $shutters->getRoommatesStatus eq 'none' + && ( $getModeUp eq 'home' + || $getModeUp eq 'always' ) + && IsAfterShuttersTimeBlocking($shuttersDev) + && !$shutters->getIfInShading + && !$shutters->getSelfDefenseState + ) + { + if ( $getResidentsLastStatus eq 'asleep' + || $getResidentsLastStatus eq 'awoken' ) + { + $shutters->setLastDrive('residents awoken'); + } + else { $shutters->setLastDrive('residents home'); } + $shutters->setDriveCmd( $shutters->getOpenPos ); + } + } + } + + return; +} + +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)}xms ) { + 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 ); + } + + return; +} + +sub RainProtection { + my ( $hash, $val, $triggerMax, $closedPos ) = @_; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + + next + if ( $shutters->getRainProtection eq 'off' ); + + if ( $val > $triggerMax + && $shutters->getStatus != $closedPos + && IsAfterShuttersManualBlocking($shuttersDev) + && $shutters->getRainProtectionStatus eq 'unprotected' ) + { + $shutters->setLastDrive('rain protected'); + $shutters->setDriveCmd($closedPos); + $shutters->setRainProtectionStatus('protected'); + } + elsif (( $val == 0 || $val < $shutters->getWindMin ) + && $shutters->getStatus == $closedPos + && IsAfterShuttersManualBlocking($shuttersDev) + && $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'); + } + } + + return; +} + +sub EventProcessingWind { + my ( $hash, $shuttersDev, $events ) = @_; + + my $name = $hash->{NAME}; + $shutters->setShuttersDev($shuttersDev); + + my $reading = $ascDev->getWindSensorReading; + if ( $events =~ m{$reading:\s(\d+(\.\d+)?)}xms ) { + for 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 + && $shutters->getShuttersPlace eq 'terrace' + ) + || $shutters->getWindProtection eq 'off' + ); + + if ( $1 > $shutters->getWindMax + && $shutters->getWindProtectionStatus eq 'unprotected' ) + { + $shutters->setLastDrive('wind protected'); + $shutters->setDriveCmd( $shutters->getWindPos ); + $shutters->setWindProtectionStatus('protected'); + } + elsif ($1 < $shutters->getWindMin + && $shutters->getWindProtectionStatus eq 'protected' ) + { + $shutters->setLastDrive('wind un-protected'); + $shutters->setDriveCmd( + ( + $shutters->getIsDay ? $shutters->getLastPos + : ( + $shutters->getPrivacyDownStatus == 2 + ? $shutters->getPrivacyDownPos + : ( + $shutters->getSleepPos > 0 + ? $shutters->getSleepPos + : $shutters->getClosedPos + ) + ) + ) + ); + $shutters->setWindProtectionStatus('unprotected'); + } + + ASC_Debug( 'EventProcessingWind: ' + . $shutters->getShuttersDev + . ' - WindProtection2: ' + . $shutters->getWindProtectionStatus + . ' WindMax2: ' + . $shutters->getWindMax + . ' WindMin2: ' + . $shutters->getWindMin + . ' Bekommender Wert2: ' + . $1 ); + } + } + + return; +} +########## + +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' + || $shutters->getUp eq 'brightness' + ) + || ( + ( + ( + ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', + $shutters->getTimeUpEarly ) / 86400 + ) + && ( + !IsWe() + || ( IsWe() + && $ascDev->getSunriseTimeWeHoliday eq 'off' ) + ) + ) + || ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ) / 86400 + ) + && IsWe() + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday eq '01:25' + ) + ) + && int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeUpLate ) / + 86400 + ) + ) + || ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / + 86400 + ) + && 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+)?)}xms ) { + 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 + ) + && ( + !IsWe() + || ( + IsWe() + && $ascDev->getSunriseTimeWeHoliday eq 'off' + || ( $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday eq + '01:25' ) + ) + ) + ) + || ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ) / 86400 + ) + && IsWe() + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' + ) + ) + && int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeUpLate ) / + 86400 + ) + ) + && ( + $1 > $brightnessMaxVal + || ( $1 > $brightnessPrivacyUpVal + && $shutters->getPrivacyUpStatus == 1 ) + ) + && $shutters->getUp eq 'brightness' + && !$shutters->getSunrise + && $ascDev->getAutoShuttersControlMorning eq 'on' + && ( + $ascDev->getSelfDefense eq 'off' + || $shutters->getSelfDefenseMode eq 'off' + || ( $ascDev->getSelfDefense eq 'on' + && $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 + || ( $shutters->getModeUp eq 'absent' + && $homemode eq 'gone' ) + || $shutters->getModeUp eq 'always' + ) + { + my $roommatestatus = $shutters->getRoommatesStatus; + + if ( + $roommatestatus eq 'home' + || $roommatestatus eq 'awoken' + || $roommatestatus eq 'absent' + || $roommatestatus eq 'gone' + || $roommatestatus eq 'none' + && ( + $ascDev->getSelfDefense eq 'off' + || ( $ascDev->getSelfDefense eq 'on' + && CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) + || ( $ascDev->getSelfDefense eq 'on' + && CheckIfShuttersWindowRecOpen($shuttersDev) != 0 + && $ascDev->getResidentsStatus eq 'home' ) + ) + ) + { + + if ( $brightnessPrivacyUpVal > 0 + && $1 < $brightnessMaxVal + && $1 > $brightnessPrivacyUpVal ) + { + $shutters->setPrivacyUpStatus(2); + $shutters->setLastDrive('brightness privacy day open'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getPrivacyUpPos ) + unless ( + !$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 + ) + && int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeDownLate ) / 86400 + ) + && ( + $1 < $brightnessMinVal + || ( $1 < $brightnessPrivacyDownVal + && $shutters->getPrivacyDownStatus == 1 ) + ) + && $shutters->getDown eq 'brightness' + && !$shutters->getSunset + && IsAfterShuttersManualBlocking($shuttersDev) + && $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 + || ( $shutters->getModeDown eq 'absent' + && $homemode eq 'gone' ) + || $shutters->getModeDown eq 'always' + ) + { + my $posValue = $shutters->getStatus; + 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 + + if ( $brightnessPrivacyDownVal > 0 + && $1 > $brightnessMinVal + && $1 < $brightnessPrivacyDownVal ) + { + $lastDrive = 'brightness privacy night close'; + $posValue = ( + ( + !$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 + && $shutters->getSubTyp eq 'threestate' + && $ascDev->getAutoShuttersControlComfort eq 'on' ) + { + $posValue = $shutters->getComfortOpenPos; + $lastDrive = 'minimum brightness threshold fell below'; + $shutters->setPrivacyDownStatus(0) + if ( $shutters->getPrivacyDownStatus == 2 ); + } + elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 0 + || $shutters->getVentilateOpen eq 'off' ) + { + $posValue = ( + $shutters->getSleepPos > 0 + ? $shutters->getSleepPos + : $shutters->getClosedPos + ); + $lastDrive = 'minimum brightness threshold fell below'; + $shutters->setPrivacyDownStatus(0) + if ( $shutters->getPrivacyDownStatus == 2 ); + } + else { + $posValue = $shutters->getVentilatePos; + $lastDrive = 'minimum brightness threshold fell below'; + $shutters->setPrivacyDownStatus(0) + if ( $shutters->getPrivacyDownStatus == 2 ); + } + + $shutters->setLastDrive($lastDrive); + + if ( + $shutters->getPrivacyDownStatus != 2 + && ( $posValue != $shutters->getStatus + || $shutters->getSelfDefenseState ) + ) + { + $shutters->setSunrise(0); + $shutters->setSunset(1); + } + + ShuttersCommandSet( $hash, $shuttersDev, $posValue ); + + ASC_Debug( 'EventProcessingBrightness: ' + . $shutters->getShuttersDev + . ' - Verarbeitung für Sunset. Roommatestatus korrekt zum fahren. Fahrbefehl wird an die Funktion FnShuttersCommandSet gesendet. Zielposition: ' + . $posValue + . ' Grund des fahrens: ' + . $shutters->getLastDrive ); + } + else { + EventProcessingShadingBrightness( $hash, $shuttersDev, $events ) + 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' + ); + } + + return; +} + +sub EventProcessingShadingBrightness { + my ( $hash, $shuttersDev, $events ) = @_; + + my $name = $hash->{NAME}; + $shutters->setShuttersDev($shuttersDev); + my $reading = $shutters->getBrightnessReading; + my $outTemp = ( + $shutters->getOutTemp != -100 + ? $shutters->getOutTemp + : $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+)?)}xms ) { + 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' + && $shutters->getRainProtectionStatus eq 'unprotected' + && $shutters->getWindProtectionStatus eq 'unprotected' ) + { + 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' + ); + } + } + + return; +} + +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+)}xms ) { + my $name = $device; + my $outTemp = $ascDev->getOutTemp; + my ( $azimuth, $elevation ); + + $azimuth = $2 if ( $1 eq 'azimuth' || $1 eq 'SunAz' ); + $elevation = $2 if ( $1 eq 'elevation' || $1 eq 'SunAlt' ); + + $azimuth = $ascDev->getAzimuth + if ( !defined($azimuth) && !$azimuth ); + $elevation = $ascDev->getElevation + if ( !defined($elevation) && !$elevation ); + + ASC_Debug( 'EventProcessingTwilightDevice: ' + . $name + . ' - Passendes Event wurde erkannt. Verarbeitung über alle Rollos beginnt' + ); + + for 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' + && $shutters->getRainProtectionStatus eq 'unprotected' + && $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' + ); + } + } + } + + return; +} + +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 + || $elevation == -1 + || $brightness == -1 + || $outTemp == -100 + || ( int( gettimeofday() ) - $shutters->getShadingStatusTimestamp ) < + ( $shutters->getShadingWaitingPeriod / 2 ) + || $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; + my $shuttersDevHash = $defs{$shuttersDev}; + + my $getModeUp = $shutters->getModeUp; + my $homemode = $shutters->getHomemode; + + 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 - 4 + || $azimuth < $azimuthLeft + || $azimuth > $azimuthRight + || !$shutters->getIsDay + ) + && $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 + || $azimuth > $azimuthRight + || $elevation < $shutters->getShadingMinElevation + || $elevation > $shutters->getShadingMaxElevation + || $brightness < $shutters->getShadingStateChangeCloudy + || $outTemp < $shutters->getShadingMinOutsideTemperature - 1 ) + { + $shutters->setShadingStatus('out reserved') + if ( $shutters->getShadingStatus eq 'in' + || $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 + && $azimuth < $azimuthRight + && $elevation > $shutters->getShadingMinElevation + && $elevation < $shutters->getShadingMaxElevation + && $brightness > $shutters->getShadingStateChangeSunny + && $outTemp > $shutters->getShadingMinOutsideTemperature ) + { + if ( $shutters->getShadingStatus eq 'out' + || $shutters->getShadingStatus eq 'out reserved' ) + { + $shutters->setShadingStatus('in 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 ( + IsAfterShuttersTimeBlocking($shuttersDev) + && !$shutters->getShadingManualDriveStatus + && $shutters->getRoommatesStatus ne 'gotosleep' + && $shutters->getRoommatesStatus ne 'asleep' + && ( + ( + $shutters->getShadingStatus eq 'out' + && $shutters->getShadingLastStatus eq 'in' + ) + || ( $shutters->getShadingStatus eq 'in' + && $shutters->getShadingLastStatus eq 'out' ) + ) + && ( $shutters->getShadingMode eq 'always' + || $shutters->getShadingMode eq $homemode ) + && ( + $shutters->getModeUp eq 'always' + || $shutters->getModeUp eq $homemode + || ( $shutters->getModeUp eq 'home' + && $homemode ne 'asleep' ) + || $shutters->getModeUp eq 'off' + ) + && ( + ( + ( + int( gettimeofday() ) - + $shutters->getShadingStatusTimestamp + ) < 2 + && $shutters->getStatus != $shutters->getClosedPos + ) + || ( !$shutters->getQueryShuttersPos( $shutters->getShadingPos ) + && $shutters->getIfInShading ) + || ( !$shutters->getIfInShading + && $shutters->getStatus == $shutters->getShadingPos ) + ) + ); + + readingsBeginUpdate($shuttersDevHash); + readingsBulkUpdate( + $shuttersDevHash, + 'ASC_ShadingMessage', + 'INFO: current shading status is \'' + . $shutters->getShadingStatus . '\'' + . ' - next check in ' + . ( + ( + ( + $shutters->getShadingLastStatus eq 'out reserved' + || $shutters->getShadingLastStatus eq 'out' + ) + ? $shutters->getShadingWaitingPeriod + : $shutters->getShadingWaitingPeriod / 2 + ) + ) / 60 + . 'm' + ); + readingsEndUpdate( $shuttersDevHash, 1 ); + + return; +} + +sub ShadingProcessingDriveCommand { + my $hash = shift; + my $shuttersDev = shift; + + my $name = $hash->{NAME}; + $shutters->setShuttersDev($shuttersDev); + + my $getShadingPos = $shutters->getShadingPos; + my $getStatus = $shutters->getStatus; + + $shutters->setShadingStatus( $shutters->getShadingStatus ); + + if ( + $shutters->getShadingStatus eq 'in' + && $getShadingPos != $getStatus + && ( CheckIfShuttersWindowRecOpen($shuttersDev) != 2 + || $shutters->getShuttersPlace ne 'terrace' ) + ) + { + $shutters->setLastDrive('shading in'); + ShuttersCommandSet( $hash, $shuttersDev, $getShadingPos ); + + ASC_Debug( 'ShadingProcessingDriveCommand: ' + . $shutters->getShuttersDev + . ' - Der aktuelle Beschattungsstatus ist: ' + . $shutters->getShadingStatus + . ' und somit wird nun in die Position: ' + . $getShadingPos + . ' zum Beschatten gefahren' ); + } + elsif ($shutters->getShadingStatus eq 'out' + && $getShadingPos == $getStatus ) + { + $shutters->setLastDrive('shading out'); + + ShuttersCommandSet( + $hash, + $shuttersDev, + ( + $getShadingPos == $shutters->getLastPos + ? $shutters->getOpenPos + : ( + $shutters->getQueryShuttersPos( $shutters->getLastPos ) + ? ( + $shutters->getLastPos == $shutters->getSleepPos + ? $shutters->getOpenPos + : $shutters->getLastPos + ) + : $shutters->getOpenPos + ) + ) + ); + + ASC_Debug( 'ShadingProcessingDriveCommand: ' + . $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( + 'ShadingProcessingDriveCommand: ' + . $shutters->getShuttersDev + . ' - Der aktuelle Beschattungsstatus ist: ' + . $shutters->getShadingStatus + . ', Beschattungsstatus Zeitstempel: ' + . strftime( + "%Y.%m.%e %T", localtime( $shutters->getShadingStatusTimestamp ) + ) + ); + + return; +} + +sub EventProcessingPartyMode { + my $hash = shift; + + my $name = $hash->{NAME}; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + next + if ( $shutters->getPartyMode eq 'off' ); + + if ( !$shutters->getIsDay + && $shutters->getModeDown ne 'off' + && IsAfterShuttersManualBlocking($shuttersDev) ) + { + if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $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' + && $shutters->getIsDay + && IsAfterShuttersManualBlocking($shuttersDev) ) + { + $shutters->setLastDrive('drive after party mode'); + ShuttersCommandSet( $hash, $shuttersDev, $shutters->getDelayCmd ); + } + } + + return; +} + +sub EventProcessingAdvShuttersClose { + my $hash = shift; + + my $name = $hash->{NAME}; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + next + if ( !$shutters->getAdv + && !$shutters->getAdvDelay ); + + $shutters->setLastDrive('adv delay close'); + $shutters->setAdvDelay(1); + ShuttersCommandSet( + $hash, + $shuttersDev, + ( + $shutters->getDelayCmd ne 'none' + ? $shutters->getDelayCmd + : $shutters->getClosedPos + ) + ); + } + + return; +} + +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+)}xms ) { + $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 + && ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) > + $shutters->getDriveUpMaxDuration ) + { + $shutters->setLastDrive('manual'); + $shutters->setLastDriveReading; + $ascDev->setStateReading; + $shutters->setLastManPos($1); + + $shutters->setShadingManualDriveStatus(1) + if ( $shutters->getIsDay + && $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. ' + ); + + return; +} + +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 $triggerValActive2 = $shutters->getExternalTriggerValueActive2; + my $triggerValInactive = $shutters->getExternalTriggerValueInactive; + my $triggerPosActive = $shutters->getExternalTriggerPosActive; + my $triggerPosActive2 = $shutters->getExternalTriggerPosActive2; + my $triggerPosInactive = $shutters->getExternalTriggerPosInactive; + + if ( $events =~ m{$reading:\s($triggerValActive|$triggerValActive2)}xms ) { + + # && !$shutters->getQueryShuttersPos($triggerPosActive) + + ASC_Debug( 'EventProcessingExternalTriggerDevice: ' + . ' In der RegEx Schleife Trigger Val Aktiv' + . ' - TriggerVal: ' + . $triggerValActive + . ' - TriggerVal2: ' + . $triggerValActive2 ); + + if ( $1 eq $triggerValActive2 ) { + $shutters->setLastDrive('external trigger2 device active'); + $shutters->setNoDelay(1); + $shutters->setExternalTriggerState(1); + ShuttersCommandSet( $hash, $shuttersDev, $triggerPosActive2 ); + } + else { + $shutters->setLastDrive('external trigger device active'); + $shutters->setNoDelay(1); + $shutters->setExternalTriggerState(1); + ShuttersCommandSet( $hash, $shuttersDev, $triggerPosActive ); + } + } + elsif ( + $events =~ m{$reading:\s($triggerValInactive)}xms + && ( $shutters->getPrivacyDownStatus != 2 + || $shutters->getPrivacyUpStatus != 2 ) + && !$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, + ( + $shutters->getIsDay + ? $triggerPosInactive + : $shutters->getClosedPos + ) + ); + } + + ASC_Debug( + 'EventProcessingExternalTriggerDevice: ' . ' Funktion durchlaufen' ); + + return; +} + +# 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 && + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + && ( $shutters->getLockOut eq 'soft' + || $shutters->getLockOut eq 'hard' ) + && !$shutters->getQueryShuttersPos($posValue) + ) + || ( + # $posValue != $shutters->getShadingPos + # && ( + ( + $shutters->getPartyMode eq 'on' + && $ascDev->getPartyMode eq 'on' + ) + || ( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getSubTyp eq 'threestate' + && ( $ascDev->getAutoShuttersControlComfort eq 'off' + || $shutters->getComfortOpenPos != $posValue ) + && $shutters->getVentilateOpen eq 'on' + && $shutters->getShuttersPlace eq 'window' + && $shutters->getLockOut ne 'off' + ) + || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getSubTyp eq 'threestate' + && $ascDev->getAutoShuttersControlComfort eq 'on' + && $shutters->getVentilateOpen eq 'off' + && $shutters->getShuttersPlace eq 'window' + && $shutters->getLockOut ne 'off' ) + || ( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && ( $shutters->getLockOut eq 'soft' + || $shutters->getLockOut eq 'hard' ) + && !$shutters->getQueryShuttersPos($posValue) + ) + || ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getShuttersPlace eq 'terrace' + && !$shutters->getQueryShuttersPos($posValue) ) + || ( $shutters->getRainProtectionStatus eq 'protected' + && $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' + ); + } + + return; +} + +## Sub welche die InternalTimer nach entsprechenden Sunset oder Sunrise zusammen stellt +sub CreateSunRiseSetShuttersTimer { + my $hash = shift; + my $shuttersDev = shift // return Log3( $hash->{NAME}, 1, +"AutoShuttersControl ($hash->{NAME}) - Error in function CreateSunRiseSetShuttersTimer. No shuttersDev given"); + + 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 ( !defined( $shutters->getPrivacyUpStatus ) ); + $shutters->setPrivacyDownStatus(0) + if ( !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' ) ne + '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' ) ne + '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, \&SunSetShuttersAfterTimerFn, + \%funcHash ); + InternalTimer( $shuttersSunriseUnixtime, \&SunRiseShuttersAfterTimerFn, + \%funcHash ); + + $ascDev->setStateReading('created new drive timer'); + + return; +} + +## Funktion zum neu setzen der Timer und der Readings für Sunset/Rise +sub RenewSunRiseSetShuttersTimer { + my $hash = shift; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + my $dhash = $defs{$shuttersDev}; + + $shutters->setShuttersDev($shuttersDev); + + RemoveInternalTimer( $shutters->getInTimerFuncHash ); + $shutters->setInTimerFuncHash(undef); + CreateSunRiseSetShuttersTimer( $hash, $shuttersDev ); + + #### 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( + $shuttersDev, '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, + 0 + ) == 0 + ) + { +# $attr{$shuttersDev}{'ASC_Up'} = $shutters->getAttrUpdateChanges('ASC_Up') +# if ( $shutters->getAttrUpdateChanges('ASC_Up') ne 'none' ); +# $attr{$shuttersDev}{'ASC_Down'} = +# $shutters->getAttrUpdateChanges('ASC_Down') +# if ( $shutters->getAttrUpdateChanges('ASC_Down') ne 'none' ); +# $attr{$shuttersDev}{'ASC_Self_Defense_Mode'} = +# $shutters->getAttrUpdateChanges('ASC_Self_Defense_Mode') +# if ( $shutters->getAttrUpdateChanges('ASC_Self_Defense_Mode') ne +# 'none' ); +# $attr{$shuttersDev}{'ASC_Self_Defense_Mode'} = 'off' +# if ( +# $shutters->getAttrUpdateChanges('ASC_Self_Defense_Exclude') eq +# 'on' ); + + CommandDeleteReading( undef, + $shuttersDev . ' .ASC_AttrUpdateChanges_.*' ) + if ( + ReadingsVal( $shuttersDev, + '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, 'none' ) eq + 'none' + ); + readingsSingleUpdate( $dhash, + '.ASC_AttrUpdateChanges_' . $hash->{VERSION}, + 1, 0 ); + } + +# $attr{$shuttersDev}{ASC_Drive_Delay} = +# AttrVal( $shuttersDev, 'ASC_Drive_Offset', 'none' ) +# if ( AttrVal( $shuttersDev, 'ASC_Drive_Offset', 'none' ) ne 'none' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Drive_Offset' ); +# +# $attr{$shuttersDev}{ASC_Drive_DelayStart} = +# AttrVal( $shuttersDev, 'ASC_Drive_OffsetStart', 'none' ) +# if ( AttrVal( $shuttersDev, 'ASC_Drive_OffsetStart', 'none' ) ne 'none' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Drive_OffsetStart' ); +# +# $attr{$shuttersDev}{ASC_Shading_StateChange_SunnyCloudy} = +# AttrVal( $shuttersDev, 'ASC_Shading_StateChange_Sunny', 'none' ) . ':' +# . AttrVal( $shuttersDev, 'ASC_Shading_StateChange_Cloudy', 'none' ) +# if ( +# AttrVal( $shuttersDev, 'ASC_Shading_StateChange_Sunny', 'none' ) ne 'none' +# && AttrVal( $shuttersDev, 'ASC_Shading_StateChange_Cloudy', 'none' ) ne +# 'none' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Shading_StateChange_Sunny' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Shading_StateChange_Cloudy' ); +# +# $attr{$shuttersDev}{ASC_Shading_InOutAzimuth} = +# ( AttrVal( $shuttersDev, 'ASC_Shading_Direction', 180 ) - +# AttrVal( $shuttersDev, 'ASC_Shading_Angle_Left', 85 ) ) +# . ':' +# . ( AttrVal( $shuttersDev, 'ASC_Shading_Direction', 180 ) + +# AttrVal( $shuttersDev, 'ASC_Shading_Angle_Right', 85 ) ) +# if ( AttrVal( $shuttersDev, 'ASC_Shading_Direction', 'none' ) ne 'none' +# || AttrVal( $shuttersDev, 'ASC_Shading_Angle_Left', 'none' ) ne 'none' +# || AttrVal( $shuttersDev, 'ASC_Shading_Angle_Right', 'none' ) ne 'none' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Shading_Direction' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Shading_Angle_Left' ); +# delFromDevAttrList( $shuttersDev, 'ASC_Shading_Angle_Right' ); +# +# $attr{$shuttersDev}{ASC_PrivacyDownValue_beforeNightClose} = +# AttrVal( $shuttersDev, 'ASC_PrivacyDownTime_beforNightClose', 'none' ) +# if ( +# AttrVal( $shuttersDev, 'ASC_PrivacyDownTime_beforNightClose', 'none' ) ne +# 'none' ); +# delFromDevAttrList( $shuttersDev, 'ASC_PrivacyDownTime_beforNightClose' ); +# +# delFromDevAttrList( $shuttersDev, 'ASC_ExternalTriggerDevice' ); + } + + return; +} + +## Funktion zum hardwareseitigen setzen des lock-out oder blocking beim Rolladen selbst +sub HardewareBlockForShutters { + my $hash = shift; + my $cmd = shift; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + $shutters->setHardLockOut($cmd); + } + + return; +} + +## Funktion für das wiggle aller Shutters zusammen +sub wiggleAll { + my $hash = shift; + + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + wiggle( $hash, $shuttersDev ); + } + + return; +} + +sub wiggle { + my $hash = shift; + my $shuttersDev = shift; + + $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, \&_SetCmdFn, \%h ); + + return; +} +#### + +## 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' + && $ascDev->getAutoShuttersControlEvening eq 'on' + && IsAfterShuttersManualBlocking($shuttersDev) + && ( + $shutters->getModeDown eq $homemode + || ( $shutters->getModeDown eq 'absent' + && $homemode eq 'gone' ) + || $shutters->getModeDown eq 'always' + ) + && ( + $ascDev->getSelfDefense eq 'off' + || $shutters->getSelfDefenseMode eq 'off' + || ( $ascDev->getSelfDefense eq 'on' + && $ascDev->getResidentsStatus ne 'gone' ) + ) + && ( + $shutters->getDown ne 'brightness' + || ( $shutters->getDown eq 'brightness' + && !$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 ); + + return; +} + +## 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' + && $ascDev->getAutoShuttersControlMorning eq 'on' + && ( + $shutters->getModeUp eq $homemode + || ( $shutters->getModeUp eq 'absent' + && $homemode eq 'gone' ) + || $shutters->getModeUp eq 'always' + ) + && ( + $ascDev->getSelfDefense eq 'off' + || $shutters->getSelfDefenseMode eq 'off' + || ( + $ascDev->getSelfDefense eq 'on' + && ( $shutters->getSelfDefenseMode eq 'gone' + || $shutters->getSelfDefenseMode eq 'absent' ) + && $ascDev->getResidentsStatus ne 'gone' + ) + || ( $ascDev->getSelfDefense eq 'on' + && $shutters->getSelfDefenseMode eq 'absent' + && $ascDev->getResidentsStatus ne 'absent' ) + ) + && ( + $shutters->getUp ne 'brightness' + || ( $shutters->getUp eq 'brightness' + && !$shutters->getSunrise ) + ) + ) + { + + if ( + ( + $shutters->getRoommatesStatus eq 'home' + || $shutters->getRoommatesStatus eq 'awoken' + || $shutters->getRoommatesStatus eq 'absent' + || $shutters->getRoommatesStatus eq 'gone' + || $shutters->getRoommatesStatus eq 'none' + ) + && ( + $ascDev->getSelfDefense eq 'off' + || ( $ascDev->getSelfDefense eq 'on' + && CheckIfShuttersWindowRecOpen($shuttersDev) == 0 ) + || ( + $ascDev->getSelfDefense eq 'on' + && CheckIfShuttersWindowRecOpen($shuttersDev) != 0 + && ( $ascDev->getResidentsStatus ne 'absent' + && $ascDev->getResidentsStatus ne 'gone' ) + ) + ) + ) + { + if ( !$shutters->getIfInShading ) { + if ( $shutters->getPrivacyUpStatus == 1 ) { + $shutters->setPrivacyUpStatus(2); + $shutters->setLastDrive('timer privacy day open'); + ShuttersCommandSet( $hash, $shuttersDev, + $shutters->getPrivacyUpPos ) + unless ( + !$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 ); + + return; +} + +sub CreateNewNotifyDev { + my $hash = shift; + + my $name = $hash->{NAME}; + + $hash->{NOTIFYDEV} = "global," . $name; + delete $hash->{monitoredDevs}; + + CommandDeleteReading( undef, $name . ' .monitoredDevs' ); + my $shuttersList = ''; + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + AddNotifyDev( $hash, + AttrVal( $shuttersDev, 'ASC_Roommate_Device', 'none' ), + $shuttersDev, 'ASC_Roommate_Device' ) + if ( + AttrVal( $shuttersDev, 'ASC_Roommate_Device', 'none' ) ne 'none' ); + AddNotifyDev( $hash, AttrVal( $shuttersDev, 'ASC_WindowRec', 'none' ), + $shuttersDev, 'ASC_WindowRec' ) + if ( AttrVal( $shuttersDev, 'ASC_WindowRec', 'none' ) ne 'none' ); + AddNotifyDev( $hash, + AttrVal( $shuttersDev, 'ASC_BrightnessSensor', 'none' ), + $shuttersDev, 'ASC_BrightnessSensor' ) + if ( + AttrVal( $shuttersDev, 'ASC_BrightnessSensor', 'none' ) ne 'none' ); + AddNotifyDev( $hash, + AttrVal( $shuttersDev, 'ASC_ExternalTrigger', 'none' ), + $shuttersDev, 'ASC_ExternalTrigger' ) + if ( + AttrVal( $shuttersDev, 'ASC_ExternalTrigger', 'none' ) ne 'none' ); + + $shuttersList = $shuttersList . ',' . $shuttersDev; + } + + 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; + + return; +} + +sub ShuttersInformation { + my ( $FW_wname, $d, $room, $pageHash ) = @_; + + my $hash = $defs{$d}; + + return + if ( !exists( $hash->{helper} ) + || !defined( $hash->{helper}->{shuttersList} ) + || ref( $hash->{helper}->{shuttersList} ) ne 'ARRAY' + || scalar( @{ $hash->{helper}->{shuttersList} } ) == 0 + || !defined( $shutters->getSunriseUnixTime ) + || !defined( $shutters->getSunsetUnixTime ) ); + + 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; + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + $shutters->setShuttersDev($shuttersDev); + + 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
$shuttersDev " + . 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( $shuttersDev, '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; + for my $notifydev ( sort keys( %{$notifydevs} ) ) { + if ( ref( $notifydevs->{$notifydev} ) eq "HASH" ) { + for my $shuttersDev ( + 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
$shuttersDev $notifydev $notifydevs->{$notifydev}{$shuttersDev}
'; + + return $ret; +} + +################################# +## my little helper +################################# + +sub PositionValueWindowRec { + my $shuttersDev = shift; + my $posValue = shift; + + if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 1 + && $shutters->getVentilateOpen eq 'on' ) + { + $posValue = $shutters->getVentilatePos; + } + elsif (CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && $shutters->getSubTyp eq 'threestate' + && $ascDev->getAutoShuttersControlComfort eq 'on' ) + { + $posValue = $shutters->getComfortOpenPos; + } + elsif ( + CheckIfShuttersWindowRecOpen($shuttersDev) == 2 + && ( $shutters->getSubTyp eq 'threestate' + || $shutters->getSubTyp eq 'twostate' ) + && $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' ); + } + + return; +} + +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, $value5, $value6, $value7, $value8 ); + ( $value3, $value4 ) = split( ':', $values[1] ) + if ( defined( $values[1] ) ); + ( $value5, $value6 ) = split( ':', $values[2] ) + if ( defined( $values[2] ) ); + ( $value7, $value8 ) = split( ':', $values[3] ) + 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} ) + && $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 = shift; + + $shutters->setShuttersDev($shuttersDev); + + my $brightnessMinVal = ( + $shutters->getBrightnessMinVal > -1 + ? $shutters->getBrightnessMinVal + : $ascDev->getBrightnessMinVal + ); + + my $brightnessMaxVal = ( + $shutters->getBrightnessMaxVal > -1 + ? $shutters->getBrightnessMaxVal + : $ascDev->getBrightnessMaxVal + ); + + my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) > + ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 ); + my $respIsDay = $isday; + + ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay ); + + if ( + ( + ( + ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeUpEarly ) + / 86400 + ) + && !IsWe() + ) + || ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ) / 86400 + ) + && IsWe() + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' + ) + ) + && int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeUpLate ) / 86400 + ) + ) + || ( + int( gettimeofday() / 86400 ) != int( + computeAlignTime( '24:00', $shutters->getTimeDownEarly ) / + 86400 + ) + && int( gettimeofday() / 86400 ) == int( + computeAlignTime( '24:00', $shutters->getTimeDownLate ) / 86400 + ) + ) + ) + { + ##### Nach Sonnenuntergang / Abends + $respIsDay = ( + ( + ( + $shutters->getBrightness > $brightnessMinVal + && $isday + && !$shutters->getSunset + ) + || !$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 + && !$isday + && $shutters->getSunrise + ) + || $respIsDay + || $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 = shift; + my $tm = shift; # 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() || IsWe('tomorrow') ) + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' ) + { + if ( !IsWe('tomorrow') ) { + if ( + IsWe() + && 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() + && ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', + sunrise_abs( + $autoAstroMode, 0, + $shutters->getTimeUpWeHoliday + ) + ) + 1 + ) / 86400 + ) + || 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) + && ref($oldFuncHash) eq 'HASH' + && ( IsWe() || IsWe('tomorrow') ) + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' ) + { + if ( !IsWe('tomorrow') ) { + 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 ) + && $oldFuncHash->{sunrisetime} < gettimeofday() ); + } + } + } + elsif ( defined($oldFuncHash) && ref($oldFuncHash) eq 'HASH' ) { + $shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 ) + if ( $shuttersSunriseUnixtime < + ( $oldFuncHash->{sunrisetime} + 180 ) + && $oldFuncHash->{sunrisetime} < gettimeofday() ); + } + } + elsif ( $shutters->getUp eq 'time' ) { + if ( ( IsWe() || IsWe('tomorrow') ) + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' ) + { + if ( !IsWe('tomorrow') ) { + 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 + ) + && $shutters->getSunrise + ) + { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', $shutters->getTimeUpEarly ) + + 86400; + } + else { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', + $shutters->getTimeUpEarly ); + } + } + else { + if ( + IsWe() + && 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' ) { + if ( ( IsWe() || IsWe('tomorrow') ) + && $ascDev->getSunriseTimeWeHoliday eq 'on' + && $shutters->getTimeUpWeHoliday ne '01:25' ) + { + if ( !IsWe('tomorrow') ) { + if ( + IsWe() + && 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->getTimeUpLate + ) + ) / 86400 + ) + ) + { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ); + } + else { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', $shutters->getTimeUpLate ); + } + } + else { + if ( + IsWe() + && ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', $shutters->getTimeUpWeHoliday + ) + ) / 86400 + ) + || 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->getTimeUpLate + ) + ) / 86400 + ) + ) + { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', $shutters->getTimeUpLate ); + } + else { + if ( + int( gettimeofday() / 86400 ) == int( + ( + computeAlignTime( + '24:00', $shutters->getTimeUpWeHoliday + ) + ) / 86400 + ) + ) + { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ); + } + else { + $shuttersSunriseUnixtime = + computeAlignTime( '24:00', + $shutters->getTimeUpWeHoliday ); + } + } + } + } + else { + + $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' ); + } + + return; +} + +sub IsAfterShuttersTimeBlocking { + my $shuttersDev = shift; + + $shutters->setShuttersDev($shuttersDev); + + if ( + ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < + $shutters->getBlockingTimeAfterManual + || ( !$shutters->getIsDay + && defined( $shutters->getSunriseUnixTime ) + && $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) < + $shutters->getBlockingTimeBeforDayOpen ) + || ( $shutters->getIsDay + && defined( $shutters->getSunriseUnixTime ) + && $shutters->getSunsetUnixTime - ( int( gettimeofday() ) ) < + $shutters->getBlockingTimeBeforNightClose ) + ) + { + return 0; + } + + else { return 1 } +} + +sub IsAfterShuttersManualBlocking { + my $shuttersDev = shift; + $shutters->setShuttersDev($shuttersDev); + + if ( $ascDev->getBlockAscDrivesAfterManual + && $shutters->getStatus != $shutters->getOpenPos + && $shutters->getStatus != $shutters->getClosedPos + && $shutters->getStatus != $shutters->getWindPos + && $shutters->getStatus != $shutters->getShadingPos + && $shutters->getStatus != $shutters->getComfortOpenPos + && $shutters->getStatus != $shutters->getVentilatePos + && $shutters->getStatus != $shutters->getAntiFreezePos + && $shutters->getLastDrive eq 'manual' ) + { + return 0; + } + elsif ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) < + $shutters->getBlockingTimeAfterManual ) + { + return 0; + } + + else { return 1 } +} + +sub ShuttersSunset { + my $shuttersDev = shift; + my $tm = shift; # 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) && ref($oldFuncHash) eq 'HASH' ) { + $shuttersSunsetUnixtime += 86400 + if ( $shuttersSunsetUnixtime < + ( $oldFuncHash->{sunsettime} + 180 ) + && $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' ); + } + + return; +} + +## Kontrolliert ob das Fenster von einem bestimmten Rolladen offen ist +sub CheckIfShuttersWindowRecOpen { + my $shuttersDev = shift; + $shutters->setShuttersDev($shuttersDev); + + if ( $shutters->getWinStatus =~ + m{[Oo]pen|false}xms ) # CK: covers: open|opened + { + return 2; + } + elsif ($shutters->getWinStatus =~ m{tilt}xms + && $shutters->getSubTyp eq 'threestate' ) # CK: covers: tilt|tilted + { + return 1; + } + elsif ( $shutters->getWinStatus =~ m{[Cc]lose|true}xms ) { + return 0; + } # CK: covers: close|closed +} + +sub makeReadingName { + my ($rname) = shift; + 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{^\./}xms ); + $rname =~ s/([$charHashkeys])/$charHash{$1}/xgi; + $rname =~ s/[^a-z0-9._\-\/]/_/xgi; + return $rname; +} + +sub TimeMin2Sec { + my $min = shift; + my $sec; + + $sec = $min * 60; + return $sec; +} + +sub IsWe { + return main::IsWe( shift, shift ); +} + +sub _DetermineSlatCmd { + my $value = shift; + my $posValue = shift; + + return $posValue == $shutters->getShadingPos + && $shutters->getShadingPositionAssignment ne 'none' ? $shutters->getShadingPositionAssignment + : $posValue == $shutters->getVentilatePos + && $shutters->getVentilatePositionAssignment ne 'none' ? $shutters->getVentilatePositionAssignment + : $posValue == $shutters->getOpenPos + && $shutters->getOpenPositionAssignment ne 'none' ? $shutters->getOpenPositionAssignment + : $posValue == $shutters->getClosedPos + && $shutters->getClosedPositionAssignment ne 'none' ? $shutters->getClosedPositionAssignment + : $posValue == $shutters->getSleepPos + && $shutters->getSleepPositionAssignment ne 'none' ? $shutters->getSleepPositionAssignment + : $posValue == $shutters->getComfortOpenPos + && $shutters->getComfortOpenPositionAssignment ne 'none' ? $shutters->getComfortOpenPositionAssignment + : $posValue == $shutters->getPrivacyUpPos + && $shutters->getPrivacyUpPositionAssignment ne 'none' ? $shutters->getPrivacyUpPositionAssignment + : $posValue == $shutters->getPrivacyDownPos + && $shutters->getPrivacyDownPositionAssignment ne 'none' ? $shutters->getPrivacyDownPositionAssignment + : $value; +} + +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' + && $ascDev->getASCenable eq 'on' + && ( $idleDetection =~ m{^$idleDetectionValue$}xms + || $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 ); + + my $driveCommand = $shutters->getPosSetCmd . ' ' . $posValue; + my $slatPos = -1; + + if ( $shutters->getShadingPositionAssignment ne 'none' + || $shutters->getOpenPositionAssignment ne 'none' + || $shutters->getClosedPositionAssignment ne 'none' + || $shutters->getPrivacyUpPositionAssignment ne 'none' + || $shutters->getPrivacyDownPositionAssignment ne 'none' + || $shutters->getSleepPositionAssignment ne 'none' + || $shutters->getVentilatePositionAssignment ne 'none' + || $shutters->getComfortOpenPositionAssignment ne 'none' ) + { + if ( + ( + $shutters->getShadingPositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getShadingPositionAssignment ne 'none' + ) + || ( $shutters->getOpenPositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getOpenPositionAssignment ne 'none' ) + || ( $shutters->getClosedPositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getClosedPositionAssignment ne 'none' ) + || ( + $shutters->getPrivacyUpPositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getPrivacyUpPositionAssignment ne 'none' ) + || ( $shutters->getPrivacyDownPositionAssignment =~ + m{\A[a-zA-Z]+\z}xms + && $shutters->getPrivacyDownPositionAssignment ne 'none' ) + || ( $shutters->getSleepPositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getSleepPositionAssignment ne 'none' ) + || ( + $shutters->getVentilatePositionAssignment =~ m{\A[a-zA-Z]+\z}xms + && $shutters->getVentilatePositionAssignment ne 'none' ) + || ( $shutters->getComfortOpenPositionAssignment =~ + m{\A[a-zA-Z]+\z}xms + && $shutters->getComfortOpenPositionAssignment ne 'none' ) + ) + { + $driveCommand = _DetermineSlatCmd( $driveCommand, $posValue ); + } + elsif ($shutters->getShadingPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getOpenPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getClosedPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getPrivacyUpPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getPrivacyDownPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getSleepPositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getVentilatePositionAssignment =~ m{\A\d{1,3}\z}xms + || $shutters->getComfortOpenPositionAssignment =~ + m{\A\d{1,3}\z}xms ) + { + $slatPos = _DetermineSlatCmd( $slatPos, $posValue ); + } + } + + if ( $ascDev->getSlatDriveCmdInverse + && $slatPos > -1 + && $shutters->getSlatPosCmd ne 'none' ) + { + CommandSet( + undef, + ( + $shutters->getSlatDevice ne 'none' + ? $shutters->getSlatDevice + : $shuttersDev + ) + . ' ' + . $shutters->getSlatPosCmd . ' ' + . $slatPos + ); + + InternalTimer( + gettimeofday() + 3, + sub() { + CommandSet( undef, + $shuttersDev + . ':FILTER=' + . $shutters->getPosCmd . '!=' + . $posValue . ' ' + . $driveCommand ); + }, + $shuttersDev + ); + } + else { + CommandSet( undef, + $shuttersDev + . ':FILTER=' + . $shutters->getPosCmd . '!=' + . $posValue . ' ' + . $driveCommand ); + + InternalTimer( + gettimeofday() + 3, + sub() { + CommandSet( + undef, + ( + $shutters->getSlatDevice ne 'none' + ? $shutters->getSlatDevice + : $shuttersDev + ) + . ' ' + . $shutters->getSlatPosCmd . ' ' + . $slatPos + ); + }, + $shuttersDev + ) + if ( $slatPos > -1 + && $shutters->getSlatPosCmd ne 'none' ); + } + + $shutters->setSelfDefenseAbsent( 0, 0 ) + if (!$shutters->getSelfDefenseAbsent + && $shutters->getSelfDefenseAbsentTimerrun ); + + return; +} + +sub _setShuttersLastDriveDelayed { + my $h = shift; + + my $shuttersDevHash = $h->{devHash}; + my $lastDrive = $h->{lastDrive}; + + readingsSingleUpdate( $shuttersDevHash, 'ASC_ShuttersLastDrive', + $lastDrive, 1 ); + + return; +} + +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" + ) + ); + + return; +} + +sub _averageBrightness { + my @input = @_; + use List::Util qw(sum); + + return int( sum(@input) / @input ); +} + +sub _perlCodeCheck { + my $exec = shift; + my $val = undef; + + if ( $exec =~ m{\A\{(.+)\}\z}xms ) { + $val = main::AnalyzePerlCommand( undef, $1 ); + } + + return $val; +} + +sub PrivacyUpTime { + my $shuttersDevHash = shift; + my $shuttersSunriseUnixtime = shift; + + my $privacyUpUnixtime; + + if ( ( $shuttersSunriseUnixtime - $shutters->getPrivacyUpTime ) > + ( gettimeofday() + 1 ) + || $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 = shift; + my $shuttersSunsetUnixtime = shift; + + my $privacyDownUnixtime; + + if ( ( $shuttersSunsetUnixtime - $shutters->getPrivacyDownTime ) > + ( gettimeofday() + 1 ) + || $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 = shift; + + $hash = $defs{$hash} if ( ref($hash) ne 'HASH' ); + + return 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 ) =~ m{.*asleep$}xms ) { + return '.*:scene_sleeping'; + } + elsif ( ReadingsVal( $name, 'state', undef ) =~ + m{^roommate(.come)?.(awoken|home)$}xms ) + { + return '.*:user_available'; + } + elsif ( ReadingsVal( $name, 'state', undef ) =~ + m{^residents.(home|awoken)$}xms ) + { + 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 ) =~ m{^selfDefense.*.active$}xms ) + { + 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 ) =~ m{.*privacy.*}xms ) { + return '.*:fts_shutter_50'; + } + elsif ( ReadingsVal( $name, 'state', undef ) eq 'adv delay close' ) { + return '.*:christmas_tree'; + } + + return; +} + +sub _CheckASC_ConditionsForShadingFn { + my $hash = shift; + + my $error; + + $error .= +' no valid data from the ASC temperature sensor, is ASC_tempSensor attribut set?' + if ( $ascDev->getOutTemp == -100 ); + $error .= ' no twilight device found' + if ( $ascDev->_getTwilightDevice eq 'none' ); + + my $count = 1; + for my $shuttersDev ( @{ $hash->{helper}{shuttersList} } ) { + InternalTimer( + gettimeofday() + $count, +'FHEM::Automation::ShuttersControl::_CheckShuttersConditionsForShadingFn', + $shuttersDev + ); + + $count++; + } + + return ( + defined($error) + ? $error + : 'none' + ); +} + +sub _CheckShuttersConditionsForShadingFn { + my $shuttersDev = shift; + + $shutters->setShuttersDev($shuttersDev); + my $shuttersDevHash = $defs{$shuttersDev}; + my $message = ''; + my $errorMessage; + my $warnMessage; + my $infoMessage; + + $infoMessage .= ( + $shutters->getShadingMode eq 'off' + && $ascDev->getAutoShuttersControlShading eq 'on' + ? ' global shading active but ASC_Shading_Mode attribut is not set or off' + : '' + ); + + $infoMessage .= ( + $shutters->getShadingMode ne 'off' + && $ascDev->getAutoShuttersControlShading eq 'on' + && $shutters->getOutTemp == -100 + ? ' shading active, global temp sensor is set, but shutters temperature sensor is not set' + : '' + ); + + $errorMessage .= ( + $shutters->getShadingMode ne 'off' + && $ascDev->getAutoShuttersControlShading ne 'on' + && $ascDev->getAutoShuttersControlShading ne 'off' + ? ' ASC_Shading_Mode attribut is set but global shading has errors, look at ASC device ' + . '' + . ReadingsVal( $shuttersDev, 'associatedWith', 'ASC device' ) + . '' + : '' + ); + + $errorMessage .= ( + $shutters->getBrightness == -1 && $shutters->getShadingMode ne 'off' + ? ' no brightness sensor found, please set ASC_BrightnessSensor attribut' + : '' + ); + + $message .= ' ERROR: ' . $errorMessage + if ( defined($errorMessage) + && $errorMessage ne '' ); + + $message .= ' WARN: ' . $warnMessage + if ( defined($warnMessage) + && $warnMessage ne '' + && $errorMessage eq '' ); + + $message .= ' INFO: ' . $infoMessage + if ( defined($infoMessage) + && $infoMessage ne '' + && $errorMessage eq '' ); + + readingsBeginUpdate($shuttersDevHash); + readingsBulkUpdateIfChanged( $shuttersDevHash, 'ASC_ShadingMessage', + '' . $message . ' ' ); + readingsEndUpdate( $shuttersDevHash, 1 ); +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Dev.pm b/lib/FHEM/Automation/ShuttersControl/Dev.pm new file mode 100644 index 0000000..6975a3f --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Dev.pm @@ -0,0 +1,83 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Klasse ASC_Dev plus Subklassen ASC_Attr_Dev und ASC_Readings_Dev## +package FHEM::Automation::ShuttersControl::Dev; + +use FHEM::Automation::ShuttersControl::Dev::Readings; +use FHEM::Automation::ShuttersControl::Dev::Attr; + +our @ISA = + qw(FHEM::Automation::ShuttersControl::Dev::Readings FHEM::Automation::ShuttersControl::Dev::Attr); + +use strict; +use warnings; +use utf8; + +sub new { + my $class = shift; + + my $self = { name => undef, }; + + bless $self, $class; + return $self; +} + +sub setName { + my $self = shift; + my $name = shift; + + $self->{name} = $name if ( defined($name) ); + return $self->{name}; +} + +sub setDefault { + my $self = shift; + my $defaultarg = shift; + + $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); + return $self->{defaultarg}; +} + +sub getName { + my $self = shift; + return $self->{name}; +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm b/lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm new file mode 100644 index 0000000..3fa278b --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Dev/Attr.pm @@ -0,0 +1,389 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Attr ## +package FHEM::Automation::ShuttersControl::Dev::Attr; + +use strict; +use warnings; +use utf8; + +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} ) + && ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 ); + $self->{ASC_brightness}->{LASTGETTIME} = int( gettimeofday() ); + + my ( $triggermax, $triggermin ) = + FHEM::Automation::ShuttersControl::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 getSlatDriveCmdInverse { + my $self = shift; + + my $name = $self->{name}; + + return AttrVal( $name, 'ASC_slatDriveCmdInverse', 0 ); +} + +sub _getTempSensor { + my $self = shift; + + my $name = $self->{name}; + + return $self->{ASC_tempSensor}->{device} + if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} ) + && ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_tempSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::Automation::ShuttersControl::GetAttrValues( $name, 'ASC_tempSensor', + 'none' ); + + ## erwartetes Ergebnis + # DEVICE:READING + $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} ) + && ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 ); + $self->{ASC_residentsDev}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_rainSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading, $max, $hyst, $pos, $wait ) = + FHEM::Automation::ShuttersControl::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 + : $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); + $self->{ASC_windSensor}->{LASTGETTIME} = int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::Automation::ShuttersControl::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} ) + && ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 ); + $FHEM::Automation::ShuttersControl::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; diff --git a/lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm b/lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm new file mode 100644 index 0000000..4ec4f1b --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Dev/Readings.pm @@ -0,0 +1,287 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Readings ## +package FHEM::Automation::ShuttersControl::Dev::Readings; + +use strict; +use warnings; +use utf8; + +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, + $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . '_lastDelayPosValue', + $FHEM::Automation::ShuttersControl::shutters->getDelayCmd, + 1 + ); + return; +} + +sub setStateReading { + my $self = shift; + my $value = shift; + + my $name = $self->{name}; + my $hash = $defs{$name}; + + readingsSingleUpdate( + $hash, 'state', + ( + defined($value) + ? $value + : $FHEM::Automation::ShuttersControl::shutters->getLastDrive + ), + 1 + ); + return; +} + +sub setPosReading { + my $self = shift; + + my $name = $self->{name}; + my $hash = $defs{$name}; + + readingsSingleUpdate( + $hash, + $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . '_PosValue', + $FHEM::Automation::ShuttersControl::shutters->getStatus, + 1 + ); + return; +} + +sub setLastPosReading { + my $self = shift; + + my $name = $self->{name}; + my $hash = $defs{$name}; + + readingsSingleUpdate( + $hash, + $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . '_lastPosValue', + $FHEM::Automation::ShuttersControl::shutters->getLastPos, + 1 + ); + return; +} + +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( + $FHEM::Automation::ShuttersControl::ascDev->_getTempSensor, + $FHEM::Automation::ShuttersControl::ascDev->getTempSensorReading, + -100 ); +} + +sub getResidentsStatus { + my $self = shift; + + my $val = + ReadingsVal( $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, + $FHEM::Automation::ShuttersControl::ascDev->getResidentsReading, + 'none' ); + + if ( $val =~ m{^(?:(.+)_)?(.+)$}xms ) { + return ( $1, $2 ) if (wantarray); + return $1 && $1 eq 'pet' ? 'absent' : $2; + } + elsif ( + ReadingsVal( + $FHEM::Automation::ShuttersControl::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( $FHEM::Automation::ShuttersControl::ascDev->_getResidentsDev, + 'lastState', 'none' ); + + if ( $val =~ m{^(?:(.+)_)?(.+)$}xms ) { + return ( $1, $2 ) if (wantarray); + return $1 && $1 eq 'pet' ? 'absent' : $2; + } + elsif ( + ReadingsVal( + $FHEM::Automation::ShuttersControl::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( + $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, + 'azimuth', -1 ) + if ( + $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } + ->{TYPE} eq 'Twilight' ); + $azimuth = ReadingsVal( + $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, + 'SunAz', -1 ) + if ( + $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } + ->{TYPE} eq 'Astro' ); + + return $azimuth; +} + +sub getElevation { + my $self = shift; + + my $elevation; + + $elevation = ReadingsVal( + $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, + 'elevation', -1 ) + if ( + $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } + ->{TYPE} eq 'Twilight' ); + $elevation = ReadingsVal( + $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice, + 'SunAlt', -1 ) + if ( + $defs{ $FHEM::Automation::ShuttersControl::ascDev->_getTwilightDevice } + ->{TYPE} eq 'Astro' ); + + return $elevation; +} + +sub getASCenable { + my $self = shift; + + my $name = $self->{name}; + + return ReadingsVal( $name, 'ascEnable', 'none' ); +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Roommate.pm b/lib/FHEM/Automation/ShuttersControl/Roommate.pm new file mode 100644 index 0000000..a0da8c1 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Roommate.pm @@ -0,0 +1,77 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Klasse ASC_Roommate ## +package FHEM::Automation::ShuttersControl::Roommate; + +use strict; +use warnings; +use utf8; + +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, + $FHEM::Automation::ShuttersControl::shutters->getRoommatesReading, + 'none' ); +} + +sub _getRoommateLastStatus { + my $self = shift; + + my $roommate = $self->{roommate}; + my $default = $self->{defaultarg}; + + $default = 'none' if ( !defined($default) ); + return ReadingsVal( $roommate, 'lastState', $default ); +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Shutters.pm b/lib/FHEM/Automation/ShuttersControl/Shutters.pm new file mode 100644 index 0000000..8a82c9f --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Shutters.pm @@ -0,0 +1,1027 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +###################################### +###################################### +########## 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 FHEM::Automation::ShuttersControl::Shutters; + +use FHEM::Automation::ShuttersControl::Shutters::Readings; +use FHEM::Automation::ShuttersControl::Shutters::Attr; +use FHEM::Automation::ShuttersControl::Roommate; +use FHEM::Automation::ShuttersControl::Window; + +our @ISA = + qw(FHEM::Automation::ShuttersControl::Shutters::Readings FHEM::Automation::ShuttersControl::Shutters::Attr FHEM::Automation::ShuttersControl::Roommate FHEM::Automation::ShuttersControl::Window); + +use strict; +use warnings; +use utf8; + +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 = shift; + my $shuttersDev = shift; + + $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; +} + +sub setHardLockOut { + my $self = shift; + my $cmd = shift; + + if ( $FHEM::Automation::ShuttersControl::shutters->getLockOut eq 'hard' + && $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd ne + 'none' ) + { + CommandSet( undef, $self->{shuttersDev} . ' inhibit ' . $cmd ) + if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq + 'inhibit' ); + CommandSet( undef, + $self->{shuttersDev} . ' ' + . ( $cmd eq 'on' ? 'blocked' : 'unblocked' ) ) + if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq + 'blocked' ); + CommandSet( undef, + $self->{shuttersDev} . ' ' + . ( $cmd eq 'on' ? 'protectionOn' : 'protectionOff' ) ) + if ( $FHEM::Automation::ShuttersControl::shutters->getLockOutCmd eq + 'protected' ); + } + return; +} + +sub setNoDelay { + my $self = shift; + my $noDelay = shift; + + $self->{ $self->{shuttersDev} }{noDelay} = $noDelay; + return; +} + +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; +} + +sub setDriveCmd { + my $self = shift; + my $posValue = shift; + + my $offSet; + my $offSetStart; + + if ( + ( + $FHEM::Automation::ShuttersControl::shutters->getPartyMode eq 'on' + && $FHEM::Automation::ShuttersControl::ascDev->getPartyMode eq 'on' + ) + || ( + $FHEM::Automation::ShuttersControl::shutters->getAdv + && !$FHEM::Automation::ShuttersControl::shutters + ->getQueryShuttersPos( + $posValue) + && !$FHEM::Automation::ShuttersControl::shutters->getAdvDelay + && !$FHEM::Automation::ShuttersControl::shutters + ->getExternalTriggerState + && !$FHEM::Automation::ShuttersControl::shutters + ->getSelfDefenseState + ) + ) + { + $FHEM::Automation::ShuttersControl::shutters->setDelayCmd($posValue); + $FHEM::Automation::ShuttersControl::ascDev->setDelayCmdReading; + $FHEM::Automation::ShuttersControl::shutters->setNoDelay(0); + $FHEM::Automation::ShuttersControl::shutters->setExternalTriggerState(0) + if ( $FHEM::Automation::ShuttersControl::shutters + ->getExternalTriggerState ); + + FHEM::Automation::ShuttersControl::ASC_Debug( 'setDriveCmd: ' + . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . ' - Die Fahrt wird zurückgestellt. Grund kann ein geöffnetes Fenster sein oder ein aktivierter Party Modus oder Weihnachtszeit' + ); + } + else { + $FHEM::Automation::ShuttersControl::shutters->setAdvDelay(0) + if ( $FHEM::Automation::ShuttersControl::shutters->getAdvDelay ); + $FHEM::Automation::ShuttersControl::shutters->setDelayCmd('none') + if ( $FHEM::Automation::ShuttersControl::shutters->getDelayCmd ne + 'none' ) + ; # setzt den Wert auf none da der Rolladen nun gesteuert werden kann. + $FHEM::Automation::ShuttersControl::shutters->setExternalTriggerState(0) + if ( $FHEM::Automation::ShuttersControl::shutters + ->getExternalTriggerState ); + + ### antifreeze Routine + if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreezeStatus > + 0 ) + { + if ( $FHEM::Automation::ShuttersControl::shutters + ->getAntiFreezeStatus != 1 ) + { + + $posValue = + $FHEM::Automation::ShuttersControl::shutters->getStatus; + $FHEM::Automation::ShuttersControl::shutters->setLastDrive( + 'no drive - antifreeze defense'); + $FHEM::Automation::ShuttersControl::shutters + ->setLastDriveReading; + $FHEM::Automation::ShuttersControl::ascDev->setStateReading; + } + elsif ( $posValue == + $FHEM::Automation::ShuttersControl::shutters->getClosedPos ) + { + $posValue = $FHEM::Automation::ShuttersControl::shutters + ->getAntiFreezePos; + $FHEM::Automation::ShuttersControl::shutters->setLastDrive( + $FHEM::Automation::ShuttersControl::shutters->getLastDrive + . ' - antifreeze mode' ); + } + } + + my %h = ( + shuttersDev => $self->{shuttersDev}, + posValue => $posValue, + ); + + $offSet = $FHEM::Automation::ShuttersControl::shutters->getDelay + if ( $FHEM::Automation::ShuttersControl::shutters->getDelay > -1 ); + $offSet = $FHEM::Automation::ShuttersControl::ascDev->getShuttersOffset + if ( $FHEM::Automation::ShuttersControl::shutters->getDelay < 0 ); + $offSetStart = + $FHEM::Automation::ShuttersControl::shutters->getDelayStart; + + if ( $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseAbsent + && !$FHEM::Automation::ShuttersControl::shutters + ->getSelfDefenseAbsentTimerrun + && $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseMode + ne 'off' + && $FHEM::Automation::ShuttersControl::shutters->getSelfDefenseState + && $FHEM::Automation::ShuttersControl::ascDev->getSelfDefense eq + 'on' ) + { + InternalTimer( + gettimeofday() + + $FHEM::Automation::ShuttersControl::shutters + ->getSelfDefenseAbsentDelay, + \&FHEM::Automation::ShuttersControl::_SetCmdFn, \%h + ); + $FHEM::Automation::ShuttersControl::shutters->setSelfDefenseAbsent( + 1, 0, \%h ); + } + elsif ( $offSetStart > 0 + && !$FHEM::Automation::ShuttersControl::shutters->getNoDelay ) + { + InternalTimer( + gettimeofday() + int( + rand($offSet) + + $FHEM::Automation::ShuttersControl::shutters + ->getDelayStart + ), + \&FHEM::Automation::ShuttersControl::_SetCmdFn, + \%h + ); + + FHEM::Automation::ShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' + . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . ' - versetztes fahren' ); + } + elsif ($offSetStart < 1 + || $FHEM::Automation::ShuttersControl::shutters->getNoDelay ) + { + FHEM::Automation::ShuttersControl::_SetCmdFn( \%h ); + FHEM::Automation::ShuttersControl::ASC_Debug( 'FnSetDriveCmd: ' + . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . ' - NICHT versetztes fahren' ); + } + + FHEM::Automation::ShuttersControl::ASC_Debug( + 'FnSetDriveCmd: ' + . $FHEM::Automation::ShuttersControl::shutters->getShuttersDev + . ' - NoDelay: ' + . ( + $FHEM::Automation::ShuttersControl::shutters->getNoDelay + ? 'JA' + : 'NEIN' + ) + ); + $FHEM::Automation::ShuttersControl::shutters->setNoDelay(0); + } + + return; +} + +sub setSunsetUnixTime { + my $self = shift; + my $unixtime = shift; + + $self->{ $self->{shuttersDev} }{sunsettime} = $unixtime; + return; +} + +sub setSunset { + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }{sunset} = $value; + return; +} + +sub setSunriseUnixTime { + my $self = shift; + my $unixtime = shift; + + $self->{ $self->{shuttersDev} }{sunrisetime} = $unixtime; + return; +} + +sub setSunrise { + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }{sunrise} = $value; + return; +} + +sub setDelayCmd { + my $self = shift; + my $posValue = shift; + + $self->{ $self->{shuttersDev} }{delayCmd} = $posValue; + return; +} + +sub setLastDrive { + my $self = shift; + my $lastDrive = shift; + + $self->{ $self->{shuttersDev} }{lastDrive} = $lastDrive; + return; +} + +sub setPosSetCmd { + my $self = shift; + my $posSetCmd = shift; + + $self->{ $self->{shuttersDev} }{posSetCmd} = $posSetCmd; + return; +} + +sub setLastDriveReading { + my $self = shift; + my $shuttersDevHash = $defs{ $self->{shuttersDev} }; + + my %h = ( + devHash => $shuttersDevHash, + lastDrive => $FHEM::Automation::ShuttersControl::shutters->getLastDrive, + ); + + InternalTimer( gettimeofday() + 0.1, + \&FHEM::Automation::ShuttersControl::_setShuttersLastDriveDelayed, + \%h ); + return; +} + +sub setLastPos { + +# letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde + my $self = shift; + my $position = shift; + + $self->{ $self->{shuttersDev} }{lastPos}{VAL} = $position + if ( defined($position) ); + $self->{ $self->{shuttersDev} }{lastPos}{TIME} = int( gettimeofday() ) + if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) ); + return; +} + +sub setLastManPos { + my $self = shift; + my $position = shift; + + $self->{ $self->{shuttersDev} }{lastManPos}{VAL} = $position + if ( defined($position) ); + $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( gettimeofday() ) + if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) + && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); + $self->{ $self->{shuttersDev} }{lastManPos}{TIME} = + int( gettimeofday() ) - 86400 + if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} ) + && !defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) ); + return; +} + +sub setDefault { + my $self = shift; + my $defaultarg = shift; + + $self->{defaultarg} = $defaultarg if ( defined($defaultarg) ); + return $self->{defaultarg}; +} + +sub setRoommate { + my $self = shift; + my $roommate = shift; + + $self->{roommate} = $roommate if ( defined($roommate) ); + return $self->{roommate}; +} + +sub setInTimerFuncHash { + my $self = shift; + my $inTimerFuncHash = shift; + + $self->{ $self->{shuttersDev} }{inTimerFuncHash} = $inTimerFuncHash + if ( defined($inTimerFuncHash) ); + return; +} + +sub setPrivacyDownStatus { + my $self = shift; + my $statusValue = shift; + + $self->{ $self->{shuttersDev} }->{privacyDownStatus} = $statusValue; + return; +} + +sub setPrivacyUpStatus { + my $self = shift; + my $statusValue = shift; + + $self->{ $self->{shuttersDev} }->{privacyUpStatus} = $statusValue; + return; +} + +sub setSelfDefenseState { + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }{selfDefenseState} = $value; + return; +} + +sub setAdvDelay { + my $self = shift; + my $advDelay = shift; + + $self->{ $self->{shuttersDev} }->{AdvDelay} = $advDelay; + return; +} + +sub getHomemode { + my $self = shift; + + my $homemode = + $FHEM::Automation::ShuttersControl::shutters->getRoommatesStatus; + $homemode = $FHEM::Automation::ShuttersControl::ascDev->getResidentsStatus + if ( $homemode eq 'none' ); + return $homemode; +} + +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 = shift; + my $attr = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{AttrUpdateChanges} ) + && defined( + $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} ) + ? $self->{ $self->{shuttersDev} }{AttrUpdateChanges}{$attr} + : 'none' + ); +} + +sub getIsDay { + my $self = shift; + + return FHEM::Automation::ShuttersControl::_IsDay( $self->{shuttersDev} ); +} + +sub getAntiFreezeStatus { + use POSIX qw(strftime); + my $self = shift; + my $daytime = strftime( "%P", localtime() ); + $daytime = ( + defined($daytime) && $daytime + ? $daytime + : ( strftime( "%k", localtime() ) < 12 ? 'am' : 'pm' ) + ); + my $outTemp = $FHEM::Automation::ShuttersControl::ascDev->getOutTemp; + +# $outTemp = $FHEM::Automation::ShuttersControl::shutters->getOutTemp if ( $FHEM::Automation::ShuttersControl::shutters->getOutTemp != -100 ); sollte raus das der Sensor im Rollo auch ein Innentemperatursensor sein kann. + + if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze ne 'off' + && $outTemp <= + $FHEM::Automation::ShuttersControl::ascDev->getFreezeTemp ) + { + + if ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq + 'soft' ) + { + return 1; + } + elsif ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq + $daytime ) + { + return 2; + } + elsif ( $FHEM::Automation::ShuttersControl::shutters->getAntiFreeze eq + 'hard' ) + { + return 3; + } + } + else { return 0; } +} + +sub getShuttersPosCmdValueNegate { + my $self = shift; + + return ( $FHEM::Automation::ShuttersControl::shutters->getOpenPos < + $FHEM::Automation::ShuttersControl::shutters->getClosedPos ? 1 : 0 ); +} + +sub getQueryShuttersPos +{ # Es wird geschaut ob die aktuelle Position des Rollos unterhalb der Zielposition ist + my $self = shift; + my $posValue = shift; # wenn dem so ist wird 1 zurück gegeben ansonsten 0 + + return ( + $FHEM::Automation::ShuttersControl::shutters + ->getShuttersPosCmdValueNegate + ? $FHEM::Automation::ShuttersControl::shutters->getStatus > $posValue + : $FHEM::Automation::ShuttersControl::shutters->getStatus < $posValue + ); +} + +sub getPosSetCmd { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{posSetCmd} ) + ? $self->{ $self->{shuttersDev} }{posSetCmd} + : $FHEM::Automation::ShuttersControl::shutters->getPosCmd + ); +} + +sub getNoDelay { + my $self = shift; + + return $self->{ $self->{shuttersDev} }{noDelay}; +} + +sub getSelfDefenseState { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{selfDefenseState} ) + ? $self->{ $self->{shuttersDev} }{selfDefenseState} + : 0 + ); +} + +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 ( + defined( + $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} + ) + ? $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} + : undef + ); +} + +sub getLastDrive { + my $self = shift; + + $self->{ $self->{shuttersDev} }{lastDrive} = + ReadingsVal( $self->{shuttersDev}, 'ASC_ShuttersLastDrive', 'none' ) + if ( !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 ( + defined( $self->{ $self->{shuttersDev} }{lastPos} ) + && defined( $self->{ $self->{shuttersDev} }{lastPos}{VAL} ) + ? $self->{ $self->{shuttersDev} }{lastPos}{VAL} + : 50 + ); +} + +sub getLastPosTimestamp { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} } ) + && defined( $self->{ $self->{shuttersDev} }{lastPos} ) + && defined( $self->{ $self->{shuttersDev} }{lastPos}{TIME} ) + ? $self->{ $self->{shuttersDev} }{lastPos}{TIME} + : 0 + ); +} + +sub getLastManPos +{ # letzte ermittelte Position bevor die Position des Rolladen manuell (nicht über ASC) geändert wurde + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{lastManPos} ) + && defined( $self->{ $self->{shuttersDev} }{lastManPos}{VAL} ) + ? $self->{ $self->{shuttersDev} }{lastManPos}{VAL} + : 50 + ); +} + +sub getLastManPosTimestamp { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} } ) + && defined( $self->{ $self->{shuttersDev} }{lastManPos} ) + && defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) + ? $self->{ $self->{shuttersDev} }{lastManPos}{TIME} + : 0 + ); +} + +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; + + for my $ro ( + split( + ",", $FHEM::Automation::ShuttersControl::shutters->getRoommates + ) + ) + { + $FHEM::Automation::ShuttersControl::shutters->setRoommate($ro); + my $currentPrio = + $statePrio{ $FHEM::Automation::ShuttersControl::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; + + for my $ro ( + split( + ",", $FHEM::Automation::ShuttersControl::shutters->getRoommates + ) + ) + { + $FHEM::Automation::ShuttersControl::shutters->setRoommate($ro); + my $currentPrio = + $statePrio{ $FHEM::Automation::ShuttersControl::shutters + ->_getRoommateLastStatus }; + $minPrio = $currentPrio if ( $minPrio > $currentPrio ); + } + + my %revStatePrio = reverse %statePrio; + return $revStatePrio{$minPrio}; +} + +sub getOutTemp { + my $self = shift; + + return ReadingsVal( + $FHEM::Automation::ShuttersControl::shutters->_getTempSensor, + $FHEM::Automation::ShuttersControl::shutters->getTempSensorReading, + -100 ); +} + +sub getIdleDetection { + my $self = shift; + + return ReadingsVal( + $self->{shuttersDev}, + $FHEM::Automation::ShuttersControl::shutters->_getIdleDetectionReading, + 'none' + ); +} + +### Begin Beschattung Objekt mit Daten befüllen +sub setShadingStatus { + my $self = shift; + my $value = shift; ### Werte für value = in, out, in reserved, out reserved + + return + if ( defined($value) + && exists( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) + && $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} eq $value ); + + $FHEM::Automation::ShuttersControl::shutters->setShadingLastStatus( + ( $value eq 'in' ? 'out' : 'in' ) ) + if ( $value eq 'in' + || $value eq 'out' ); + + $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value + if ( defined($value) ); + $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = int( gettimeofday() ) + if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) ); + + return; +} + +sub setShadingLastStatus { + my $self = shift; + my $value = shift; ### Werte für value = in, out + + return + if ( defined($value) + && exists( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) + && $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} eq $value ); + + $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; +} + +sub setShadingManualDriveStatus { + my $self = shift; + my $value = shift; ### Werte für value = 0, 1 + + $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = $value + if ( defined($value) ); + + return; +} + +sub setWindProtectionStatus { # Werte protected, unprotected + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value + if ( defined($value) ); + + return; +} + +sub setRainProtectionStatus { # Werte protected, unprotected + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} = $value + if ( defined($value) ); + return; +} + +sub setExternalTriggerState { + my $self = shift; + my $value = shift; + + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{event} = $value + if ( defined($value) ); + + return; +} + +sub setPushBrightnessInArray { + my $self = shift; + my $value = shift; + + unshift( + @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} }, + $value + ); + pop( @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) + if ( + scalar( + @{ + $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} + } + ) > $FHEM::Automation::ShuttersControl::shutters + ->getMaxBrightnessAverageArrayObjects + ); + + return; +} + +sub getBrightnessAverage { + my $self = shift; + + return FHEM::Automation::ShuttersControl::_averageBrightness( + @{ $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} } ) + if ( + ref( $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} ) + eq 'ARRAY' + && scalar( + @{ + $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{VAL} + } + ) > 0 + ); + + return; +} + +sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) + && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) + ? $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} + : 'out' + ); +} + +sub getShadingLastStatus { # Werte für value = in, out + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) + && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} ) + ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} + : 'out' + ); +} + +sub getShadingManualDriveStatus { # Werte für value = 0, 1 + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus} ) + && defined( + $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} + ) + ? $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} + : 0 + ); +} + +sub getIfInShading { + my $self = shift; + + return ( + ( + $FHEM::Automation::ShuttersControl::shutters->getShadingMode ne + 'off' + && $FHEM::Automation::ShuttersControl::shutters + ->getShadingLastStatus eq 'out' + ) ? 1 : 0 + ); +} + +sub getWindProtectionStatus { # Werte protected, unprotected + my $self = shift; + + return ( + ( + defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} ) + && 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} ) + && defined( + $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} + ) + ) + ? $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} + : 'unprotected' + ); +} + +sub getShadingStatusTimestamp { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} } ) + && defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) + && defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) + ? $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} + : 0 + ); +} + +sub getShadingLastStatusTimestamp { + my $self = shift; + + return ( + defined( $self->{ $self->{shuttersDev} } ) + && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) + && defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} ) + ? $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} + : 0 + ); +} +### Ende Beschattung + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm b/lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm new file mode 100644 index 0000000..6126ab8 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Shutters/Attr.pm @@ -0,0 +1,1974 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Attr von ASC_Shutters## +package FHEM::Automation::ShuttersControl::Shutters::Attr; + +use strict; +use warnings; +use utf8; + +use GPUtils qw(GP_Import); + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw( + AttrVal + CommandAttr + gettimeofday) + ); +} + +sub _setAttributs { + my $shuttersDev = shift; + my $attr = shift; + my $attrVal = shift; + + CommandAttr( undef, $shuttersDev . ' ' . $attr . ' ' . $attrVal ); + + return; +} + +sub _getPosition { + my $self = shift; + + my $attr = shift; + my $userAttrList = shift; + + return $self->{ $self->{shuttersDev} }->{$attr}->{position} + if ( + exists( $self->{ $self->{shuttersDev} }->{$attr}->{LASTGETTIME} ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{$attr}->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{$attr}->{LASTGETTIME} = + int( gettimeofday() ); + + my $position; + my $posAssignment; + + if ( + AttrVal( $self->{shuttersDev}, $attr, + $FHEM::Automation::ShuttersControl::userAttrList{$userAttrList} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] ) =~ + m{\A\{.+\}\z}xms + ) + { + my $response = FHEM::Automation::ShuttersControl::_perlCodeCheck( + AttrVal( + $self->{shuttersDev}, + $attr, + $FHEM::Automation::ShuttersControl::userAttrList{$userAttrList} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] + ) + ); + + ( $position, $posAssignment ) = split ':', $response; + + $position = ( + $position =~ m{\A\d+(\.\d+)?\z}xms + ? $position + : $FHEM::Automation::ShuttersControl::userAttrList{$userAttrList} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] + ); + + $posAssignment = ( + $posAssignment =~ m{\A\d+(\.\d+)?\z}xms + ? $posAssignment + : 'none' + ); + } + else { + ( $position, $posAssignment ) = + FHEM::Automation::ShuttersControl::GetAttrValues( + $self->{shuttersDev}, + $attr, + $FHEM::Automation::ShuttersControl::userAttrList{$userAttrList} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] + ); + } + + ### erwartetes Ergebnis + # DEVICE:READING + $self->{ $self->{shuttersDev} }->{$attr}->{position} = $position; + $self->{ $self->{shuttersDev} }->{$attr}->{posAssignment} = + $posAssignment; + + return $self->{ $self->{shuttersDev} }->{$attr}->{position}; + + if ( + defined( + FHEM::Automation::ShuttersControl::_perlCodeCheck( + $self->{ $self->{shuttersDev} }->{$attr}->{position} + ) + ) + ) + { + $self->{ $self->{shuttersDev} }->{$attr}->{position} = + FHEM::Automation::ShuttersControl::_perlCodeCheck( + $self->{ $self->{shuttersDev} }->{$attr}->{position} ); + } + + return ( + $self->{ $self->{shuttersDev} }->{$attr}->{position} =~ + m{^\d+(\.\d+)?$}xms + ? $self->{ $self->{shuttersDev} }->{$attr}->{position} + : $FHEM::Automation::ShuttersControl::userAttrList{$userAttrList} + [ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] + ); +} + +sub _getPositionAssignment { + my $self = shift; + + my $attr = shift; + my $getFn = shift; + + return $self->{ $self->{shuttersDev} }->{$attr}->{posAssignment} + if ( + exists( $self->{ $self->{shuttersDev} }->{$attr}->{LASTGETTIME} ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{$attr}->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->$getFn; + + return ( $self->{ $self->{shuttersDev} }->{$attr}->{posAssignment} ); +} + +sub setAntiFreezePos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Antifreeze_Pos', $attrVal ); + + return; +} + +sub getAntiFreezePos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Antifreeze_Pos', +'ASC_Antifreeze_Pos:5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100' + ); +} + +sub getAntiFreezePosAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Antifreeze_Pos', 'getAntiFreezePos' ); +} + +sub setShuttersPlace { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_ShuttersPlace', $attrVal ); + + return; +} + +sub getShuttersPlace { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_ShuttersPlace', 'window' ); +} + +sub setSlatPosCmd { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_SlatPosCmd_SlatDevice', + $attrVal ); + + return; +} + +sub getSlatPosCmd { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{poscmd} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice}->{LASTGETTIME} + = int( gettimeofday() ); + my ( $slatPosCmd, $slatDevice ) = + FHEM::Automation::ShuttersControl::GetAttrValues( $self->{shuttersDev}, + 'ASC_SlatPosCmd_SlatDevice', 'none:none' ); + + ## Erwartetes Ergebnis + # upTime:upBrightnessVal + + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice}->{poscmd} = + $slatPosCmd; + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice}->{device} = + $slatDevice; + + return $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{poscmd}; +} + +sub getSlatDevice { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{device} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getSlatPosCmd; + + return ( + $self->{ $self->{shuttersDev} }->{ASC_SlatPosCmd_SlatDevice}->{device} + ); +} + +sub setPrivacyUpTime { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_PrivacyUpValue_beforeDayOpen', + $attrVal ); + + return; +} + +sub getPrivacyUpTime { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{uptime} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{LASTGETTIME} = int( gettimeofday() ); + my ( $upTime, $upBrightnessVal ) = + FHEM::Automation::ShuttersControl::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 ); + + $FHEM::Automation::ShuttersControl::shutters->setPrivacyUpStatus(0) + if ( + defined( + $FHEM::Automation::ShuttersControl::shutters->getPrivacyUpStatus + ) + && $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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getPrivacyUpTime; + + return ( + defined( + $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{upbrightnessval} + ) + ? $self->{ $self->{shuttersDev} }->{ASC_PrivacyUpValue_beforeDayOpen} + ->{upbrightnessval} + : -1 + ); +} + +sub setPrivacyDownTime { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, + 'ASC_PrivacyDownValue_beforeNightClose', $attrVal ); + + return; +} + +sub getPrivacyDownTime { + my $self = shift; + + return $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{downtime} + if ( + exists( + $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_PrivacyDownValue_beforeNightClose} + ->{LASTGETTIME} = int( gettimeofday() ); + my ( $downTime, $downBrightnessVal ) = + FHEM::Automation::ShuttersControl::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 ); + + $FHEM::Automation::ShuttersControl::shutters->setPrivacyDownStatus(0) + if ( + defined( + $FHEM::Automation::ShuttersControl::shutters->getPrivacyDownStatus + ) + && $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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getPrivacyDownTime; + + return ( + defined( + $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{downbrightnessval} + ) + ? $self->{ $self->{shuttersDev} } + ->{ASC_PrivacyDownValue_beforeNightClose}->{downbrightnessval} + : -1 + ); +} + +sub setPrivacyUpPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_PrivacyUp_Pos', $attrVal ); + + return; +} + +sub getPrivacyUpPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_PrivacyUp_Pos', 'ASC_PrivacyUp_Pos' ); +} + +sub getPrivacyUpPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_PrivacyUp_Pos', 'getPrivacyUpPos' ); +} + +sub setPrivacyDownPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_PrivacyDown_Pos', $attrVal ); + + return; +} + +sub getPrivacyDownPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_PrivacyDown_Pos', 'ASC_PrivacyDown_Pos' ); +} + +sub getPrivacyDownPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_PrivacyDown_Pos', 'getPrivacyDownPos' ); +} + +sub setSelfDefenseMode { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Self_Defense_Mode', $attrVal ); + + return; +} + +sub getSelfDefenseMode { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Self_Defense_Mode', 'gone' ); +} + +sub setSelfDefenseAbsentDelay { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Self_Defense_AbsentDelay', + $attrVal ); + + return; +} + +sub getSelfDefenseAbsentDelay { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Self_Defense_AbsentDelay', 300 ); +} + +sub setWiggleValue { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WiggleValue', $attrVal ); + + return; +} + +sub getWiggleValue { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_WiggleValue', 5 ); +} + +sub setAdv { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Adv', $attrVal ); + + return; +} + +sub getAdv { + my $self = shift; + + return ( + AttrVal( $self->{shuttersDev}, 'ASC_Adv', 'off' ) eq 'on' + ? ( \&FHEM::Automation::ShuttersControl::_IsAdv == 1 ? 1 : 0 ) + : 0 + ); +} + +### Begin Beschattung +sub setShadingPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_Pos', $attrVal ); + + return; +} + +sub getShadingPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Shading_Pos', 'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100' ); +} + +sub getShadingPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Shading_Pos', 'getShadingPos' ); +} + +sub setShadingMode { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_Mode', $attrVal ); + + return; +} + +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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) + < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} ) + < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->_getTempSensor; + + return ( + defined( $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} ) + ? $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} + : 'temperature' + ); +} + +sub setIdleDetectionReading { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shutter_IdleDetection', + $attrVal ); + + return; +} + +sub _getIdleDetectionReading { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} + ->{reading} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{LASTGETTIME} + = int( gettimeofday() ); + my ( $reading, $value ) = + FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->_getIdleDetectionReading; + + return ( + defined( + $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection} + ->{value} + ) + ? $self->{ $self->{shuttersDev} }->{ASC_Shutter_IdleDetection}->{value} + : 'none' + ); +} + +sub setBrightnessSensor { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_BrightnessSensor', $attrVal ); + + return; +} + +sub _getBrightnessSensor { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $device, $reading, $max, $min ) = + FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getShadingAzimuthRight; + + return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} + ->{leftVal}; +} + +sub setShadingInOutAzimuth { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_InOutAzimuth', $attrVal ); + + return; +} + +sub getShadingAzimuthRight { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} + ->{rightVal} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_Shading_InOutAzimuth}->{LASTGETTIME} + = int( gettimeofday() ); + my ( $left, $right ) = + FHEM::Automation::ShuttersControl::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 setShadingMinOutsideTemperature { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_Min_OutsideTemperature', + $attrVal ); + + return; +} + +sub getShadingMinOutsideTemperature { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_OutsideTemperature', + 18 ); +} + +sub setShadingMinMaxElevation { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_MinMax_Elevation', + $attrVal ); + + return; +} + +sub getShadingMinElevation { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{minVal} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{LASTGETTIME} = int( gettimeofday() ); + my ( $min, $max ) = + FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getShadingMinElevation; + + return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation} + ->{maxVal}; +} + +sub setShadingStateChangeSunnyCloudy { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_StateChange_SunnyCloudy', + $attrVal ); + + return; +} + +sub getShadingStateChangeSunny { + my $self = shift; + + return $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{sunny} + if ( + exists( + $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} + ->{LASTGETTIME} = int( gettimeofday() ); + my ( $sunny, $cloudy, $maxBrightnessAverageArrayObjects ) = + FHEM::Automation::ShuttersControl::GetAttrValues( $self->{shuttersDev}, + 'ASC_Shading_StateChange_SunnyCloudy', + '35000:20000' ); + + ### erwartetes Ergebnis + # SUNNY:CLOUDY [BrightnessAverage] + + $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} + ->{sunny} = $sunny; + $self->{ $self->{shuttersDev} }->{ASC_Shading_StateChange_SunnyCloudy} + ->{cloudy} = $cloudy; + $self->{ $self->{shuttersDev} }->{BrightnessAverageArray}->{MAXOBJECT} = ( + defined($maxBrightnessAverageArrayObjects) + && $maxBrightnessAverageArrayObjects ne 'none' + ? $maxBrightnessAverageArrayObjects + : 3 + ); + + 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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getShadingStateChangeSunny; + + return $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{cloudy}; +} + +sub getMaxBrightnessAverageArrayObjects { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{BrightnessAverageArray} + ->{MAXOBJECT} + if ( + exists( + $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} } + ->{ASC_Shading_StateChange_SunnyCloudy}->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getShadingStateChangeSunny; + + return $self->{ $self->{shuttersDev} }->{BrightnessAverageArray} + ->{MAXOBJECT}; +} + +sub setShadingWaitingPeriod { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Shading_WaitingPeriod', + $attrVal ); + + return; +} + +sub getShadingWaitingPeriod { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Shading_WaitingPeriod', 1200 ); +} +### Ende Beschattung +sub setExternalTrigger { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_ExternalTrigger', $attrVal ); + + return; +} + +sub getExternalTriggerDevice { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{device} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $device, $reading, $valueActive, $valueInactive, $posActive, + $posInactive, $valueActive2, $posActive2 ) + = FHEM::Automation::ShuttersControl::GetAttrValues( $self->{shuttersDev}, + 'ASC_ExternalTrigger', 'none' ); + + ### erwartetes Ergebnis +# DEVICE:READING VALUEACTIVE:VALUEINACTIVE POSACTIVE:POSINACTIVE VALUEACTIVE2:POSACTIVE2 + + $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 + : $FHEM::Automation::ShuttersControl::shutters->getLastPos ); + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{valueactive2} = + $valueActive2; + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2} = + $posActive2; + + 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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getExternalTriggerDevice; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{valueactive}; +} + +sub getExternalTriggerValueActive2 { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{valueactive2} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getExternalTriggerDevice; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{valueactive2}; +} + +sub getExternalTriggerValueInactive { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{valueinactive} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getExternalTriggerDevice; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive}; +} + +sub getExternalTriggerPosActive2 { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getExternalTriggerDevice; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posactive2}; +} + +sub getExternalTriggerPosInactive { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger}->{posinactive} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_ExternalTrigger} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::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 setDelay { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Drive_Delay', $attrVal ); + + return; +} + +sub getDelay { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_Delay', -1 ); + return ( $val =~ m{^\d+$}xms ? $val : -1 ); +} + +sub setDelayStart { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Drive_DelayStart', $attrVal ); + + return; +} + +sub getDelayStart { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_DelayStart', -1 ); + return ( ( $val > 0 && $val =~ m{^\d+$}xms ) ? $val : -1 ); +} + +sub setBlockingTimeAfterManual { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_BlockingTime_afterManual', + $attrVal ); + + return; +} + +sub getBlockingTimeAfterManual { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_afterManual', + 1200 ); +} + +sub setBlockingTimeBeforNightClose { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_BlockingTime_beforNightClose', + $attrVal ); + + return; +} + +sub getBlockingTimeBeforNightClose { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforNightClose', + 3600 ); +} + +sub setBlockingTimeBeforDayOpen { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_BlockingTime_beforDayOpen', + $attrVal ); + + return; +} + +sub getBlockingTimeBeforDayOpen { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforDayOpen', + 3600 ); +} + +sub setPosCmd { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Pos_Reading', $attrVal ); + + return; +} + +sub getPosCmd { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Pos_Reading', + $FHEM::Automation::ShuttersControl::userAttrList{'ASC_Pos_Reading'} + [ AttrVal( $self->{shuttersDev}, 'ASC', 1 ) ] ); +} + +sub setOpenPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Open_Pos', $attrVal ); + + return; +} + +sub getOpenPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Open_Pos', 'ASC_Open_Pos:0,10,20,30,40,50,60,70,80,90,100' ); +} + +sub getOpenPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Open_Pos', 'getOpenPos' ); +} + +sub setVentilatePos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Ventilate_Pos', $attrVal ); + + return; +} + +sub getVentilatePos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Ventilate_Pos', + 'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100' ); +} + +sub getVentilatePositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Ventilate_Pos', 'getVentilatePos' ); +} + +sub setVentilatePosAfterDayClosed { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WindowRec_PosAfterDayClosed', + $attrVal ); + + return; +} + +sub getVentilatePosAfterDayClosed { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_PosAfterDayClosed', + 'open' ); +} + +sub setClosedPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Closed_Pos', $attrVal ); + + return; +} + +sub getClosedPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Closed_Pos', 'ASC_Closed_Pos:0,10,20,30,40,50,60,70,80,90,100' ); +} + +sub getClosedPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Closed_Pos', 'getClosedPos' ); +} + +sub setSleepPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Sleep_Pos', $attrVal ); + + return; +} + +sub getSleepPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_Sleep_Pos', 'ASC_Sleep_Pos:0,10,20,30,40,50,60,70,80,90,100' ); +} + +sub getSleepPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_Sleep_Pos', 'getSleepPos' ); +} + +sub setVentilateOpen { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', + $attrVal ); + + return; +} + +sub getVentilateOpen { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', 'on' ); +} + +sub setComfortOpenPos { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_ComfortOpen_Pos', $attrVal ); + + return; +} + +sub getComfortOpenPos { + my $self = shift; + + return $FHEM::Automation::ShuttersControl::shutters->_getPosition( + 'ASC_ComfortOpen_Pos', + 'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100' ); +} + +sub getComfortOpenPositionAssignment { + my $self = shift; + + return + $FHEM::Automation::ShuttersControl::shutters->_getPositionAssignment( + 'ASC_ComfortOpen_Pos', 'getComfortOpenPos' ); +} + +sub setPartyMode { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Partymode', $attrVal ); + + return; +} + +sub getPartyMode { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Partymode', 'off' ); +} + +sub setRoommates { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Roommate_Device', $attrVal ); + + return; +} + +sub getRoommates { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Device', 'none' ); +} + +sub setRoommatesReading { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Roommate_Reading', $attrVal ); + + return; +} + +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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $max, $hyst, $pos ) = + FHEM::Automation::ShuttersControl::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 + : $FHEM::Automation::ShuttersControl::shutters->getOpenPos ); + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax}; +} + +sub setWindParameters { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WindParameters', $attrVal ); + + return; +} + +sub getWindMin { + my $self = shift; + + my $name = $self->{name}; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} + ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->getWindMax; + + return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst}; +} + +sub setWindProtection { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WindProtection', $attrVal ); + + return; +} + +sub getWindProtection { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_WindProtection', 'off' ); +} + +sub setRainProtection { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_RainProtection', $attrVal ); + + return; +} + +sub getRainProtection { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_RainProtection', 'off' ); +} + +sub setModeUp { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Mode_Up', $attrVal ); + + return; +} + +sub getModeUp { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Up', 'always' ); +} + +sub setModeDown { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Mode_Down', $attrVal ); + + return; +} + +sub getModeDown { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Down', 'always' ); +} + +sub setLockOut { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_LockOut', $attrVal ); + + return; +} + +sub getLockOut { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_LockOut', 'off' ); +} + +sub setLockOutCmd { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_LockOut_Cmd', $attrVal ); + + return; +} + +sub getLockOutCmd { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_LockOut_Cmd', 'none' ); +} + +sub setAntiFreeze { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Antifreeze', $attrVal ); + + return; +} + +sub getAntiFreeze { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze', 'off' ); +} + +sub setAutoAstroModeMorning { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', $attrVal ); + + return; +} + +sub getAutoAstroModeMorning { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', 'none' ); +} + +sub setAutoAstroModeEvening { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', $attrVal ); + + return; +} + +sub getAutoAstroModeEvening { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', 'none' ); +} + +sub setAutoAstroModeMorningHorizon { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_AutoAstroModeMorningHorizon', + $attrVal ); + + return; +} + +sub getAutoAstroModeMorningHorizon { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorningHorizon', + 0 ); +} + +sub setAutoAstroModeEveningHorizon { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon', + $attrVal ); + + return; +} + +sub getAutoAstroModeEveningHorizon { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon', + 0 ); +} + +sub setUp { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Up', $attrVal ); + + return; +} + +sub getUp { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Up', 'astro' ); +} + +sub setDown { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Down', $attrVal ); + + return; +} + +sub getDown { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_Down', 'astro' ); +} + +sub setTimeUpEarly { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Time_Up_Early', $attrVal ); + + return; +} + +sub getTimeUpEarly { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Early', '05:00' ); + + if ( defined( FHEM::Automation::ShuttersControl::_perlCodeCheck($val) ) ) { + $val = FHEM::Automation::ShuttersControl::_perlCodeCheck($val); + } + + return ( + $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms + ? $val + : '05:00' + ); +} + +sub setTimeUpLate { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Time_Up_Late', $attrVal ); + + return; +} + +sub getTimeUpLate { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Late', '08:30' ); + + if ( defined( FHEM::Automation::ShuttersControl::_perlCodeCheck($val) ) ) { + $val = FHEM::Automation::ShuttersControl::_perlCodeCheck($val); + } + + return ( + $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms + ? $val + : '08:30' + ); +} + +sub setTimeDownEarly { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Time_Down_Early', $attrVal ); + + return; +} + +sub getTimeDownEarly { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Early', '16:00' ); + + if ( defined( FHEM::Automation::ShuttersControl::_perlCodeCheck($val) ) ) { + $val = FHEM::Automation::ShuttersControl::_perlCodeCheck($val); + } + + return ( + $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms + ? $val + : '16:00' + ); +} + +sub setTimeDownLate { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Time_Down_Late', $attrVal ); + + return; +} + +sub getTimeDownLate { + my $self = shift; + + my $val = AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Late', '22:00' ); + + if ( defined( FHEM::Automation::ShuttersControl::_perlCodeCheck($val) ) ) { + $val = FHEM::Automation::ShuttersControl::_perlCodeCheck($val); + } + + return ( + $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms + ? $val + : '22:00' + ); +} + +sub setTimeUpWeHoliday { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', $attrVal ); + + return; +} + +sub getTimeUpWeHoliday { + my $self = shift; + + my $val = + AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', '01:25' ); + + if ( defined( FHEM::Automation::ShuttersControl::_perlCodeCheck($val) ) ) { + $val = FHEM::Automation::ShuttersControl::_perlCodeCheck($val); + } + + return ( + $val =~ m{^(?:[01]?\d|2[0-3]):(?:[0-5]\d)(:(?:[0-5]\d))?$}xms + ? $val + : '01:25' + ); +} + +sub getBrightnessMinVal { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{LASTGETTIME} ) < 2 + ); + $FHEM::Automation::ShuttersControl::shutters->_getBrightnessSensor; + + return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor} + ->{triggermax}; +} + +sub setDriveUpMaxDuration { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_DriveUpMaxDuration', $attrVal ); + + return; +} + +sub getDriveUpMaxDuration { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_DriveUpMaxDuration', 60 ); +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm b/lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm new file mode 100644 index 0000000..03ca247 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Shutters/Readings.pm @@ -0,0 +1,94 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Readings von ASC_Shutters ## +package FHEM::Automation::ShuttersControl::Shutters::Readings; + +use strict; +use warnings; +use utf8; + +use GPUtils qw(GP_Import); + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw( + ReadingsVal + ReadingsNum) + ); +} + +sub getBrightness { + my $self = shift; + + return ReadingsNum( + $FHEM::Automation::ShuttersControl::shutters->_getBrightnessSensor, + $FHEM::Automation::ShuttersControl::shutters->getBrightnessReading, + -1 ); +} + +sub getWindStatus { + my $self = shift; + + return ReadingsVal( + $FHEM::Automation::ShuttersControl::ascDev->_getWindSensor, + $FHEM::Automation::ShuttersControl::ascDev->getWindSensorReading, -1 ); +} + +sub getStatus { + my $self = shift; + + return ReadingsNum( $self->{shuttersDev}, + $FHEM::Automation::ShuttersControl::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' ); +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Window.pm b/lib/FHEM/Automation/ShuttersControl/Window.pm new file mode 100644 index 0000000..de9d350 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Window.pm @@ -0,0 +1,53 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Klasse Fenster (Window) und die Subklassen Attr und Readings ## +package FHEM::Automation::ShuttersControl::Window; + +use strict; +use warnings; +use utf8; + +use FHEM::Automation::ShuttersControl::Window::Attr; +use FHEM::Automation::ShuttersControl::Window::Readings; + +our @ISA = + qw(FHEM::Automation::ShuttersControl::Window::Attr FHEM::Automation::ShuttersControl::Window::Readings); + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Window/Attr.pm b/lib/FHEM/Automation/ShuttersControl/Window/Attr.pm new file mode 100644 index 0000000..739a3c0 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Window/Attr.pm @@ -0,0 +1,128 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Attr von Klasse ASC_Window ## +package FHEM::Automation::ShuttersControl::Window::Attr; + +use strict; +use warnings; +use utf8; + +use GPUtils qw(GP_Import); + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw( + AttrVal + gettimeofday) + ); +} + +sub setSubTyp { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WindowRec_subType', $attrVal ); + + return; +} + +sub getSubTyp { + my $self = shift; + + return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', 'twostate' ); +} + +sub setWinDev { + my $self = shift; + my $attrVal = shift; + + _setAttributs( $self->{shuttersDev}, 'ASC_WindowRec', $attrVal ); + + return; +} + +sub _getWinDev { + my $self = shift; + + return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{device} + if ( + exists( + $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < + 2 + ); + $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} = + int( gettimeofday() ); + my ( $device, $reading ) = + FHEM::Automation::ShuttersControl::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} + ) + && ( gettimeofday() - + $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{LASTGETTIME} ) < + 2 + ); + $FHEM::Automation::ShuttersControl::shutters->_getWinDev; + + return $self->{ $self->{shuttersDev} }->{ASC_WindowRec}->{reading}; +} + +1; diff --git a/lib/FHEM/Automation/ShuttersControl/Window/Readings.pm b/lib/FHEM/Automation/ShuttersControl/Window/Readings.pm new file mode 100644 index 0000000..e8a9025 --- /dev/null +++ b/lib/FHEM/Automation/ShuttersControl/Window/Readings.pm @@ -0,0 +1,66 @@ +############################################################################### +# +# 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$ +# +############################################################################### + +## Subklasse Readings von Klasse ASC_Window ## +package FHEM::Automation::ShuttersControl::Window::Readings; + +use strict; +use warnings; +use utf8; + +use GPUtils qw(GP_Import); + +## Import der FHEM Funktionen +BEGIN { + GP_Import( + qw( + ReadingsVal) + ); +} + +sub getWinStatus { + my $self = shift; + + return ReadingsVal( + $FHEM::Automation::ShuttersControl::shutters->_getWinDev, + $FHEM::Automation::ShuttersControl::shutters->getWinDevReading, + 'closed' ); +} + +1;