###############################################################################
#
# Developed with Kate
#
# (c) 2018-2019 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
# - Feststellen ob ein Rolladen fährt oder nicht
# !!!!! - Innerhalb einer Shutterschleife kein CommandAttr verwenden. Bring Fehler!!! Kommen Raumnamen in die Shutterliste !!!!!!
#
package main;
use strict;
use warnings;
sub ascAPIget($@) {
my ( $getCommand, $shutterDev, $value ) = @_;
return AutoShuttersControl_ascAPIget( $getCommand, $shutterDev, $value );
}
## unserer packagename
package FHEM::AutoShuttersControl;
use strict;
use warnings;
use POSIX;
use utf8;
use 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_abs
sunrise_abs
InternalTimer
RemoveInternalTimer
computeAlignTime
ReplaceEventMap)
);
}
#-- Export to main context with different name
GP_Export(
qw(
Initialize
ascAPIget
)
);
## 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' => '-',
'ASC_Down:time,astro,brightness' => '-',
'ASC_AutoAstroModeMorning:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON' => '-',
'ASC_AutoAstroModeMorningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9'
=> '-',
'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_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_PrivacyDownTime_beforNightClose' => '-',
'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_Direction' => '-',
'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 80, 20 ],
'ASC_Shading_Mode:absent,always,off,home' => '-',
'ASC_Shading_Angle_Left' => '-',
'ASC_Shading_Angle_Right' => '-',
'ASC_Shading_StateChange_Sunny' => '-',
'ASC_Shading_StateChange_Cloudy' => '-',
'ASC_Shading_MinMax_Elevation' => '-',
'ASC_Shading_Min_OutsideTemperature' => '-',
'ASC_Shading_WaitingPeriod' => '-',
'ASC_Drive_Offset' => '-',
'ASC_Drive_OffsetStart' => '-',
'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_Exclude:on,off' => '-',
'ASC_Self_Defense_Mode:absent,gone' => '-',
'ASC_Self_Defense_AbsentDelay' => '-',
'ASC_WiggleValue' => '-',
'ASC_WindParameters' => '-',
'ASC_DriveUpMaxDuration' => '-',
'ASC_WindProtection:on,off' => '-',
'ASC_RainProtection: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',
);
my $shutters = new ASC_Shutters();
my $ascDev = new ASC_Dev();
sub ascAPIget($@) {
my ( $getCommand, $shutterDev, $value ) = @_;
my $getter = 'get' . $getCommand;
if ( defined($value) and $value ) {
$shutters->setShuttersDev($shutterDev);
return $shutters->$getter($value);
}
elsif ( defined($shutterDev) and $shutterDev ) {
$shutters->setShuttersDev($shutterDev);
return $shutters->$getter;
}
else {
return $ascDev->$getter;
}
}
sub Initialize($) {
my ($hash) = @_;
## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname
# und davor mit :: getrennt der eigentliche package Name des Modules
$hash->{SetFn} = 'FHEM::AutoShuttersControl::Set';
$hash->{GetFn} = 'FHEM::AutoShuttersControl::Get';
$hash->{DefFn} = 'FHEM::AutoShuttersControl::Define';
$hash->{NotifyFn} = 'FHEM::AutoShuttersControl::Notify';
$hash->{UndefFn} = 'FHEM::AutoShuttersControl::Undef';
$hash->{AttrFn} = 'FHEM::AutoShuttersControl::Attr';
$hash->{AttrList} =
'ASC_tempSensor '
. 'ASC_brightnessDriveUpDown '
. 'ASC_autoShuttersControlMorning:on,off '
. 'ASC_autoShuttersControlEvening:on,off '
. 'ASC_autoShuttersControlComfort:on,off '
. 'ASC_residentsDev '
. 'ASC_rainSensor '
. 'ASC_autoAstroModeMorning:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON '
. 'ASC_autoAstroModeMorningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9 '
. 'ASC_autoAstroModeEvening:REAL,CIVIL,NAUTIC,ASTRONOMIC,HORIZON '
. 'ASC_autoAstroModeEveningHorizon:-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9 '
. 'ASC_freezeTemp:-5,-4,-3,-2,-1,0,1,2,3,4,5 '
. 'ASC_shuttersDriveOffset '
. 'ASC_twilightDevice '
. 'ASC_windSensor '
. 'ASC_expert:1 '
. 'ASC_blockAscDrivesAfterManual:0,1 '
. 'ASC_debug:1 '
. $readingFnAttributes;
$hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn
return FHEM::Meta::InitMod( __FILE__, $hash );
}
sub Define($$) {
my ( $hash, $def ) = @_;
my @a = split( '[ \t][ \t]*', $def );
return $@ unless ( FHEM::Meta::SetInternals($hash) );
use version 0.60; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
return 'only one AutoShuttersControl instance allowed'
if ( devspec2array('TYPE=AutoShuttersControl') > 1 )
; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen
return 'too few parameters: define
AutoShuttersControl (ASC) provides a complete automation for shutters with comprehensive
configuration options, e.g. open or close shutters depending on the sunrise or sunset,
by outdoor brightness or randomly for simulate presence.
After telling ASC which shutters should be controlled, several in-depth configuration options
are provided. With these and in combination with a resident presence state, complex scenarios are possible:
For example, shutters could be opened if a resident awakes from sleep and the sun is already rosen. Or if a
closed window with shutters down is tilted, the shutters could be half opened for ventilation.
Many more is possible.
';
return $ret;
}
sub GetMonitoredDevs($) {
my $hash = shift;
my $notifydevs = eval {
decode_json( ReadingsVal( $hash->{NAME}, '.monitoredDevs', 'none' ) );
};
my $ret = ' ';
$ret .= '';
$ret .= ' ';
$ret .= '
';
$ret .= " ';
my $linecount = 1;
foreach my $shutter ( @{ $hash->{helper}{shuttersList} } ) {
$shutters->setShuttersDev($shutter);
if ( $linecount % 2 == 0 ) { $ret .= 'Shutters ";
$ret .= " ";
$ret .= "Next DriveUp ";
$ret .= " ";
$ret .= "Next DriveDown ";
$ret .= " ";
$ret .= "ASC Up ";
$ret .= " ";
$ret .= "ASC Down ";
$ret .= " ";
$ret .= "ASC Mode Up ";
$ret .= " ";
$ret .= "ASC Mode Down ";
$ret .= " ";
$ret .= "Partymode ";
$ret .= " ";
$ret .= "Lock-Out ";
$ret .= " ";
$ret .= "Last Drive ";
$ret .= " ";
$ret .= "Position ";
$ret .= " ";
$ret .= "Last Position ";
$ret .= " ";
$ret .= "Shading Info ";
$ret .= ''; }
else { $ret .= ' '; }
$ret .= " ';
$linecount++;
}
$ret .= '$shutter ";
$ret .= " ";
$ret .= ""
. strftime( "%e.%m.%Y - %H:%M:%S",
localtime( $shutters->getSunriseUnixTime ) )
. " ";
$ret .= " ";
$ret .= ""
. strftime( "%e.%m.%Y - %H:%M:%S",
localtime( $shutters->getSunsetUnixTime ) )
. " ";
$ret .= " ";
$ret .= "" . $shutters->getUp . " ";
$ret .= " ";
$ret .= "" . $shutters->getDown . " ";
$ret .= " ";
$ret .= "" . $shutters->getModeUp . " ";
$ret .= " ";
$ret .= "" . $shutters->getModeDown . " ";
$ret .= " ";
$ret .= "" . $shutters->getPartyMode . " ";
$ret .= " ";
$ret .= "" . $shutters->getLockOut . " ";
$ret .= " ";
$ret .= ""
. ReadingsVal( $shutter, 'ASC_ShuttersLastDrive', 'none' ) . " ";
$ret .= " ";
$ret .= "" . $shutters->getStatus . " ";
$ret .= " ";
$ret .= "" . $shutters->getLastPos . " ";
$ret .= " ";
$ret .= ""
. $shutters->getShadingStatus . ' - '
. strftime( "%H:%M:%S",
localtime( $shutters->getShadingStatusTimestamp ) )
. " ";
$ret .= '
';
return $ret;
}
#################################
## my little helper
#################################
sub PositionValueWindowRec($$) {
my ( $shuttersDev, $posValue ) = @_;
if ( CheckIfShuttersWindowRecOpen($shuttersDev) == 1
and $shutters->getVentilateOpen eq 'on' )
{
$posValue = $shutters->getVentilatePos;
}
elsif ( CheckIfShuttersWindowRecOpen($shuttersDev) == 2
and $shutters->getSubTyp eq 'threestate'
and $ascDev->getAutoShuttersControlComfort eq 'on' )
{
$posValue = $shutters->getComfortOpenPos;
}
elsif (
CheckIfShuttersWindowRecOpen($shuttersDev) == 2
and ( $shutters->getSubTyp eq 'threestate'
or $shutters->getSubTyp eq 'twostate' )
and $shutters->getVentilateOpen eq 'on'
)
{
$posValue = $shutters->getVentilatePos;
}
if ( $shutters->getQueryShuttersPos($posValue) ) {
$posValue = $shutters->getStatus;
}
return $posValue;
}
sub AutoSearchTwilightDev($) {
my $hash = shift;
my $name = $hash->{NAME};
if ( devspec2array('TYPE=(Astro|Twilight)') > 0 ) {
CommandAttr( undef,
$name
. ' ASC_twilightDevice '
. ( devspec2array('TYPE=(Astro|Twilight)') )[0] )
if ( AttrVal( $name, 'ASC_twilightDevice', 'none' ) eq 'none' );
}
}
sub GetAttrValues($@) {
my ( $dev, $attribut, $default ) = @_;
my @values = split( ' ',
AttrVal( $dev, $attribut, ( defined($default) ? $default : 'none' ) ) );
my ( $value1, $value2 ) = split( ':', $values[0] );
my ( $value3, $value4 ) = split( ':', $values[1] )
if ( defined( $values[1] ) );
my ( $value5, $value6 ) = split( ':', $values[2] )
if ( defined( $values[2] ) );
my ( $value7, $value8 ) = split( ':', $values[2] )
if ( defined( $values[3] ) );
return (
$value1,
defined($value2) ? $value2 : 'none',
defined($value3) ? $value3 : 'none',
defined($value4) ? $value4 : 'none',
defined($value5) ? $value5 : 'none',
defined($value6) ? $value6 : 'none',
defined($value7) ? $value7 : 'none',
defined($value8) ? $value8 : 'none'
);
}
# Hilfsfunktion welche meinen ReadingString zum finden der getriggerten Devices und der Zurdnung was das Device überhaupt ist und zu welchen Rolladen es gehört aus liest und das Device extraiert
sub ExtractNotifyDevFromEvent($$$) {
my ( $hash, $shuttersDev, $shuttersAttr ) = @_;
my %notifyDevs;
while ( my $notifyDev = each %{ $hash->{monitoredDevs} } ) {
Log3( $hash->{NAME}, 4,
"AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - NotifyDev: "
. $notifyDev );
Log3( $hash->{NAME}, 5,
"AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDev: "
. $shuttersDev );
if ( defined( $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} )
and $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} eq
$shuttersAttr )
{
Log3( $hash->{NAME}, 4,
"AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - ShuttersDevHash: "
. $hash->{monitoredDevs}{$notifyDev}{$shuttersDev} );
Log3( $hash->{NAME}, 5,
"AutoShuttersControl ($hash->{NAME}) - ExtractNotifyDevFromEvent - return ShuttersDev: "
. $notifyDev );
$notifyDevs{$notifyDev} = $shuttersDev;
}
}
return \%notifyDevs;
}
## Ist Tag oder Nacht für den entsprechende Rolladen
sub _IsDay($) {
my ($shuttersDev) = @_;
$shutters->setShuttersDev($shuttersDev);
my $isday = ( ShuttersSunrise( $shuttersDev, 'unix' ) >
ShuttersSunset( $shuttersDev, 'unix' ) ? 1 : 0 );
my $respIsDay = $isday;
ASC_Debug( 'FnIsDay: ' . $shuttersDev . ' Allgemein: ' . $respIsDay );
if (
(
$shutters->getModeDown eq 'brightness'
or $shutters->getModeUp eq 'brightness'
)
or (
(
(
(
int( gettimeofday() / 86400 ) != int(
computeAlignTime( '24:00',
$shutters->getTimeUpEarly ) / 86400
)
and not IsWe()
)
or (
int( gettimeofday() / 86400 ) != int(
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday ) / 86400
)
and IsWe()
and $ascDev->getSunriseTimeWeHoliday eq 'on'
)
)
and int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00', $shutters->getTimeUpLate ) /
86400
)
)
or (
int( gettimeofday() / 86400 ) != int(
computeAlignTime( '24:00', $shutters->getTimeDownEarly ) /
86400
)
and int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00', $shutters->getTimeDownLate ) /
86400
)
)
)
)
{
my $brightnessMinVal;
if ( $shutters->getBrightnessMinVal > -1 ) {
$brightnessMinVal = $shutters->getBrightnessMinVal;
}
else {
$brightnessMinVal = $ascDev->getBrightnessMinVal;
}
my $brightnessMaxVal;
if ( $shutters->getBrightnessMaxVal > -1 ) {
$brightnessMaxVal = $shutters->getBrightnessMaxVal;
}
else {
$brightnessMaxVal = $ascDev->getBrightnessMaxVal;
}
##### Nach Sonnenuntergang / Abends
$respIsDay = (
(
(
$shutters->getBrightness > $brightnessMinVal
and $isday
and not $shutters->getSunset
)
or not $shutters->getSunset
) ? 1 : 0
) if ( $shutters->getDown eq 'brightness' );
ASC_Debug( 'FnIsDay: '
. $shuttersDev
. ' getDownBrightness: '
. $respIsDay
. ' Brightness: '
. $shutters->getBrightness
. ' BrightnessMin: '
. $brightnessMinVal
. ' Sunset: '
. $shutters->getSunset );
##### Nach Sonnenauf / Morgens
$respIsDay = (
(
(
$shutters->getBrightness > $brightnessMaxVal
and not $isday
and not $shutters->getSunrise
)
or $respIsDay
or $shutters->getSunrise
) ? 1 : 0
) if ( $shutters->getUp eq 'brightness' );
ASC_Debug( 'FnIsDay: '
. $shuttersDev
. ' getUpBrightness: '
. $respIsDay
. ' Brightness: '
. $shutters->getBrightness
. ' BrightnessMax: '
. $brightnessMaxVal
. ' Sunrise: '
. $shutters->getSunrise );
}
return $respIsDay;
}
sub ShuttersSunrise($$) {
my ( $shuttersDev, $tm ) =
@_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit
my $autoAstroMode;
$shutters->setShuttersDev($shuttersDev);
if ( $shutters->getAutoAstroModeMorning ne 'none' ) {
$autoAstroMode = $shutters->getAutoAstroModeMorning;
$autoAstroMode =
$autoAstroMode . '=' . $shutters->getAutoAstroModeMorningHorizon
if ( $autoAstroMode eq 'HORIZON' );
}
else {
$autoAstroMode = $ascDev->getAutoAstroModeMorning;
$autoAstroMode =
$autoAstroMode . '=' . $ascDev->getAutoAstroModeMorningHorizon
if ( $autoAstroMode eq 'HORIZON' );
}
my $oldFuncHash = $shutters->getInTimerFuncHash;
my $shuttersSunriseUnixtime;
if ( $tm eq 'unix' ) {
if ( $shutters->getUp eq 'astro' ) {
if ( ( IsWe() or IsWeTomorrow() )
and $ascDev->getSunriseTimeWeHoliday eq 'on' )
{
if ( not IsWeTomorrow() ) {
if (
IsWe()
and int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
) / 86400
)
)
{
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
);
}
elsif (
int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
) / 86400
)
)
{
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
);
}
else {
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
);
}
}
else {
if (
IsWe()
and (
int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
) / 86400
)
or int( gettimeofday() / 86400 ) != int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
) / 86400
)
)
)
{
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
);
}
elsif (
int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
) / 86400
)
)
{
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
);
}
else {
if (
int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
) / 86400
)
)
{
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 86401
);
}
else {
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode, 0,
$shutters->getTimeUpWeHoliday
)
) + 1
);
}
}
}
}
else {
$shuttersSunriseUnixtime = (
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
);
}
if ( defined($oldFuncHash)
and ref($oldFuncHash) eq 'HASH'
and ( IsWe() or IsWeTomorrow() )
and $ascDev->getSunriseTimeWeHoliday eq 'on' )
{
if ( not IsWeTomorrow() ) {
if (
int( gettimeofday() / 86400 ) == int(
(
computeAlignTime(
'24:00',
sunrise_abs(
$autoAstroMode,
0,
$shutters->getTimeUpEarly,
$shutters->getTimeUpLate
)
) + 1
) / 86400
)
)
{
$shuttersSunriseUnixtime =
( $shuttersSunriseUnixtime + 86400 )
if ( $shuttersSunriseUnixtime <
( $oldFuncHash->{sunrisetime} + 180 )
and $oldFuncHash->{sunrisetime} < gettimeofday() );
}
}
}
elsif ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' ) {
$shuttersSunriseUnixtime = ( $shuttersSunriseUnixtime + 86400 )
if ( $shuttersSunriseUnixtime <
( $oldFuncHash->{sunrisetime} + 180 )
and $oldFuncHash->{sunrisetime} < gettimeofday() );
}
}
elsif ( $shutters->getUp eq 'time' ) {
if ( ( IsWe() or IsWeTomorrow() )
and $ascDev->getSunriseTimeWeHoliday eq 'on' )
{
if ( not IsWeTomorrow() ) {
if (
int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday ) / 86400
)
)
{
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday );
}
elsif (
int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00',
$shutters->getTimeUpEarly ) / 86400
)
and $shutters->getSunrise
)
{
$shuttersSunriseUnixtime =
computeAlignTime( '24:00', $shutters->getTimeUpEarly )
+ 86400;
}
else {
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpEarly );
}
}
else {
if (
IsWe()
and int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday ) / 86400
)
)
{
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday );
}
elsif (
int( gettimeofday() / 86400 ) == int(
computeAlignTime( '24:00',
$shutters->getTimeUpEarly ) / 86400
)
)
{
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpEarly );
}
elsif (
int( gettimeofday() / 86400 ) != int(
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday ) / 86400
)
)
{
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday );
}
else {
$shuttersSunriseUnixtime =
computeAlignTime( '24:00',
$shutters->getTimeUpWeHoliday ) + 86400;
}
}
}
else {
$shuttersSunriseUnixtime =
computeAlignTime( '24:00', $shutters->getTimeUpEarly );
}
}
elsif ( $shutters->getUp eq 'brightness' ) {
$shuttersSunriseUnixtime =
computeAlignTime( '24:00', $shutters->getTimeUpLate );
}
return $shuttersSunriseUnixtime;
}
elsif ( $tm eq 'real' ) {
return sunrise_abs( $autoAstroMode, 0, $shutters->getTimeUpEarly,
$shutters->getTimeUpLate )
if ( $shutters->getUp eq 'astro' );
return $shutters->getTimeUpEarly if ( $shutters->getUp eq 'time' );
}
}
sub IsAfterShuttersTimeBlocking($) {
my ($shuttersDev) = @_;
$shutters->setShuttersDev($shuttersDev);
if (
( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) <
$shutters->getBlockingTimeAfterManual
or ( not $shutters->getIsDay
and defined( $shutters->getSunriseUnixTime )
and $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) <
$shutters->getBlockingTimeBeforDayOpen )
or ( $shutters->getIsDay
and defined( $shutters->getSunriseUnixTime )
and $shutters->getSunsetUnixTime - ( int( gettimeofday() ) ) <
$shutters->getBlockingTimeBeforNightClose )
)
{
return 0;
}
else { return 1 }
}
sub IsAfterShuttersManualBlocking($) {
my $shuttersDev = shift;
$shutters->setShuttersDev($shuttersDev);
if ( $ascDev->getblockAscDrivesAfterManual
and $shutters->getStatus != $shutters->getOpenPos
and $shutters->getStatus != $shutters->getClosedPos
and $shutters->getStatus != $shutters->getWindPos
and $shutters->getStatus != $shutters->getShadingPos
and $shutters->getStatus != $shutters->getComfortOpenPos
and $shutters->getStatus != $shutters->getVentilatePos
and $shutters->getStatus != $shutters->getAntiFreezePos
and $shutters->getLastDrive eq 'manual' )
{
return 0;
}
elsif ( ( int( gettimeofday() ) - $shutters->getLastManPosTimestamp ) <
$shutters->getBlockingTimeAfterManual )
{
return 0;
}
else { return 1 }
}
sub ShuttersSunset($$) {
my ( $shuttersDev, $tm ) =
@_; # Tm steht für Timemode und bedeutet Realzeit oder Unixzeit
my $autoAstroMode;
$shutters->setShuttersDev($shuttersDev);
if ( $shutters->getAutoAstroModeEvening ne 'none' ) {
$autoAstroMode = $shutters->getAutoAstroModeEvening;
$autoAstroMode =
$autoAstroMode . '=' . $shutters->getAutoAstroModeEveningHorizon
if ( $autoAstroMode eq 'HORIZON' );
}
else {
$autoAstroMode = $ascDev->getAutoAstroModeEvening;
$autoAstroMode =
$autoAstroMode . '=' . $ascDev->getAutoAstroModeEveningHorizon
if ( $autoAstroMode eq 'HORIZON' );
}
my $oldFuncHash = $shutters->getInTimerFuncHash;
my $shuttersSunsetUnixtime;
if ( $tm eq 'unix' ) {
if ( $shutters->getDown eq 'astro' ) {
$shuttersSunsetUnixtime = (
computeAlignTime(
'24:00',
sunset_abs(
$autoAstroMode,
0,
$shutters->getTimeDownEarly,
$shutters->getTimeDownLate
)
) + 1
);
if ( defined($oldFuncHash) and ref($oldFuncHash) eq 'HASH' ) {
$shuttersSunsetUnixtime += 86400
if ( $shuttersSunsetUnixtime <
( $oldFuncHash->{sunsettime} + 180 )
and $oldFuncHash->{sunsettime} < gettimeofday() );
}
}
elsif ( $shutters->getDown eq 'time' ) {
$shuttersSunsetUnixtime =
computeAlignTime( '24:00', $shutters->getTimeDownEarly );
}
elsif ( $shutters->getDown eq 'brightness' ) {
$shuttersSunsetUnixtime =
computeAlignTime( '24:00', $shutters->getTimeDownLate );
}
return $shuttersSunsetUnixtime;
}
elsif ( $tm eq 'real' ) {
return sunset_abs(
$autoAstroMode, 0,
$shutters->getTimeDownEarly,
$shutters->getTimeDownLate
) if ( $shutters->getDown eq 'astro' );
return $shutters->getTimeDownEarly
if ( $shutters->getDown eq 'time' );
}
}
## Kontrolliert ob das Fenster von einem bestimmten Rolladen offen ist
sub CheckIfShuttersWindowRecOpen($) {
my $shuttersDev = shift;
$shutters->setShuttersDev($shuttersDev);
if ( $shutters->getWinStatus =~ /[Oo]pen/ ) # CK: covers: open|opened
{
return 2;
}
elsif ( $shutters->getWinStatus =~ /tilt/
and $shutters->getSubTyp eq 'threestate' ) # CK: covers: tilt|tilted
{
return 1;
}
elsif ( $shutters->getWinStatus =~ /[Cc]lose/ ) {
return 0;
} # CK: covers: close|closed
}
sub makeReadingName($) {
my ($rname) = @_;
my %charHash = (
chr(0xe4) => "ae", # ä
chr(0xc4) => "Ae", # Ä
chr(0xfc) => "ue", # ü
chr(0xdc) => "Ue", # Ü
chr(0xf6) => "oe", # ö
chr(0xd6) => "Oe", # Ö
chr(0xdf) => "ss" # ß
);
my $charHashkeys = join( "", keys(%charHash) );
return $rname if ( $rname =~ m/^\./ );
$rname =~ s/([$charHashkeys])/$charHash{$1}/gi;
$rname =~ s/[^a-z0-9._\-\/]/_/gi;
return $rname;
}
sub TimeMin2Sec($) {
my $min = shift;
my $sec;
$sec = $min * 60;
return $sec;
}
sub IsWe() {
my $we = main::IsWe();
return $we;
}
sub IsWeTomorrow() {
my $we = main::IsWe('tomorrow');
return $we;
}
sub _SetCmdFn($) {
my $h = shift;
my $shuttersDev = $h->{shuttersDev};
my $posValue = $h->{posValue};
$shutters->setShuttersDev($shuttersDev);
$shutters->setLastDrive( $h->{lastDrive} )
if ( defined( $h->{lastDrive} ) );
return
unless ( $shutters->getASCenable eq 'on'
and $ascDev->getASCenable eq 'on' );
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
. ' - Rolllo wird gefahren, aktuelle Position: '
. $shutters->getStatus
. ', Zielposition: '
. $posValue
. '. Grund der Fahrt: '
. $shutters->getLastDrive );
CommandSet( undef,
$shuttersDev
. ':FILTER='
. $shutters->getPosCmd . '!='
. $posValue . ' '
. $shutters->getPosSetCmd . ' '
. $posValue );
$shutters->setSelfDefenseAbsent( 0, 0 )
if ( not $shutters->getSelfDefenseAbsent
and $shutters->getSelfDefenseAbsentTimerrun );
}
sub _setShuttersLastDriveDelayed($) {
my $h = shift;
my $shuttersDevHash = $h->{devHash};
my $lastDrive = $h->{lastDrive};
readingsSingleUpdate( $shuttersDevHash, 'ASC_ShuttersLastDrive',
$lastDrive, 1 );
}
sub ASC_Debug($) {
return
unless ( AttrVal( $ascDev->getName, 'ASC_debug', 0 ) );
my $debugMsg = shift;
my $debugTimestamp = strftime( "%Y.%m.%e %T", localtime(time) );
print(
"\n" . 'ASC_DEBUG!!! ' . $debugTimestamp . ' - ' . $debugMsg . "\n" );
}
######################################
######################################
########## Begin der Klassendeklarierungen für OOP (Objektorientierte Programmierung) #########################
## Klasse Rolläden (Shutters) und die Subklassen Attr und Readings ##
## desweiteren wird noch die Klasse ASC_Roommate mit eingebunden
package ASC_Shutters;
our @ISA =
qw(ASC_Shutters::Readings ASC_Shutters::Attr ASC_Roommate ASC_Window);
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
defs
ReadingsVal
readingsSingleUpdate
gettimeofday
InternalTimer
CommandSet
Log3)
);
}
sub new {
my $class = shift;
my $self = {
shuttersDev => undef,
defaultarg => undef,
roommate => undef,
};
bless $self, $class;
return $self;
}
sub setShuttersDev {
my ( $self, $shuttersDev ) = @_;
$self->{shuttersDev} = $shuttersDev if ( defined($shuttersDev) );
return $self->{shuttersDev};
}
sub getShuttersDev {
my $self = shift;
return $self->{shuttersDev};
}
sub setHardLockOut {
my ( $self, $cmd ) = @_;
if ( $shutters->getLockOut eq 'hard'
and $shutters->getLockOutCmd ne 'none' )
{
CommandSet( undef, $self->{shuttersDev} . ' inhibit ' . $cmd )
if ( $shutters->getLockOutCmd eq 'inhibit' );
CommandSet( undef,
$self->{shuttersDev} . ' '
. ( $cmd eq 'on' ? 'blocked' : 'unblocked' ) )
if ( $shutters->getLockOutCmd eq 'blocked' );
CommandSet( undef,
$self->{shuttersDev} . ' '
. ( $cmd eq 'on' ? 'protectionOn' : 'protectionOff' ) )
if ( $shutters->getLockOutCmd eq 'protected' );
}
return 0;
}
sub setNoOffset {
my ( $self, $noOffset ) = @_;
$self->{ $self->{shuttersDev} }{noOffset} = $noOffset;
return 0;
}
sub setSelfDefenseAbsent {
my ( $self, $timerrun, $active, $timerhash ) = @_;
$self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun} = $timerrun;
$self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active} = $active;
$self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash} = $timerhash
if ( defined($timerhash) );
return 0;
}
sub setDriveCmd {
my ( $self, $posValue ) = @_;
my $offSet;
my $offSetStart;
### 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->getOffset if ( $shutters->getOffset > -1 );
$offSet = $ascDev->getShuttersOffset if ( $shutters->getOffset < 0 );
$offSetStart = $shutters->getOffsetStart;
if ( $shutters->getSelfDefenseAbsent
and not $shutters->getSelfDefenseAbsentTimerrun
and $shutters->getSelfDefenseExclude eq 'off'
and $shutters->getLastDrive eq 'selfDefense active'
and $ascDev->getSelfDefense eq 'on' )
{
InternalTimer( gettimeofday() + $shutters->getSelfDefenseAbsentDelay,
'FHEM::AutoShuttersControl::_SetCmdFn', \%h );
$shutters->setSelfDefenseAbsent( 1, 0, \%h );
}
elsif ( $offSetStart > 0 and not $shutters->getNoOffset ) {
InternalTimer(
gettimeofday() + int( rand($offSet) + $shutters->getOffsetStart ),
'FHEM::AutoShuttersControl::_SetCmdFn', \%h );
FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: '
. $shutters->getShuttersDev
. ' - versetztes fahren' );
}
elsif ( $offSetStart < 1 or $shutters->getNoOffset ) {
FHEM::AutoShuttersControl::_SetCmdFn( \%h );
FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: '
. $shutters->getShuttersDev
. ' - NICHT versetztes fahren' );
}
FHEM::AutoShuttersControl::ASC_Debug( 'FnSetDriveCmd: '
. $shutters->getShuttersDev
. ' - NoOffset: '
. ( $shutters->getNoOffset ? 'JA' : 'NEIN' ) );
$shutters->setNoOffset(0);
return 0;
}
sub setSunsetUnixTime {
my ( $self, $unixtime ) = @_;
$self->{ $self->{shuttersDev} }{sunsettime} = $unixtime;
return 0;
}
sub setSunset {
my ( $self, $value ) = @_;
$self->{ $self->{shuttersDev} }{sunset} = $value;
return 0;
}
sub setSunriseUnixTime {
my ( $self, $unixtime ) = @_;
$self->{ $self->{shuttersDev} }{sunrisetime} = $unixtime;
return 0;
}
sub setSunrise {
my ( $self, $value ) = @_;
$self->{ $self->{shuttersDev} }{sunrise} = $value;
return 0;
}
sub setDelayCmd {
my ( $self, $posValue ) = @_;
$self->{ $self->{shuttersDev} }{delayCmd} = $posValue;
return 0;
}
sub setLastDrive {
my ( $self, $lastDrive ) = @_;
$self->{ $self->{shuttersDev} }{lastDrive} = $lastDrive;
return 0;
}
sub setPosSetCmd {
my ( $self, $posSetCmd ) = @_;
$self->{ $self->{shuttersDev} }{posSetCmd} = $posSetCmd;
return 0;
}
sub setLastDriveReading {
my $self = shift;
my $shuttersDevHash = $defs{ $self->{shuttersDev} };
my %h = (
devHash => $shuttersDevHash,
lastDrive => $shutters->getLastDrive,
);
InternalTimer( gettimeofday() + 0.1,
'FHEM::AutoShuttersControl::_setShuttersLastDriveDelayed', \%h );
return 0;
}
sub setLastPos
{ # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde
my ( $self, $position ) = @_;
$self->{ $self->{shuttersDev} }{lastPos}{VAL} = $position
if ( defined($position) );
$self->{ $self->{shuttersDev} }{lastPos}{TIME} = int( gettimeofday() )
if ( defined( $self->{ $self->{shuttersDev} }{lastPos} ) );
return 0;
}
sub setLastManPos {
my ( $self, $position ) = @_;
$self->{ $self->{shuttersDev} }{lastManPos}{VAL} = $position
if ( defined($position) );
$self->{ $self->{shuttersDev} }{lastManPos}{TIME} = int( gettimeofday() )
if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} )
and defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) );
$self->{ $self->{shuttersDev} }{lastManPos}{TIME} =
int( gettimeofday() ) - 86400
if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} )
and not defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) );
return 0;
}
sub setDefault {
my ( $self, $defaultarg ) = @_;
$self->{defaultarg} = $defaultarg if ( defined($defaultarg) );
return $self->{defaultarg};
}
sub setRoommate {
my ( $self, $roommate ) = @_;
$self->{roommate} = $roommate if ( defined($roommate) );
return $self->{roommate};
}
sub setInTimerFuncHash {
my ( $self, $inTimerFuncHash ) = @_;
$self->{ $self->{shuttersDev} }{inTimerFuncHash} = $inTimerFuncHash
if ( defined($inTimerFuncHash) );
return 0;
}
sub setPrivacyDownStatus {
my ( $self, $statusValue ) = @_;
$self->{ $self->{shuttersDev} }->{privacyDownStatus} = $statusValue;
return 0;
}
sub getPrivacyDownStatus {
my $self = shift;
return (
defined( $self->{ $self->{shuttersDev} }->{privacyDownStatus} )
? $self->{ $self->{shuttersDev} }->{privacyDownStatus}
: undef
);
}
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() );
my $outTemp = $ascDev->getOutTemp;
$outTemp = $shutters->getOutTemp if ( $shutters->getOutTemp != -100 );
if ( $shutters->getAntiFreeze ne 'off'
and $outTemp <= $ascDev->getFreezeTemp )
{
if ( $shutters->getAntiFreeze eq 'soft' ) {
return 1;
}
elsif ( $shutters->getAntiFreeze eq $daytime ) {
return 2;
}
elsif ( $shutters->getAntiFreeze eq 'hard' ) {
return 3;
}
}
else { return 0; }
}
sub getShuttersPosCmdValueNegate {
my $self = shift;
return ( $shutters->getOpenPos < $shutters->getClosedPos ? 1 : 0 );
}
sub getQueryShuttersPos
{ # Es wird geschaut ob die aktuelle Position des Rollos unterhalb der Zielposition ist
my ( $self, $posValue ) =
@_; # wenn dem so ist wird 1 zurück gegeben ansonsten 0
return (
$shutters->getShuttersPosCmdValueNegate
? $shutters->getStatus > $posValue
: $shutters->getStatus < $posValue
);
}
sub getPosSetCmd {
my $self = shift;
return (
defined( $self->{ $self->{shuttersDev} }{posSetCmd} )
? $self->{ $self->{shuttersDev} }{posSetCmd}
: $shutters->getPosCmd
);
}
sub getNoOffset {
my $self = shift;
return $self->{ $self->{shuttersDev} }{noOffset};
}
sub getSelfDefenseAbsent {
my $self = shift;
return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{active};
}
sub getSelfDefenseAbsentTimerrun {
my $self = shift;
return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerrun};
}
sub getSelfDefenseAbsentTimerhash {
my $self = shift;
return $self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash}
if (
defined(
$self->{ $self->{shuttersDev} }{selfDefenseAbsent}{timerhash}
)
);
}
sub getLastDrive {
my $self = shift;
$self->{ $self->{shuttersDev} }{lastDrive} =
ReadingsVal( $self->{shuttersDev}, 'ASC_ShuttersLastDrive', 'none' )
if ( not defined( $self->{ $self->{shuttersDev} }{lastDrive} ) );
return $self->{ $self->{shuttersDev} }{lastDrive};
}
sub getLastPos
{ # letzte ermittelte Position bevor die Position des Rolladen über ASC geändert wurde
my $self = shift;
return $self->{ $self->{shuttersDev} }{lastPos}{VAL}
if ( defined( $self->{ $self->{shuttersDev} }{lastPos} )
and defined( $self->{ $self->{shuttersDev} }{lastPos}{VAL} ) );
}
sub getLastPosTimestamp {
my $self = shift;
return $self->{ $self->{shuttersDev} }{lastPos}{TIME}
if ( defined( $self->{ $self->{shuttersDev} } )
and defined( $self->{ $self->{shuttersDev} }{lastPos} )
and defined( $self->{ $self->{shuttersDev} }{lastPos}{TIME} ) );
}
sub getLastManPos
{ # letzte ermittelte Position bevor die Position des Rolladen manuell (nicht über ASC) geändert wurde
my $self = shift;
return $self->{ $self->{shuttersDev} }{lastManPos}{VAL}
if ( defined( $self->{ $self->{shuttersDev} }{lastManPos} )
and defined( $self->{ $self->{shuttersDev} }{lastManPos}{VAL} ) );
}
sub getLastManPosTimestamp {
my $self = shift;
return $self->{ $self->{shuttersDev} }{lastManPos}{TIME}
if ( defined( $self->{ $self->{shuttersDev} } )
and defined( $self->{ $self->{shuttersDev} }{lastManPos} )
and defined( $self->{ $self->{shuttersDev} }{lastManPos}{TIME} ) );
}
sub getInTimerFuncHash {
my $self = shift;
return $self->{ $self->{shuttersDev} }{inTimerFuncHash};
}
sub getSunsetUnixTime {
my $self = shift;
return $self->{ $self->{shuttersDev} }{sunsettime};
}
sub getSunset {
my $self = shift;
return (
defined( $self->{ $self->{shuttersDev} }{sunset} )
? $self->{ $self->{shuttersDev} }{sunset}
: 0
);
}
sub getSunriseUnixTime {
my $self = shift;
return $self->{ $self->{shuttersDev} }{sunrisetime};
}
sub getSunrise {
my $self = shift;
return (
defined( $self->{ $self->{shuttersDev} }{sunrise} )
? $self->{ $self->{shuttersDev} }{sunrise}
: 0
);
}
sub getRoommatesStatus {
my $self = shift;
my $loop = 0;
my @roState;
my %statePrio = (
'asleep' => 1,
'gotosleep' => 2,
'awoken' => 3,
'home' => 4,
'absent' => 5,
'gone' => 6,
'none' => 7
);
my $minPrio = 10;
foreach my $ro ( split( ",", $shutters->getRoommates ) ) {
$shutters->setRoommate($ro);
my $currentPrio = $statePrio{ $shutters->_getRoommateStatus };
$minPrio = $currentPrio if ( $minPrio > $currentPrio );
}
my %revStatePrio = reverse %statePrio;
return $revStatePrio{$minPrio};
}
sub getRoommatesLastStatus {
my $self = shift;
my $loop = 0;
my @roState;
my %statePrio = (
'asleep' => 1,
'gotosleep' => 2,
'awoken' => 3,
'home' => 6,
'absent' => 5,
'gone' => 4,
'none' => 7
);
my $minPrio = 10;
foreach my $ro ( split( ",", $shutters->getRoommates ) ) {
$shutters->setRoommate($ro);
my $currentPrio = $statePrio{ $shutters->_getRoommateLastStatus };
$minPrio = $currentPrio if ( $minPrio > $currentPrio );
}
my %revStatePrio = reverse %statePrio;
return $revStatePrio{$minPrio};
}
sub getOutTemp {
my $self = shift;
return ReadingsVal( $shutters->_getTempSensor,
$shutters->getTempSensorReading, -100 );
}
### Begin Beschattung Objekt mit Daten befüllen
sub setShadingStatus {
my ( $self, $value ) = @_;
### Werte für value = in, out, in reserved, out reserved
$self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} = $value
if ( defined($value) );
$self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} = int( gettimeofday() )
if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} ) );
return 0;
}
sub setShadingLastStatus {
my ( $self, $value ) = @_;
### Werte für value = in, out
$self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} = $value
if ( defined($value) );
$self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} =
int( gettimeofday() )
if ( defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} ) );
$self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = 0
if ( $value eq 'out' );
return 0;
}
sub setShadingManualDriveStatus {
my ( $self, $value ) = @_;
### Werte für value = in, out
$self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL} = $value
if ( defined($value) );
return 0;
}
sub setWindProtectionStatus { # Werte protected, unprotected
my ( $self, $value ) = @_;
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL} = $value
if ( defined($value) );
return 0;
}
sub setRainProtectionStatus { # Werte protected, unprotected
my ( $self, $value ) = @_;
$self->{ $self->{shuttersDev} }->{RainProtection}->{VAL} = $value
if ( defined($value) );
return 0;
}
sub getShadingStatus { # Werte für value = in, out, in reserved, out reserved
my $self = shift;
return $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL}
if ( defined( $self->{ $self->{shuttersDev} }{ShadingStatus} )
and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{VAL} ) );
}
sub getShadingLastStatus { # Werte für value = in, out
my $self = shift;
return $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL}
if ( defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} )
and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{VAL} )
);
}
sub getShadingManualDriveStatus { # Werte für value = in, out
my $self = shift;
return (
defined( $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus} )
and defined(
$self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL}
)
? $self->{ $self->{shuttersDev} }{ShadingManualDriveStatus}{VAL}
: 0
);
}
sub getIfInShading {
my $self = shift;
return (
(
$shutters->getShadingMode ne 'off'
and $shutters->getShadingLastStatus eq 'out'
) ? 1 : 0
);
}
sub getWindProtectionStatus { # Werte protected, unprotected
my $self = shift;
return (
(
defined( $self->{ $self->{shuttersDev} }->{ASC_WindParameters} )
and defined(
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL}
)
)
? $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{VAL}
: 'unprotected'
);
}
sub getRainProtectionStatus { # Werte protected, unprotected
my $self = shift;
return (
(
defined( $self->{ $self->{shuttersDev} }->{RainProtection} )
and defined(
$self->{ $self->{shuttersDev} }->{RainProtection}->{VAL}
)
)
? $self->{ $self->{shuttersDev} }->{RainProtection}->{VAL}
: 'unprotected'
);
}
sub getShadingStatusTimestamp {
my $self = shift;
return $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME}
if ( defined( $self->{ $self->{shuttersDev} } )
and defined( $self->{ $self->{shuttersDev} }{ShadingStatus} )
and defined( $self->{ $self->{shuttersDev} }{ShadingStatus}{TIME} ) );
}
sub getShadingLastStatusTimestamp {
my $self = shift;
return $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME}
if ( defined( $self->{ $self->{shuttersDev} } )
and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus} )
and defined( $self->{ $self->{shuttersDev} }{ShadingLastStatus}{TIME} )
);
}
### Ende Beschattung
## Subklasse Attr von ASC_Shutters##
package ASC_Shutters::Attr;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
AttrVal
gettimeofday)
);
}
sub getAntiFreezePos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze_Pos',
$userAttrList{ASC_Antifreeze_Pos}
[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] );
}
sub getShuttersPlace {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_ShuttersPlace', 'window' );
}
sub getPrivacyDownTime {
my $self = shift;
return AttrVal( $self->{shuttersDev},
'ASC_PrivacyDownTime_beforNightClose', -1 );
}
sub getPrivacyDownPos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_PrivacyDown_Pos', 50 );
}
sub getSelfDefenseExclude {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Self_Defense_Exclude', 'off' );
}
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 );
}
### Begin Beschattung
sub getShadingPos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Pos',
$userAttrList{'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100'}
[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] );
}
sub getShadingMode {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Mode', 'off' );
}
sub _getTempSensor {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} )
< 2
);
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} =
int( gettimeofday() );
my ( $device, $reading ) =
FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev},
'ASC_TempSensor', 'none' );
### erwartetes Ergebnis
# DEVICE:READING
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device} = $device;
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} =
( $reading ne 'none' ? $reading : 'temperature' );
return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{device};
}
sub getTempSensorReading {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{LASTGETTIME} )
< 2
);
$shutters->_getTempSensor;
return (
defined( $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading} )
? $self->{ $self->{shuttersDev} }->{ASC_TempSensor}->{reading}
: 'temperature'
);
}
sub _getBrightnessSensor {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME} ) < 2
);
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{LASTGETTIME} =
int( gettimeofday() );
my ( $device, $reading, $max, $min ) =
FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev},
'ASC_BrightnessSensor', 'none' );
### erwartetes Ergebnis
# DEVICE:READING MAX:MIN
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device} = $device;
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} =
( $reading ne 'none' ? $reading : 'brightness' );
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} =
( $min ne 'none' ? $min : -1 );
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermax} =
( $max ne 'none' ? $max : -1 );
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device};
}
sub getBrightnessReading {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME} ) < 2
);
$shutters->_getBrightnessSensor;
return (
defined(
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading}
)
? $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading}
: 'brightness'
);
}
sub getDirection {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Direction', 180 );
}
sub getShadingAngleLeft {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Left', 75 );
}
sub getShadingAngleRight {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Angle_Right', 75 );
}
sub getShadingMinOutsideTemperature {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_OutsideTemperature',
18 );
}
sub getShadingMinElevation {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{minVal}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{LASTGETTIME} ) < 2
);
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{LASTGETTIME} = int( gettimeofday() );
my ( $min, $max ) =
FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev},
'ASC_Shading_MinMax_Elevation', '25.0:100.0' );
### erwartetes Ergebnis
# MIN:MAX
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}->{minVal} =
$min;
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}->{maxVal} =
( $max ne 'none' ? $max : 100 );
return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{minVal};
}
sub getShadingMaxElevation {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{maxVal}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{LASTGETTIME} ) < 2
);
$shutters->getShadingMinElevation;
return $self->{ $self->{shuttersDev} }->{ASC_Shading_MinMax_Elevation}
->{maxVal};
}
sub getShadingStateChangeSunny {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_StateChange_Sunny',
35000 );
}
sub getShadingStateChangeCloudy {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_StateChange_Cloudy',
20000 );
}
sub getShadingWaitingPeriod {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Shading_WaitingPeriod', 1200 );
}
### Ende Beschattung
sub getOffset {
my $self = shift;
my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_Offset', -1 );
return ( $val =~ /^\d+$/ ? $val : -1 );
}
sub getOffsetStart {
my $self = shift;
my $val = AttrVal( $self->{shuttersDev}, 'ASC_Drive_OffsetStart', -1 );
return ( ( $val > 0 and $val =~ /^\d+$/ ) ? $val : -1 );
}
sub getBlockingTimeAfterManual {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_afterManual',
1200 );
}
sub getBlockingTimeBeforNightClose {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforNightClose',
3600 );
}
sub getBlockingTimeBeforDayOpen {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_BlockingTime_beforDayOpen',
3600 );
}
sub getPosCmd {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Pos_Reading', 'pct' );
}
sub getOpenPos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Open_Pos',
$userAttrList{'ASC_Open_Pos:0,10,20,30,40,50,60,70,80,90,100'}
[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] );
}
sub getVentilatePos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Pos',
$userAttrList{'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100'}
[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] );
}
sub 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 getVentilateOpen {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Ventilate_Window_Open', 'on' );
}
sub getComfortOpenPos {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_ComfortOpen_Pos',
$userAttrList{'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100'}
[ AttrVal( $self->{shuttersDev}, 'ASC', 2 ) ] );
}
sub getPartyMode {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Partymode', 'off' );
}
sub getRoommates {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Device', 'none' );
}
sub getRoommatesReading {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Roommate_Reading', 'state' );
}
sub getWindPos {
my $self = shift;
my $name = $self->{name};
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
) < 2
);
$shutters->getWindMax;
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos};
}
sub getWindMax {
my $self = shift;
my $name = $self->{name};
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
) < 2
);
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME} =
int( gettimeofday() );
my ( $max, $hyst, $pos ) =
FHEM::AutoShuttersControl::GetAttrValues( $self->{shuttersDev},
'ASC_WindParameters', '50:20' );
## Erwartetes Ergebnis
# max:hyst pos
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax} = $max;
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst} =
( $hyst ne 'none' ? $max - $hyst : $max - 20 );
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{closedPos} =
( $pos ne 'none' ? $pos : $shutters->getOpenPos );
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggermax};
}
sub getWindMin {
my $self = shift;
my $name = $self->{name};
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{LASTGETTIME}
) < 2
);
$shutters->getWindMax;
return $self->{ $self->{shuttersDev} }->{ASC_WindParameters}->{triggerhyst};
}
sub getWindProtection {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_WindProtection', 'on' );
}
sub getRainProtection {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_RainProtection', 'on' );
}
sub getModeUp {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Up', 'always' );
}
sub getModeDown {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Mode_Down', 'always' );
}
sub getLockOut {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_LockOut', 'off' );
}
sub getLockOutCmd {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_LockOut_Cmd', 'none' );
}
sub getAntiFreeze {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Antifreeze', 'off' );
}
sub getAutoAstroModeMorning {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorning', 'none' );
}
sub getAutoAstroModeEvening {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEvening', 'none' );
}
sub getAutoAstroModeMorningHorizon {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeMorningHorizon',
'none' );
}
sub getAutoAstroModeEveningHorizon {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_AutoAstroModeEveningHorizon',
'none' );
}
sub getUp {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Up', 'astro' );
}
sub getDown {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Down', 'astro' );
}
sub getTimeUpEarly {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Early', '05:00' );
}
sub getTimeUpLate {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_Late', '08:30' );
}
sub getTimeDownEarly {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Early', '16:00' );
}
sub getTimeDownLate {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Time_Down_Late', '22:00' );
}
sub getTimeUpWeHoliday {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_Time_Up_WE_Holiday', '08:00' );
}
sub getBrightnessMinVal {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME} ) < 2
);
$shutters->_getBrightnessSensor;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{triggermin};
}
sub getBrightnessMaxVal {
my $self = shift;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermax}
if (
exists(
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME}
)
and ( gettimeofday() -
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{LASTGETTIME} ) < 2
);
$shutters->_getBrightnessSensor;
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}
->{triggermax};
}
sub getDriveUpMaxDuration {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_DriveUpMaxDuration', 60 );
}
## Subklasse Readings von ASC_Shutters ##
package ASC_Shutters::Readings;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
ReadingsVal
ReadingsNum)
);
}
sub getBrightness {
my $self = shift;
return ReadingsNum( $shutters->_getBrightnessSensor,
$shutters->getBrightnessReading, -1 );
}
sub getWindStatus {
my $self = shift;
return ReadingsVal( $ascDev->_getWindSensor,
$ascDev->getWindSensorReading, -1 );
}
sub getStatus {
my $self = shift;
return ReadingsNum( $self->{shuttersDev}, $shutters->getPosCmd, 0 );
}
sub getDelayCmd {
my $self = shift;
return $self->{ $self->{shuttersDev} }{delayCmd};
}
sub getASCenable {
my $self = shift;
return ReadingsVal( $self->{shuttersDev}, 'ASC_Enable', 'on' );
}
## Klasse Fenster (Window) und die Subklassen Attr und Readings ##
package ASC_Window;
our @ISA = qw(ASC_Window::Attr ASC_Window::Readings);
## Subklasse Attr von Klasse ASC_Window ##
package ASC_Window::Attr;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
AttrVal)
);
}
sub getSubTyp {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec_subType', 'twostate' );
}
sub _getWinDev {
my $self = shift;
return AttrVal( $self->{shuttersDev}, 'ASC_WindowRec', 'none' );
}
## Subklasse Readings von Klasse ASC_Window ##
package ASC_Window::Readings;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
ReadingsVal)
);
}
sub getWinStatus {
my $self = shift;
return ReadingsVal( $shutters->_getWinDev, 'state', 'closed' );
}
## Klasse ASC_Roommate ##
package ASC_Roommate;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
ReadingsVal)
);
}
sub _getRoommateStatus {
my $self = shift;
my $roommate = $self->{roommate};
return ReadingsVal( $roommate, $shutters->getRoommatesReading, 'none' );
}
sub _getRoommateLastStatus {
my $self = shift;
my $roommate = $self->{roommate};
my $default = $self->{defaultarg};
$default = 'none' if ( not defined($default) );
return ReadingsVal( $roommate, 'lastState', $default );
}
## Klasse ASC_Dev plus Subklassen ASC_Attr_Dev und ASC_Readings_Dev##
package ASC_Dev;
our @ISA = qw(ASC_Dev::Readings ASC_Dev::Attr);
use strict;
use warnings;
sub new {
my $class = shift;
my $self = { name => undef, };
bless $self, $class;
return $self;
}
sub setName {
my ( $self, $name ) = @_;
$self->{name} = $name if ( defined($name) );
return $self->{name};
}
sub setDefault {
my ( $self, $defaultarg ) = @_;
$self->{defaultarg} = $defaultarg if ( defined($defaultarg) );
return $self->{defaultarg};
}
sub getName {
my $self = shift;
return $self->{name};
}
## Subklasse Readings ##
package ASC_Dev::Readings;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
readingsSingleUpdate
ReadingsVal
defs)
);
}
sub setDelayCmdReading {
my $self = shift;
my $name = $self->{name};
my $hash = $defs{$name};
readingsSingleUpdate( $hash,
$shutters->getShuttersDev . '_lastDelayPosValue',
$shutters->getDelayCmd, 1 );
return 0;
}
sub setStateReading {
my $self = shift;
my $value = shift;
my $name = $self->{name};
my $hash = $defs{$name};
readingsSingleUpdate( $hash, 'state',
( defined($value) ? $value : $shutters->getLastDrive ), 1 );
return 0;
}
sub setPosReading {
my $self = shift;
my $name = $self->{name};
my $hash = $defs{$name};
readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_PosValue',
$shutters->getStatus, 1 );
return 0;
}
sub setLastPosReading {
my $self = shift;
my $name = $self->{name};
my $hash = $defs{$name};
readingsSingleUpdate( $hash, $shutters->getShuttersDev . '_lastPosValue',
$shutters->getLastPos, 1 );
return 0;
}
sub getPartyMode {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'partyMode', 'off' );
}
sub getHardLockOut {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'hardLockOut', 'none' );
}
sub getSunriseTimeWeHoliday {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'sunriseTimeWeHoliday', 'none' );
}
sub getMonitoredDevs {
my $self = shift;
my $name = $self->{name};
$self->{monitoredDevs} = ReadingsVal( $name, '.monitoredDevs', 'none' );
return $self->{monitoredDevs};
}
sub getOutTemp {
my $self = shift;
return ReadingsVal( $ascDev->_getTempSensor, $ascDev->getTempSensorReading,
-100 );
}
sub getResidentsStatus {
my $self = shift;
my $val =
ReadingsVal( $ascDev->_getResidentsDev, $ascDev->getResidentsReading,
'none' );
if ( $val =~ m/^(?:(.+)_)?(.+)$/ ) {
return ( $1, $2 ) if (wantarray);
return $1 && $1 eq 'pet' ? 'absent' : $2;
}
elsif (
ReadingsVal( $ascDev->_getResidentsDev, 'homealoneType', '-' ) eq
'PET' )
{
return ( 'pet', 'absent' ) if (wantarray);
return 'absent';
}
else {
return ( undef, $val ) if (wantarray);
return $val;
}
}
sub getResidentsLastStatus {
my $self = shift;
my $val = ReadingsVal( $ascDev->_getResidentsDev, 'lastState', 'none' );
if ( $val =~ m/^(?:(.+)_)?(.+)$/ ) {
return ( $1, $2 ) if (wantarray);
return $1 && $1 eq 'pet' ? 'absent' : $2;
}
elsif (
ReadingsVal( $ascDev->_getResidentsDev, 'lastHomealoneType', '-' ) eq
'PET' )
{
return ( 'pet', 'absent' ) if (wantarray);
return 'absent';
}
else {
return ( undef, $val ) if (wantarray);
return $val;
}
}
sub getAutoShuttersControlShading {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'controlShading', 'none' );
}
sub getSelfDefense {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'selfDefense', 'none' );
}
sub getAzimuth {
my $self = shift;
my $azimuth;
$azimuth = ReadingsVal( $ascDev->_getTwilightDevice, 'azimuth', -1 )
if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Twilight' );
$azimuth = ReadingsVal( $ascDev->_getTwilightDevice, 'SunAz', -1 )
if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Astro' );
return $azimuth;
}
sub getElevation {
my $self = shift;
my $elevation;
$elevation = ReadingsVal( $ascDev->_getTwilightDevice, 'elevation', -1 )
if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Twilight' );
$elevation = ReadingsVal( $ascDev->_getTwilightDevice, 'SunAlt', -1 )
if ( $defs{ $ascDev->_getTwilightDevice }->{TYPE} eq 'Astro' );
return $elevation;
}
sub getASCenable {
my $self = shift;
my $name = $self->{name};
return ReadingsVal( $name, 'ascEnable', 'none' );
}
## Subklasse Attr ##
package ASC_Dev::Attr;
use strict;
use warnings;
use GPUtils qw(GP_Import);
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(
AttrVal
gettimeofday)
);
}
sub getShuttersOffset {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_shuttersDriveOffset', -1 );
}
sub getBrightnessMinVal {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_brightness}->{triggermin}
if ( exists( $self->{ASC_brightness}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 );
$ascDev->getBrightnessMaxVal;
return $self->{ASC_brightness}->{triggermin};
}
sub getBrightnessMaxVal {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_brightness}->{triggermax}
if ( exists( $self->{ASC_brightness}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_brightness}->{LASTGETTIME} ) < 2 );
$self->{ASC_brightness}->{LASTGETTIME} = int( gettimeofday() );
my ( $triggermax, $triggermin ) =
FHEM::AutoShuttersControl::GetAttrValues( $name,
'ASC_brightnessDriveUpDown', '800:500' );
## erwartetes Ergebnis
# max:min
$self->{ASC_brightness}->{triggermin} = $triggermin;
$self->{ASC_brightness}->{triggermax} = $triggermax;
return $self->{ASC_brightness}->{triggermax};
}
sub _getTwilightDevice {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_twilightDevice', 'none' );
}
sub getAutoAstroModeEvening {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoAstroModeEvening', 'REAL' );
}
sub getAutoAstroModeEveningHorizon {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoAstroModeEveningHorizon', 0 );
}
sub getAutoAstroModeMorning {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoAstroModeMorning', 'REAL' );
}
sub getAutoAstroModeMorningHorizon {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoAstroModeMorningHorizon', 0 );
}
sub getAutoShuttersControlMorning {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoShuttersControlMorning', 'on' );
}
sub getAutoShuttersControlEvening {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoShuttersControlEvening', 'on' );
}
sub getAutoShuttersControlComfort {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_autoShuttersControlComfort', 'off' );
}
sub getFreezeTemp {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_freezeTemp', 3 );
}
sub _getTempSensor {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_tempSensor}->{device}
if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 );
$self->{ASC_tempSensor}->{LASTGETTIME} = int( gettimeofday() );
my ( $device, $reading ) =
FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_tempSensor',
'none' );
## erwartetes Ergebnis
# DEVICE:READING
return $device if ( $device eq 'none' );
$self->{ASC_tempSensor}->{device} = $device;
$self->{ASC_tempSensor}->{reading} =
( $reading ne 'none' ? $reading : 'temperature' );
return $self->{ASC_tempSensor}->{device};
}
sub getTempSensorReading {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_tempSensor}->{reading}
if ( exists( $self->{ASC_tempSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_tempSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getTempSensor;
return $self->{ASC_tempSensor}->{reading};
}
sub _getResidentsDev {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_residentsDev}->{device}
if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 );
$self->{ASC_residentsDev}->{LASTGETTIME} = int( gettimeofday() );
my ( $device, $reading ) =
FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_residentsDev',
'none' );
$self->{ASC_residentsDev}->{device} = $device;
$self->{ASC_residentsDev}->{reading} =
( $reading ne 'none' ? $reading : 'state' );
return $self->{ASC_residentsDev}->{device};
}
sub getResidentsReading {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_residentsDev}->{reading}
if ( exists( $self->{ASC_residentsDev}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_residentsDev}->{LASTGETTIME} ) < 2 );
$ascDev->_getResidentsDev;
return $self->{ASC_residentsDev}->{reading};
}
sub _getRainSensor {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_rainSensor}->{device}
if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 );
$self->{ASC_rainSensor}->{LASTGETTIME} = int( gettimeofday() );
my ( $device, $reading, $max, $hyst, $pos ) =
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 );
return $self->{ASC_rainSensor}->{device};
}
sub getRainSensorReading {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_rainSensor}->{reading}
if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getRainSensor;
return $self->{ASC_rainSensor}->{reading};
}
sub getRainTriggerMax {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_rainSensor}->{triggermax}
if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getRainSensor;
return $self->{ASC_rainSensor}->{triggermax};
}
sub getRainTriggerMin {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_rainSensor}->{triggerhyst}
if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getRainSensor;
return $self->{ASC_rainSensor}->{triggerhyst};
}
sub getRainSensorShuttersClosedPos {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_rainSensor}->{shuttersClosedPos}
if ( exists( $self->{ASC_rainSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_rainSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getRainSensor;
return $self->{ASC_rainSensor}->{shuttersClosedPos};
}
sub _getWindSensor {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_windSensor}->{device}
if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 );
$self->{ASC_windSensor}->{LASTGETTIME} = int( gettimeofday() );
my ( $device, $reading ) =
FHEM::AutoShuttersControl::GetAttrValues( $name, 'ASC_windSensor',
'none' );
return $device if ( $device eq 'none' );
$self->{ASC_windSensor}->{device} = $device;
$self->{ASC_windSensor}->{reading} =
( $reading ne 'none' ? $reading : 'wind' );
return $self->{ASC_windSensor}->{device};
}
sub getWindSensorReading {
my $self = shift;
my $name = $self->{name};
return $self->{ASC_windSensor}->{reading}
if ( exists( $self->{ASC_windSensor}->{LASTGETTIME} )
and ( gettimeofday() - $self->{ASC_windSensor}->{LASTGETTIME} ) < 2 );
$ascDev->_getWindSensor;
return (
defined( $self->{ASC_windSensor}->{reading} )
? $self->{ASC_windSensor}->{reading}
: 'wind'
);
}
sub getblockAscDrivesAfterManual {
my $self = shift;
my $name = $self->{name};
return AttrVal( $name, 'ASC_blockAscDrivesAfterManual', 0 );
}
1;
=pod
=item device
=item summary Module for controlling shutters depending on various conditions
=item summary_DE Modul zur automatischen Rolladensteuerung auf Basis bestimmter Ereignisse
=begin html
';
$ret .= '';
$ret .= ' ';
$ret .= '
';
$ret .= " ';
if ( ref($notifydevs) eq "HASH" ) {
my $linecount = 1;
foreach my $notifydev ( sort keys( %{$notifydevs} ) ) {
if ( ref( $notifydevs->{$notifydev} ) eq "HASH" ) {
foreach
my $shutters ( sort keys( %{ $notifydevs->{$notifydev} } ) )
{
if ( $linecount % 2 == 0 ) { $ret .= 'Shutters/ASC-Device ";
$ret .= " ";
$ret .= "NOTIFYDEV ";
$ret .= " ";
$ret .= "Attribut ";
$ret .= " ";
$ret .= ''; }
else { $ret .= ' '; }
$ret .= " ';
$linecount++;
}
}
}
}
$ret .= '$shutters ";
$ret .= " ";
$ret .= "$notifydev ";
$ret .= " ";
$ret .= "$notifydevs->{$notifydev}{$shutters} ";
$ret .= " ";
$ret .= 'AutoShuttersControl
define <name> AutoShuttersControl
define myASControl AutoShuttersControl
This creates an new AutoShuttersControl device, called myASControl.
Now was the new global attribute ASC added to the FHEM installation.
Each shutter that is to be controlled by AutoShuttersControl must now have the attribute ASC set to 1 or 2.
The value 1 is to be used with devices whose state is given as position (i.e. ROLLO or Siro, shutters
openend is 0, shutters closed is 100), 2 with devices whose state is given as percent closed (i.e. HomeMatic,
shutters opened is 100, closed is 0).
After setting the attributes to all devices who should be controlled, the automatic scan at the main device
can be started for example with
set myASControl scanForShutters
Within the ASC device:
Within the shutter devices:
At the global ASC device:
At shutter devices, controlled by ASC:
HomeMaticmode. Shutter is open equals to 100, shutter is closed equals to 0, is controlled by pct values.
50:20 ASC_Closed_Pos.
Shading
Shading is only available if the following prerequests are met:
- The controlShading reading is set to on, and there is a device of type Astro or Twilight configured to ASC_twilightDevice, and ASC_tempSensor is set.
- ASC_BrightnessSensor is configured to any shutter device.
- All other attributes are optional and the default value for them is used, if they are not otherwise configured. Please review the settings carefully, especially the values for StateChange_Cloudy and StateChange_Sunny.
The following attributes are available:
- ASC_Shading_Angle_Left - Minimal shading angle in relation to the window, from when shade is applied. For example: Window is 180 ° (perpendicular) − 85 ° set for ASC_Shading_Angle_Left → shading starts if sun position is 95 °. Defaults to 75.
- ASC_Shading_Angle_Right - Complements ASC_Shading_Angle_Left and sets the maximum shading angle in relation to the window. For example: Window is 180 ° (perpendicular) + 85 ° set from ASC_Shading_Angle_Right → shading until sun position of 265 ° is reached. Defaults to 75.
- ASC_Shading_Direction - Compass point degrees for which the window resp. shutter points. East is 90 °, South 180 °, West is 270 ° and North is 0 °. Defaults to South (180).
- ASC_Shading_MinMax_Elevation - Shading starts as min point of sun elevation is reached and end as max point of sun elevation is reached, depending also on other sensor values. Defaults to 25.0:100.0.
- ASC_Shading_Min_OutsideTemperature - Shading starts at this outdoor temperature, depending also on other sensor values. Defaults to 18.0.
- ASC_Shading_Mode absent|always|off|home - see ASC_Mode_Down above, but for shading. Defaults to off.
- ASC_Shading_Pos - Shading position in percent.
- ASC_Shading_StateChange_Cloudy - Shading ends at this outdoor brightness, depending also on other sensor values. Defaults to 20000.
- ASC_Shading_StateChange_Sunny - Shading starts at this outdoor brightness, depending also on other sensor values. Defaults to 35000.
- ASC_Shading_WaitingPeriod - Waiting time in seconds before additional sensor values to ASC_Shading_StateChange_Sunny or ASC_Shading_StateChange_Cloudy are used for shading. Defaults to 120.
AutoShuttersControl API description
It's possible to access internal data of the ASC module by calling the API function.
Data points of a shutter device, controlled by ASC
{ ascAPIget('Getter','SHUTTERS_DEVICENAME') }