###############################################################################
#
# 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;
use FHEM::Meta;
my $version = '0.6.15.4';
sub AutoShuttersControl_Initialize($) {
my ($hash) = @_;
# ### alte Attribute welche entfernt werden
# my $oldAttr =
# 'ASC_temperatureSensor '
# . 'ASC_temperatureReading '
# . 'ASC_residentsDevice '
# . 'ASC_residentsDeviceReading '
# . 'ASC_rainSensorDevice '
# . 'ASC_rainSensorReading '
# . 'ASC_rainSensorShuttersClosedPos:0,10,20,30,40,50,60,70,80,90,100 '
# . 'ASC_brightnessMinVal '
# . 'ASC_brightnessMaxVal ';
## Da ich mit package arbeite müssen in die Initialize für die jeweiligen hash Fn Funktionen der Funktionsname
# und davor mit :: getrennt der eigentliche package Name des Modules
$hash->{SetFn} = 'FHEM::AutoShuttersControl::Set';
$hash->{GetFn} = 'FHEM::AutoShuttersControl::Get';
$hash->{DefFn} = 'FHEM::AutoShuttersControl::Define';
$hash->{NotifyFn} = 'FHEM::AutoShuttersControl::Notify';
$hash->{UndefFn} = 'FHEM::AutoShuttersControl::Undef';
$hash->{AttrFn} = 'FHEM::AutoShuttersControl::Attr';
$hash->{AttrList} =
'ASC_tempSensor '
. 'ASC_brightnessDriveUpDown '
. 'ASC_autoShuttersControlMorning:on,off '
. 'ASC_autoShuttersControlEvening:on,off '
. 'ASC_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 '
# . $oldAttr
. $readingFnAttributes;
$hash->{NotifyOrderPrefix} = '51-'; # Order Nummer für NotifyFn
return FHEM::Meta::InitMod( __FILE__, $hash );
}
sub ascAPIget($;$) {
my ( $getCommand, $shutterDev ) = @_;
return FHEM::AutoShuttersControl::ascAPIget( $getCommand, $shutterDev );
}
## unserer packagename
package FHEM::AutoShuttersControl;
use strict;
use warnings;
use POSIX;
use FHEM::Meta;
use GPUtils qw(:all)
; # wird für den Import der FHEM Funktionen aus der fhem.pl benötigt
use Data::Dumper; #only for Debugging
use Date::Parse;
my $missingModul = '';
eval "use JSON qw(decode_json encode_json);1" or $missingModul .= 'JSON ';
## Import der FHEM Funktionen
BEGIN {
GP_Import(
qw(devspec2array
readingsSingleUpdate
readingsBulkUpdate
readingsBulkUpdateIfChanged
readingsBeginUpdate
readingsEndUpdate
defs
modules
Log3
CommandAttr
attr
CommandDeleteAttr
CommandDeleteReading
CommandSet
AttrVal
ReadingsVal
Value
IsDisabled
deviceEvents
init_done
addToDevAttrList
addToAttrList
delFromDevAttrList
delFromAttrList
gettimeofday
sunset_abs
sunrise_abs
InternalTimer
RemoveInternalTimer
computeAlignTime
ReplaceEventMap)
);
}
## 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_WindowRec' => '-',
'ASC_Ventilate_Window_Open:on,off' => '-',
'ASC_LockOut:soft,hard,off' => '-',
'ASC_LockOut_Cmd:inhibit,blocked,protection' => '-',
'ASC_BlockingTime_afterManual' => '-',
'ASC_BlockingTime_beforNightClose' => '-',
'ASC_BlockingTime_beforDayOpen' => '-',
'ASC_BrightnessSensor' => '-',
'ASC_Shading_Direction' => '-',
'ASC_Shading_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 80, 20 ],
'ASC_Shading_Mode:absent,always,off,home' => '-',
'ASC_Shading_Angle_Left' => '-',
'ASC_Shading_Angle_Right' => '-',
'ASC_Shading_StateChange_Sunny' => '-',
'ASC_Shading_StateChange_Cloudy' => '-',
'ASC_Shading_Min_Elevation' => '-',
'ASC_Shading_Min_OutsideTemperature' => '-',
'ASC_Shading_WaitingPeriod' => '-',
'ASC_Drive_Offset' => '-',
'ASC_Drive_OffsetStart' => '-',
'ASC_WindowRec_subType:twostate,threestate' => '-',
'ASC_ShuttersPlace:window,terrace' => '-',
'ASC_Ventilate_Pos:10,20,30,40,50,60,70,80,90,100' => [ '', 70, 30 ],
'ASC_ComfortOpen_Pos:0,10,20,30,40,50,60,70,80,90,100' => [ '', 20, 80 ],
'ASC_GuestRoom:on,off' => '-',
'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_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',
);
my $shutters = new ASC_Shutters();
my $ascDev = new ASC_Dev();
sub ascAPIget($;$) {
my ( $getCommand, $shutterDev ) = @_;
my $getter = 'get' . $getCommand;
if ( defined($shutterDev) and $shutterDev ) {
$shutters->setShuttersDev($shutterDev);
return $shutters->$getter;
}
else {
return $ascDev->$getter;
}
}
sub Define($$) {
my ( $hash, $def ) = @_;
my @a = split( '[ \t][ \t]*', $def );
return $@ unless ( FHEM::Meta::SetInternals($hash) );
return 'only one AutoShuttersControl instance allowed'
if ( devspec2array('TYPE=AutoShuttersControl') > 1 )
; # es wird geprüft ob bereits eine Instanz unseres Modules existiert,wenn ja wird abgebrochen
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 .= "" . $shutters->getLastDrive . " ";
$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 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 IsDay($shuttersDev)
and $shutters->getSunriseUnixTime - ( int( gettimeofday() ) ) <
$shutters->getBlockingTimeBeforDayOpen )
or ( IsDay($shuttersDev)
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 =~ /open/ ) # CK: covers: open|opened
{
return 2;
}
elsif ( $shutters->getWinStatus =~ /tilt/
and $shutters->getSubTyp eq 'threestate' ) # CK: covers: tilt|tilted
{
return 1;
}
elsif ( $shutters->getWinStatus =~ /close/ ) {
return 0;
} # CK: covers: close|closed
}
sub makeReadingName($) {
my ($rname) = @_;
my %charHash = (
"ä" => "ae",
"Ä" => "Ae",
"ü" => "ue",
"Ü" => "Ue",
"ö" => "oe",
"Ö" => "Oe",
"ß" => "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 );
}
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 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 ( $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} };
readingsSingleUpdate( $shuttersDevHash, 'ASC_ShuttersLastDrive',
$shutters->getLastDrive, 1 );
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 getIsDay {
my $self = shift;
return FHEM::AutoShuttersControl::IsDay( $self->{shuttersDev} );
}
sub getFreezeStatus {
use POSIX qw(strftime);
my $self = shift;
my $daytime = strftime( "%P", localtime() );
if ( $shutters->getAntiFreeze ne 'off'
and $ascDev->getOutTemp <= $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 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' => 4,
'absent' => 5,
'gone' => 6,
'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};
}
### 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 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 getIfInShading {
my $self = shift;
return (
(
$shutters->getShadingMode eq 'always'
or $shutters->getShadingMode eq 'home'
)
and $shutters->getShadingStatus eq 'in' ? 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} ) );
}
### 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 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 _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
return $device if ( $device eq 'none' );
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device} = $device;
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{reading} =
( $reading ne 'none' ? $reading : 'brightness' );
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermin} =
( $min ne 'none' ? $min : '-1' );
$self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{triggermax} =
( $max ne 'none' ? $max : '-1' );
return $self->{ $self->{shuttersDev} }->{ASC_BrightnessSensor}->{device};
}
sub getBrightnessReading {
my $self = shift;
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 AttrVal( $self->{shuttersDev}, 'ASC_Shading_Min_Elevation', 25.0 );
}
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 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->getTempReading,
-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 getTempReading {
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 ASC_autoShuttersControlShading attribute 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_Min_Elevation - Shading starts as this point of sun elevation is reached, depending also on other sensor values. Defaults to 25.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') }
Getter | Description |
---|---|
FreezeStatus | 1 = soft, 2 = daytime, 3 = hard |
NoOffset | Was the offset handling deactivated (e.g. by operations triggered by a window event) |
LastDrive | Reason for the last action caused by ASC |
LastPos | Last position of the shutter |
LastPosTimestamp | Timestamp of the last position |
LastManPos | Last position manually set of the shutter |
LastManPosTimestamp | Timestamp of the last position manually set |
SunsetUnixTime | Calculated sunset time in seconds since the UNIX epoche |
Sunset | 1 = operation in the evening was made, 0 = operation in the evening was not yet made |
SunriseUnixTime | Calculated sunrise time in seconds since the UNIX epoche |
Sunrise | 1 = operation in the morning was made, 0 = operation in the morning was not yet made |
RoommatesStatus | Current state of the room mate set for this shutter |
RoommatesLastStatus | Last state of the room mate set for this shutter |
ShadingStatus | Value of the current shading state. Can hold in, out, in reserved or out reserved |
ShadingStatusTimestamp | Timestamp of the last shading state |
IfInShading | Is the shutter currently in shading (depends on the shading mode) |
WindProtectionStatus | Current state of the wind protection. Can hold protection or unprotection |
RainProtectionStatus | Current state of the rain protection. Can hold protection or unprotection |
DelayCmd | Last operation order in the waiting queue. Set for example by the party mode |
Status | Position of the shutter |
ASCenable | Does ASC control the shutter? |
{ ascAPIget('Getter') }
Getter | Description |
---|---|
outTemp | Current temperature of a configured temperature device |
ResidentsStatus | Current state of a configured resident device |
ResidentsLastStatus | Last state of a configured resident device |
Azimuth | Current azimuth of the sun |
Elevation | Current elevation of the sun |
ASCenable | Is ASC globally activated? |
AutoShuttersControl (ASC) ermöglicht eine vollständige Automatisierung der vorhandenen Rollläden. Das Modul bietet umfangreiche Konfigurationsmöglichkeiten, um Rollläden bspw. nach Sonnenauf- und untergangszeiten, nach Helligkeitswerten oder rein zeitgesteuert zu steuern.
Man kann festlegen, welche Rollläden von ASC in die Automatisierung mit aufgenommen werden sollen. Daraufhin stehen diverse Attribute zur Feinkonfiguration zur Verfügung. So sind unter anderem komplexe Lösungen wie Fahrten in Abhängigkeit des Bewohnerstatus einfach umsetzbar. Beispiel: Hochfahren von Rollläden, wenn der Bewohner erwacht ist und draußen bereits die Sonne aufgegangen ist. Weiterhin ist es möglich, dass der geschlossene Rollladen z.B. nach dem Ankippen eines Fensters in eine Lüftungsposition fährt. Und vieles mehr.
Definedefine <name> AutoShuttersControl
define myASControl AutoShuttersControl
{ ascAPIget('Getter','ROLLODEVICENAME') }
Getter | Erläuterung |
---|---|
FreezeStatus | 1=soft, 2=Daytime, 3=hard |
NoOffset | Wurde die Behandlung von Offset deaktiviert (Beispiel bei Fahrten über Fensterevents) |
LastDrive | Grund des letzten Fahrens |
LastPos | die letzte Position des Rollladens |
LastPosTimestamp | Timestamp der letzten festgestellten Position |
LastManPos | Position der letzten manuellen Fahrt |
LastManPosTimestamp | Timestamp der letzten manuellen Position |
SunsetUnixTime | berechnete Unixzeit für Abends (Sonnenuntergang) |
Sunset | 1=Abendfahrt wurde durchgeführt, 0=noch keine Abendfahrt durchgeführt |
SunriseUnixTime | berechnete Unixzeit für Morgens (Sonnenaufgang) |
Sunrise | 1=Morgenfahrt wurde durchgeführt, 0=noch keine Morgenfahrt durchgeführt |
RoommatesStatus | aktueller Status der/des Roommate/s für den Rollladen |
RoommatesLastStatus | letzter Status der/des Roommate/s für den Rollladen |
ShadingStatus | Ausgabe des aktuellen Shading Status, „in“, „out“, „in reserved“, „out reserved“ |
ShadingStatusTimestamp | Timestamp des letzten Beschattungsstatus |
IfInShading | Befindet sich der Rollladen, in Abhängigkeit des Shading Mode, in der Beschattung |
WindProtectionStatus | aktueller Status der Wind Protection „protected“ oder „unprotected“ |
RainProtectionStatus | aktueller Status der Regen Protection „unprotected“ oder „unprotected“ |
DelayCmd | letzter Fahrbefehl welcher in die Warteschlange kam. Grund z.B. Partymodus. |
Status | Position des Rollladens |
ASCenable | Abfrage ob für den Rollladen die ASC Steuerung aktiv ist. |
IsDay | Abfrage ob das Rollo im Tag oder Nachtmodus ist. Also nach Sunset oder nach Sunrise |
{ ascAPIget('Getter') }
Getter | Erläuterung |
---|---|
outTemp | aktuelle Außentemperatur sofern Sensor definiert |
ResidentsStatus | aktueller Status des Residents Devices |
ResidentsLastStatus | letzter Status des Residents Devices |
Azimuth | Azimut Wert |
Elevation | Elevation Wert |
ASCenable | ist die ASC Steuerung global aktiv? |