| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315 |
- ###############################################################################
- # $Id: HOMESTATEtk.pm 14339 2017-05-21 15:31:50Z loredo $
- package main;
- use strict;
- use warnings;
- use Data::Dumper;
- use Time::Local;
- require RESIDENTStk;
- # module variables ############################################################
- my %stateSecurity = (
- en => [ 'unlocked', 'locked', 'protected', 'secured', 'guarded' ],
- de =>
- [ 'unverriegelt', 'verriegelt', 'geschützt', 'gesichert', 'überwacht' ],
- icons => [
- 'status_open@yellow', 'status_standby@yellow@green',
- 'status_night@green', 'status_locked@green',
- 'building_security@green'
- ],
- );
- my %stateOnoff = (
- en => [ 'off', 'on' ],
- de => [ 'aus', 'an' ],
- );
- my %readingsMap = (
- date_long => 'calTod',
- date_short => 'calTodS',
- daytime_long => 'daytime',
- daytimeStage => 'daytimeStage',
- daytimeStageLn => 'calTodDaytimeStageLn',
- daytimeT => 'calTodDaytimeT',
- day_desc => 'calTodDesc',
- # dstchange => 'calTodDSTchng',
- dst_long => 'calTodDST',
- isholiday => 'calTodHoliday',
- isly => 'calTodLeapyear',
- iswe => 'calTodTodWeekend',
- mday => 'calTodMonthday',
- mdayrem => 'calTodMonthdayRem',
- monISO => 'calTodMonthN',
- mon_long => 'calTodMonth',
- mon_short => 'calTodMonthS',
- rday_long => 'calTodRel',
- seasonAstroChng => 'calTodSAstroChng',
- seasonAstro_long => 'calTodSAstro',
- seasonMeteoChng => 'calTodSMeteoChng',
- seasonMeteo_long => 'calTodSMeteo',
- seasonPheno_long => 'calTodSPheno',
- sunrise => 'calTodSunrise',
- sunset => 'calTodSunset',
- daytimeStages => 'daytimeStages',
- wdaynISO => 'calTodWeekdayN',
- wday_long => 'calTodWeekday',
- wday_short => 'calTodWeekdayS',
- weekISO => 'calTodWeek',
- yday => 'calTodYearday',
- ydayrem => 'calTodYeardayRem',
- year => 'calTodYear',
- );
- my %readingsMap_tom = (
- date_long => 'calTom',
- date_short => 'calTomS',
- daytimeStageLn => 'calTomDaytimeStageLn',
- daytimeT => 'calTomDaytimeT',
- day_desc => 'calTomDesc',
- # dstchange => 'calTomDSTchng',
- dst_long => 'calTomDST',
- isholiday => 'calTomHoliday',
- isly => 'calTomLeapyear',
- iswe => 'calTomWeekend',
- mday => 'calTomMonthday',
- mdayrem => 'calTomMonthdayRem',
- monISO => 'calTomMonthN',
- mon_long => 'calTomMonth',
- mon_short => 'calTomMonthS',
- rday_long => 'calTomRel',
- seasonAstroChng => 'calTomSAstroChng',
- seasonAstro_long => 'calTomSAstro',
- seasonMeteoChng => 'calTomSMeteoChng',
- seasonMeteo_long => 'calTomSMeteo',
- seasonPheno_long => 'calTodSPheno',
- sunrise => 'calTomSunrise',
- sunset => 'calTomSunset',
- wdaynISO => 'calTomWeekdayN',
- wday_long => 'calTomWeekday',
- wday_short => 'calTomWeekdayS',
- weekISO => 'calTomWeek',
- yday => 'calTomYearday',
- ydayrem => 'calTomYeardayRem',
- year => 'calTomYear',
- );
- # initialize ##################################################################
- sub HOMESTATEtk_Initialize($) {
- my ($hash) = @_;
- $hash->{InitDevFn} = "HOMESTATEtk_InitializeDev";
- $hash->{DefFn} = "HOMESTATEtk_Define";
- $hash->{UndefFn} = "HOMESTATEtk_Undefine";
- $hash->{SetFn} = "HOMESTATEtk_Set";
- $hash->{GetFn} = "HOMESTATEtk_Get";
- $hash->{AttrFn} = "HOMESTATEtk_Attr";
- $hash->{NotifyFn} = "HOMESTATEtk_Notify";
- $hash->{parseParams} = 1;
- $hash->{AttrList} =
- "disable:1,0 disabledForIntervals do_not_notify:1,0 "
- . $readingFnAttributes
- . " Lang:EN,DE DebugDate ";
- my $holidayFilter =
- $attr{global}{holiday2we}
- ? ":FILTER=NAME!=" . $attr{global}{holiday2we}
- : "";
- $hash->{AttrList} .=
- " HolidayDevices:multiple,"
- . join( ",", devspec2array( "TYPE=holiday" . $holidayFilter ) );
- $hash->{AttrList} .= " ResidentsDevices:multiple,"
- . join( ",", devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE,TYPE=GUEST") );
- }
- # module Fn ####################################################################
- sub HOMESTATEtk_InitializeDev($) {
- my ($hash) = @_;
- $hash = $defs{$hash} unless ( ref($hash) );
- my $name = $hash->{NAME};
- my $TYPE = $hash->{TYPE};
- my $changed = 0;
- my $lang =
- lc( AttrVal( $name, "Lang", AttrVal( "global", "language", "EN" ) ) );
- my $langUc = uc($lang);
- my @error;
- delete $hash->{NEXT_EVENT};
- RemoveInternalTimer($hash);
- no strict "refs";
- &{ $TYPE . "_Initialize" }( \%{ $modules{$TYPE} } ) if ($init_done);
- use strict "refs";
- # NOTIFYDEV
- my $NOTIFYDEV = "global,$name";
- $NOTIFYDEV .= "," . HOMESTATEtk_findHomestateSlaves($hash);
- unless ( defined( $hash->{NOTIFYDEV} ) && $hash->{NOTIFYDEV} eq $NOTIFYDEV )
- {
- $hash->{NOTIFYDEV} = $NOTIFYDEV;
- $changed = 1;
- }
- my $time = time;
- my $debugDate = AttrVal( $name, "DebugDate", "" );
- if ( $debugDate =~
- m/^((?:\d{4}\-)?\d{2}-\d{2})(?: (\d{2}:\d{2}(?::\d{2})?))?$/ )
- {
- my $date = "$1";
- $date .= " $2" if ($2);
- my ( $sec, $min, $hour, $mday, $mon, $year ) = UConv::_time();
- $date = "$year-$date" unless ( $date =~ /^\d{4}-/ );
- $date .= "00:00:00" unless ( $date =~ /\d{2}:\d{2}:\d{2}$/ );
- $date .= ":00" unless ( $date =~ /\d{2}:\d{2}:\d{2}$/ );
- $time = time_str2num($date);
- push @error, "WARNING: DebugDate in use ($date)";
- }
- delete $hash->{'.events'};
- delete $hash->{'.t'};
- $hash->{'.t'} = HOMESTATEtk_GetDaySchedule( $hash, $time, undef, $lang );
- $hash->{'.events'} = $hash->{'.t'}{events};
- ## begin reading updates
- #
- readingsBeginUpdate($hash);
- foreach ( sort keys %{ $hash->{'.t'} } ) {
- next if ( ref( $hash->{'.t'}{$_} ) );
- my $r = $readingsMap{$_} ? $readingsMap{$_} : undef;
- my $v = $hash->{'.t'}{$_};
- readingsBulkUpdateIfChanged( $hash, $r, $v )
- if ( defined($r) );
- $r = $readingsMap_tom{$_} ? $readingsMap_tom{$_} : undef;
- $v = $hash->{'.t'}{1}{$_} ? $hash->{'.t'}{1}{$_} : undef;
- readingsBulkUpdateIfChanged( $hash, $r, $v )
- if ( defined($r) && defined($v) );
- }
- unless ( $lang =~ /^en/i || !$hash->{'.t'}{$lang} ) {
- foreach ( sort keys %{ $hash->{'.t'}{$lang} } ) {
- next if ( ref( $hash->{'.t'}{$lang}{$_} ) );
- my $r = $readingsMap{$_} ? $readingsMap{$_} . "_$langUc" : undef;
- my $v = $hash->{'.t'}{$lang}{$_};
- readingsBulkUpdateIfChanged( $hash, $r, $v )
- if ( defined($r) );
- $r =
- $readingsMap_tom{$_} ? $readingsMap_tom{$_} . "_$langUc" : undef;
- $v =
- $hash->{'.t'}{1}{$lang}{$_} ? $hash->{'.t'}{1}{$lang}{$_} : undef;
- readingsBulkUpdateIfChanged( $hash, $r, $v )
- if ( defined($r) && defined($v) );
- }
- }
- # TODO: seasonSocial
- #
- # TODO: höchster Sonnenstand
- # > Trend Sonne aufgehend, abgehend?
- # > temperaturmaximum 14h / 15h bei DST
- # error
- if ( scalar @error ) {
- readingsBulkUpdateIfChanged( $hash, "error", join( "; ", @error ) );
- }
- else {
- delete $hash->{READINGS}{error};
- }
- HOMESTATEtk_UpdateReadings($hash);
- readingsEndUpdate( $hash, 1 );
- #
- ## end reading updates
- # schedule next timer
- foreach ( sort keys %{ $hash->{'.events'} } ) {
- next if ( $_ < $time );
- $hash->{NEXT_EVENT} =
- $hash->{'.events'}{$_}{TIME} . " - " . $hash->{'.events'}{$_}{DESC};
- InternalTimer( $_, "HOMESTATEtk_InitializeDev", $hash );
- last;
- }
- return 0 unless ($changed);
- return undef;
- }
- sub HOMESTATEtk_Define($$$) {
- my ( $hash, $a, $h ) = @_;
- my $name = shift @$a;
- my $TYPE = shift @{$a};
- my $name_attr;
- $hash->{MOD_INIT} = 1;
- $hash->{NOTIFYDEV} = "global";
- delete $hash->{NEXT_EVENT};
- RemoveInternalTimer($hash);
- # set default settings on first define
- if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
- HOMESTATEtk_Attr( "init", $name, "Lang" );
- $attr{$name}{room} = "Homestate";
- $attr{$name}{devStateIcon} =
- '{(HOMESTATEtk_devStateIcon($name),"toggle")}';
- $attr{$name}{icon} = "control_building_control"
- if ( $TYPE eq "HOMESTATE" );
- $attr{$name}{icon} = "control_building_eg"
- if ( $TYPE eq "SECTIONSTATE" );
- $attr{$name}{icon} = "floor"
- if ( $TYPE eq "ROOMSTATE" );
- # find HOMESTATE device
- if ( $TYPE eq "ROOMSTATE" || $TYPE eq "SECTIONSTATE" ) {
- my @homestates = devspec2array("TYPE=HOMESTATE");
- if ( scalar @homestates ) {
- $attr{$name}{"HomestateDevices"} = $homestates[0];
- $attr{$name}{room} = $attr{ $homestates[0] }{room}
- if ( $attr{ $homestates[0] }
- && $attr{ $homestates[0] }{room} );
- $attr{$name}{"Lang"} = $attr{ $homestates[0] }{Lang}
- if ( $attr{ $homestates[0] }
- && $attr{ $homestates[0] }{Lang} );
- HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} )
- if $attr{$name}{"Lang"};
- }
- else {
- my $n = "Home";
- my $i = "";
- while ( IsDevice( $n . $i ) ) {
- $i = 0 if ( $i eq "" );
- $i++;
- }
- CommandDefine( undef, "$n HOMESTATE" );
- $attr{$n}{comment} =
- "Auto-created by $TYPE module for use with HOMESTATE Toolkit";
- $attr{$name}{"HomestateDevices"} = $n;
- $attr{$name}{room} = $attr{$n}{room};
- $attr{$name}{"Lang"} = $attr{ $homestates[0] }{Lang}
- if ( $attr{ $homestates[0] }
- && $attr{ $homestates[0] }{Lang} );
- HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} )
- if $attr{$name}{"Lang"};
- }
- }
- # find ROOMSTATE device
- if ( $TYPE eq "SECTIONSTATE" ) {
- my @roomstates = devspec2array("TYPE=ROOMSTATE");
- unless ( scalar @roomstates ) {
- my $n = "Room";
- my $i = "";
- while ( IsDevice( $n . $i ) ) {
- $i = 0 if ( $i eq "" );
- $i++;
- }
- CommandDefine( undef, "$n ROOMSTATE" );
- $attr{$n}{comment} =
- "Auto-created by $TYPE module for use with HOMESTATE Toolkit";
- $attr{$name}{room} = $attr{$n}{room};
- $attr{$name}{"Lang"} = $attr{ $roomstates[0] }{Lang}
- if ( $attr{ $roomstates[0] }
- && $attr{ $roomstates[0] }{Lang} );
- HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} )
- if $attr{$name}{"Lang"};
- }
- }
- # find RESIDENTS device
- if ( $TYPE eq "HOMESTATE" ) {
- my @residents = devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE");
- if ( scalar @residents ) {
- $attr{$name}{"ResidentsDevices"} = $residents[0];
- $attr{$name}{room} = $attr{ $residents[0] }{room}
- if ( $attr{ $residents[0] } && $attr{ $residents[0] }{room} );
- $attr{$name}{"Lang"} = $attr{ $residents[0] }{rgr_lang}
- if ( $attr{ $residents[0] }
- && $attr{ $residents[0] }{rgr_lang} );
- $attr{$name}{"Lang"} = $attr{ $residents[0] }{rr_lang}
- if ( $attr{ $residents[0] }
- && $attr{ $residents[0] }{rr_lang} );
- HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} )
- if $attr{$name}{"Lang"};
- }
- else {
- my $n = "rgr_Residents";
- my $i = "";
- while ( IsDevice( $n . $i ) ) {
- $i = 0 if ( $i eq "" );
- $i++;
- }
- CommandDefine( undef, "$n RESIDENTS" );
- $attr{$n}{comment} =
- "Auto-created by $TYPE module for use with HOMESTATE Toolkit";
- $attr{$name}{"ResidentsDevices"} = $n;
- $attr{$n}{room} = $attr{$name}{room};
- HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} )
- if $attr{$name}{"Lang"};
- $attr{$name}{group} = $attr{$n}{group};
- }
- }
- }
- return undef;
- }
- sub HOMESTATEtk_Undefine($$) {
- my ( $hash, $name ) = @_;
- delete $hash->{NEXT_EVENT};
- RemoveInternalTimer($hash);
- return undef;
- }
- sub HOMESTATEtk_Set($$$);
- sub HOMESTATEtk_Set($$$) {
- my ( $hash, $a, $h ) = @_;
- my $TYPE = $hash->{TYPE};
- my $name = shift @$a;
- my $lang =
- lc( AttrVal( $name, "Lang", AttrVal( "global", "language", "EN" ) ) );
- my $langUc = uc($lang);
- my $state = ReadingsVal( $name, "state", "" );
- my $mode = ReadingsVal( $name, "mode", "" );
- my $security = ReadingsVal( $name, "security", "" );
- my $autoMode =
- HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "autoMode", "on" ),
- $stateOnoff{en} );
- my $silent = 0;
- my %rvals;
- return undef if ( IsDisabled($name) );
- return "No argument given" unless (@$a);
- my $cmd = shift @$a;
- my $usage = "toggle:noArg";
- my $usageL = "";
- # usage: mode
- my $i =
- $autoMode && ReadingsVal( $name, "daytime", "night" ) ne "night"
- ? HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "daytime", 0 ),
- $UConv::daytimes{en} )
- : 0;
- $usage .= " mode:";
- $usageL .= " mode_$langUc:";
- while ( $i < scalar @{ $UConv::daytimes{en} } ) {
- last
- if ( $autoMode
- && $i == 6
- && ReadingsVal( $name, "daytime", "night" ) !~
- m/^evening|midevening|night$/ );
- if ( $autoMode
- && ReadingsVal( $name, "daytime", "night" ) eq "night"
- && $i > 3
- && $i != 6 )
- {
- $i++;
- }
- else {
- $usage .= $UConv::daytimes{en}[$i];
- $usageL .= $UConv::daytimes{$lang}[$i];
- $i++;
- unless ( $autoMode
- && $i == 6
- && ReadingsVal( $name, "daytime", "night" ) !~
- m/^evening|midevening|night$/ )
- {
- $usage .= "," unless ( $i == scalar @{ $UConv::daytimes{en} } );
- $usageL .= ","
- unless ( $i == scalar @{ $UConv::daytimes{$lang} } );
- }
- }
- }
- # usage: autoMode
- $usage .= " autoMode:" . join( ",", @{ $stateOnoff{en} } );
- $usageL .= " autoMode_$langUc:" . join( ",", @{ $stateOnoff{$lang} } );
- $usage .= " $usageL" unless ( $lang eq "en" );
- return "Set usage: choose one of $usage"
- unless ( $cmd && $cmd ne "?" );
- return
- "Device is currently $security and cannot be controlled at this state"
- unless ( $security =~ m/^unlocked|locked$/ );
- # mode
- if ( $cmd eq "state"
- || $cmd eq "mode"
- || $cmd eq "state_$langUc"
- || $cmd eq "mode_$langUc"
- || grep ( m/^$cmd$/i, @{ $UConv::daytimes{en} } )
- || grep ( /^$cmd$/i, @{ $UConv::daytimes{$lang} } ) )
- {
- $cmd = shift @$a
- if ( $cmd eq "state"
- || $cmd eq "mode"
- || $cmd eq "state_$langUc"
- || $cmd eq "mode_$langUc" );
- my $i = HOMESTATEtk_GetIndexFromArray( $cmd, $UConv::daytimes{en} );
- $i = HOMESTATEtk_GetIndexFromArray( $cmd, $UConv::daytimes{$lang} )
- unless ( $lang eq "en" || defined($i) );
- $i = $cmd
- if ( !defined($i)
- && $cmd =~ /^\d+$/
- && defined( $UConv::daytimes{en}[$cmd] ) );
- return "Invalid argument $cmd"
- unless ( defined($i) );
- my $id =
- HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "daytime", 0 ),
- $UConv::daytimes{en} );
- if ($autoMode) {
- # during daytime, one cannot go back in time...
- $i = $id
- if ( ReadingsVal( $name, "daytime", "night" ) ne "night"
- && $i < $id );
- # evening is latest until evening itself was reached
- $i = $id if ( $i >= 6 && $id <= 3 );
- # afternoon is latest until morning was reached
- $i = 6 if ( $i >= 4 && $i != 6 && $id == 6 );
- $i = 0 if ( $i > 6 && $id == 6 );
- }
- Log3 $name, 2, "$TYPE set $name mode " . $UConv::daytimes{en}[$i];
- $rvals{mode} = $UConv::daytimes{en}[$i];
- }
- # toggle
- elsif ( $cmd eq "toggle" ) {
- my $i = HOMESTATEtk_GetIndexFromArray( $mode, $UConv::daytimes{en} );
- my $id =
- HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "daytime", 0 ),
- $UConv::daytimes{en} );
- $i++;
- $i = 0 if ( $i == 7 );
- if ($autoMode) {
- # during daytime, one cannot go back in time...
- $i = $id
- if ( ReadingsVal( $name, "daytime", "night" ) ne "night"
- && $i < $id );
- # evening is latest until evening itself was reached
- $i = $id if ( $i >= 6 && $id <= 3 );
- # afternoon is latest until morning was reached
- $i = 6 if ( $i >= 4 && $i != 6 && $id == 6 );
- $i = 0 if ( $i > 6 && $id == 6 );
- }
- Log3 $name, 2, "$TYPE set $name mode " . $UConv::daytimes{en}[$i];
- $rvals{mode} = $UConv::daytimes{en}[$i];
- }
- # autoMode
- elsif ( $cmd eq "autoMode" || $cmd eq "autoMode_$langUc" ) {
- my $p1 = shift @$a;
- my $i = HOMESTATEtk_GetIndexFromArray( $p1, $stateOnoff{en} );
- $i = HOMESTATEtk_GetIndexFromArray( $p1, $stateOnoff{$lang} )
- unless ( $lang eq "en" || defined($i) );
- $i = $cmd
- if ( !defined($i)
- && $cmd =~ /^\d+$/
- && defined( $stateOnoff{en}[$cmd] ) );
- return "Invalid argument $cmd"
- unless ( defined($i) );
- Log3 $name, 2, "$TYPE set $name autoMode " . $stateOnoff{en}[$i];
- $rvals{autoMode} = $stateOnoff{en}[$i];
- }
- # usage
- else {
- return "Unknown set command $cmd, choose one of $usage";
- }
- readingsBeginUpdate($hash);
- # if autoMode changed
- if ( defined( $rvals{autoMode} ) ) {
- readingsBulkUpdateIfChanged( $hash, "autoMode", $rvals{autoMode} );
- readingsBulkUpdateIfChanged(
- $hash,
- "autoMode_$langUc",
- $stateOnoff{$lang}[
- HOMESTATEtk_GetIndexFromArray(
- $rvals{autoMode}, $stateOnoff{en}
- )
- ]
- ) unless ( $lang eq "en" );
- if ( $rvals{autoMode} eq "on" ) {
- my $im =
- HOMESTATEtk_GetIndexFromArray( $mode, $UConv::daytimes{en} );
- my $id =
- HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "daytime", 0 ),
- $UConv::daytimes{en} );
- $rvals{mode} = $UConv::daytimes{en}[$id]
- if ( $im < $id || ( $im == 6 && $id < 6 ) )
- ; #TODO check when switching during evening and midevening time
- }
- }
- # if mode changed
- if ( defined( $rvals{mode} ) && $rvals{mode} ne $mode ) {
- my $modeL = ReadingsVal( $name, "mode_$langUc", "" );
- readingsBulkUpdate( $hash, "lastMode", $mode ) if ( $mode ne "" );
- readingsBulkUpdate( $hash, "lastMode_$langUc", $modeL )
- if ( $modeL ne "" );
- $mode = $rvals{mode};
- $modeL =
- $UConv::daytimes{$lang}
- [ HOMESTATEtk_GetIndexFromArray( $rvals{mode}, $UConv::daytimes{en} )
- ];
- readingsBulkUpdate( $hash, "mode", $mode );
- readingsBulkUpdate( $hash, "mode_$langUc", $modeL )
- unless ( $lang eq "en" );
- }
- HOMESTATEtk_UpdateReadings($hash);
- readingsEndUpdate( $hash, 1 );
- return undef;
- }
- sub HOMESTATEtk_Get($$$) {
- my ( $hash, $a, $h ) = @_;
- my $name = shift @$a;
- my $lang =
- lc( AttrVal( $name, "Lang", AttrVal( "global", "language", "EN" ) ) );
- my $langUc = uc($lang);
- return "No argument given" unless (@$a);
- my $cmd = shift @$a;
- my $usage = "Unknown argument $cmd, choose one of schedule";
- # schedule
- if ( $cmd eq "schedule" ) {
- my $date = shift @$a;
- my $time = shift @$a;
- if ($date) {
- return "invalid date format $date"
- unless ( !$date
- || $date =~ m/^\d{4}\-\d{2}-\d{2}$/
- || $date =~ m/^\d{2}-\d{2}$/
- || $date =~ m/^\d{10}$/ );
- return "invalid time format $time"
- unless ( !$time
- || $time =~ m/^\d{2}:\d{2}(:\d{2})?$/ );
- unless ( $date =~ m/^\d{10}$/ ) {
- my ( $sec, $min, $hour, $mday, $mon, $year ) = UConv::_time();
- $date = "$year-$date" if ( $date =~ m/^\d{2}-\d{2}$/ );
- $time .= ":00" if ( $time && $time =~ m/^\d{2}:\d{2}$/ );
- $date .= $time ? " $time" : " 00:00:00";
- # ( $year, $mon, $mday, $hour, $min, $sec ) =
- # split( /[\s.:-]+/, $date );
- # $date = timelocal( $sec, $min, $hour, $mday, $mon - 1, $year );
- $date = time_str2num($date);
- }
- }
- #TODO timelocal? 03-26 results in wrong timestamp
- # return PrintHash(
- # $date
- # ? %{ HOMESTATEtk_GetDaySchedule( $hash, $date, undef, $lang ) }
- # {events}
- # : $hash->{helper}{events},
- # 3
- # );
- return PrintHash(
- $date
- ? HOMESTATEtk_GetDaySchedule( $hash, $date, undef, $lang )
- : $hash->{'.events'},
- 3
- );
- }
- # return usage hint
- else {
- return $usage;
- }
- return undef;
- }
- sub HOMESTATEtk_Attr(@) {
- my ( $cmd, $name, $attribute, $value ) = @_;
- my $hash = $defs{$name};
- my $TYPE = $hash->{TYPE};
- my $security = ReadingsVal( $name, "security", "" );
- return
- "Device is currently $security and attributes cannot be changed at this state"
- unless ( !$init_done || $security =~ m/^unlocked|locked$/ );
- if ( $attribute eq "HomestateDevices" ) {
- return "Value for $attribute has invalid format"
- unless ( $cmd eq "del"
- || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
- delete $hash->{HOMESTATES};
- $hash->{HOMESTATES} = $value unless ( $cmd eq "del" );
- }
- elsif ( $attribute eq "FloorstateDevices" ) {
- return "Value for $attribute has invalid format"
- unless ( $cmd eq "del"
- || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
- delete $hash->{SECTIONSTATES};
- $hash->{SECTIONSTATES} = $value unless ( $cmd eq "del" );
- }
- elsif ( $attribute eq "RoomstateDevices" ) {
- return "Value for $attribute has invalid format"
- unless ( $cmd eq "del"
- || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
- delete $hash->{ROOMSTATES};
- $hash->{ROOMSTATES} = $value unless ( $cmd eq "del" );
- }
- elsif ( $attribute eq "ResidentsDevices" ) {
- return "Value for $attribute has invalid format"
- unless ( $cmd eq "del"
- || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
- delete $hash->{RESIDENTS};
- $hash->{RESIDENTS} = $value unless ( $cmd eq "del" );
- }
- elsif ( $attribute eq "HolidayDevices" ) {
- return "Value for $attribute has invalid format"
- unless ( $cmd eq "del"
- || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
- }
- elsif ( $attribute eq "DebugDate" ) {
- return
- "Invalid format for $attribute. Can be:\n"
- . "\nYYYY-MM-DD"
- . "\nYYYY-MM-DD HH:MM"
- . "\nYYYY-MM-DD HH:MM:SS"
- . "\nMM-DD"
- . "\nMM-DD HH:MM"
- . "\nMM-DD HH:MM:SS"
- unless ( $cmd eq "del"
- || $value =~
- m/^((?:\d{4}\-)?\d{2}-\d{2})(?: (\d{2}:\d{2}(?::\d{2})?))?$/ );
- }
- elsif ( !$init_done ) {
- return undef;
- }
- elsif ( $attribute eq "disable" ) {
- if ( $value and $value == 1 ) {
- $hash->{STATE} = "disabled";
- }
- elsif ( $cmd eq "del" or !$value ) {
- evalStateFormat($hash);
- }
- }
- elsif ( $attribute eq "Lang" ) {
- my $lang =
- $cmd eq "set"
- ? lc($value)
- : lc( AttrVal( "global", "language", "EN" ) );
- my $langUc = uc($lang);
- # for initial define, ensure fallback to EN
- $lang = "en"
- if ( $cmd eq "init" && $lang !~ /^en|de$/i );
- if ( $lang eq "de" ) {
- $attr{$name}{alias} = "Modus"
- if ( !defined( $attr{$name}{alias} )
- || $attr{$name}{alias} eq "Mode" );
- $attr{$name}{webCmd} = "mode_$langUc"
- if ( !defined( $attr{$name}{webCmd} )
- || $attr{$name}{webCmd} eq "mode" );
- if ( $TYPE eq "HOMESTATE" ) {
- $attr{$name}{group} = "Zuhause Status"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Home State" );
- }
- if ( $TYPE eq "SECTIONSTATE" ) {
- $attr{$name}{group} = "Bereichstatus"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Section State" );
- }
- if ( $TYPE eq "ROOMSTATE" ) {
- $attr{$name}{group} = "Raumstatus"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Room State" );
- }
- }
- elsif ( $lang eq "en" ) {
- $attr{$name}{alias} = "Mode"
- if ( !defined( $attr{$name}{alias} )
- || $attr{$name}{alias} eq "Modus" );
- $attr{$name}{webCmd} = "mode"
- if ( !defined( $attr{$name}{webCmd} )
- || $attr{$name}{webCmd} =~ /^mode_[A-Z]{2}$/ );
- if ( $TYPE eq "HOMESTATE" ) {
- $attr{$name}{group} = "Home State"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Zuhause Status" );
- }
- if ( $TYPE eq "SECTIONSTATE" ) {
- $attr{$name}{group} = "Section State"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Bereichstatus" );
- }
- if ( $TYPE eq "ROOMSTATE" ) {
- $attr{$name}{group} = "Room State"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Raumstatus" );
- }
- }
- else {
- return "Unsupported language $langUc";
- }
- $attr{$name}{$attribute} = $value if ( $cmd eq "set" );
- evalStateFormat($hash);
- }
- return undef;
- }
- sub HOMESTATEtk_Notify($$) {
- my ( $hash, $dev ) = @_;
- my $name = $hash->{NAME};
- my $TYPE = $hash->{TYPE};
- my $devName = $dev->{NAME};
- my $devType = GetType($devName);
- if ( $devName eq "global" ) {
- my $events = deviceEvents( $dev, 1 );
- return "" unless ($events);
- foreach ( @{$events} ) {
- next if ( $_ =~ m/^[A-Za-z\d_-]+:/ );
- # module and device initialization
- if ( $_ =~ m/^INITIALIZED|REREADCFG$/ ) {
- if ( !defined( &{'DoInitDev'} ) ) {
- if ( $_ eq "REREADCFG" ) {
- delete $modules{$devType}{READY};
- delete $modules{$devType}{INIT};
- }
- RESIDENTStk_DoInitDev(
- devspec2array("TYPE=$TYPE:FILTER=MOD_INIT=.+") );
- }
- }
- # if any of our monitored devices was modified,
- # recalculate monitoring status
- elsif ( $_ =~
- m/^(DEFINED|MODIFIED|RENAMED|DELETED)\s+([A-Za-z\d_-]+)$/ )
- {
- if ( defined( &{'DoInitDev'} ) ) {
- # DELETED would normally be handled by fhem.pl and imply
- # DoModuleTrigger instead of DoInitDev to update module
- # init state
- next if ( $_ =~ /^DELETED/ );
- DoInitDev($name);
- }
- else {
- # for DELETED, we normally would want to use
- # DoModuleTrigger() but we miss the deleted
- # device's TYPE at this state :-(
- RESIDENTStk_DoInitDev($name);
- }
- }
- # only process attribute events
- next
- unless ( $_ =~
- m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/
- );
- my $cmd = $1;
- my $d = $2;
- my $attr = $3;
- my $val = $4;
- my $type = GetType($d);
- # filter attributes to be processed
- next
- unless ( $attr =~ /[Dd]evices?$/
- || $attr eq "DebugDate" );
- # when own attributes were changed
- if ( $d eq $name ) {
- if ( defined( &{'DoInitDev'} ) ) {
- delete $hash->{NEXT_EVENT};
- RemoveInternalTimer($hash);
- InternalTimer( gettimeofday() + 0.5, "DoInitDev", $hash );
- }
- else {
- delete $hash->{NEXT_EVENT};
- RemoveInternalTimer($hash);
- InternalTimer( gettimeofday() + 0.5,
- "RESIDENTStk_DoInitDev", $hash );
- }
- return "";
- }
- }
- return "";
- }
- return "" if ( IsDisabled($name) or IsDisabled($devName) );
- # process events from RESIDENTS, ROOMMATE or GUEST devices
- # only when they hit HOMESTATE devices
- if ( $TYPE ne $devType
- && $devType =~
- m/^HOMESTATE|SECTIONSTATE|ROOMSTATE|RESIDENTS|ROOMMATE|GUEST$/ )
- {
- my $events = deviceEvents( $dev, 1 );
- return "" unless ($events);
- foreach my $event ( @{$events} ) {
- next unless ( defined($event) );
- # state changed
- if ( $event !~ /^[a-zA-Z\d._]+:/
- || $event =~ /^state:/
- || $event =~ /^presence:/
- || $event =~ /^mode:/
- || $event =~ /^security:/
- || $event =~ /^wayhome:/
- || $event =~ /^wakeup:/ )
- {
- if ( defined( &{'DoInitDev'} ) ) {
- DoInitDev($name);
- }
- else {
- RESIDENTStk_DoInitDev($name);
- }
- }
- }
- return "";
- }
- # process own events
- elsif ( $devName eq $name ) {
- my $events = deviceEvents( $dev, 1 );
- return "" unless ($events);
- foreach my $event ( @{$events} ) {
- next unless ( defined($event) );
- }
- return "";
- }
- return "";
- }
- sub HOMESTATEtk_GetIndexFromArray($$) {
- my ( $string, $array ) = @_;
- return undef unless ( ref($array) eq "ARRAY" );
- my ($index) = grep { $array->[$_] =~ /^$string$/i } ( 0 .. @$array - 1 );
- return defined $index ? $index : undef;
- }
- sub HOMESTATEtk_findHomestateSlaves($;$) {
- my ( $hash, $ret ) = @_;
- my @slaves;
- if ( $hash->{TYPE} eq "HOMESTATE" ) {
- my @SECTIONSTATES;
- foreach ( devspec2array("TYPE=SECTIONSTATE") ) {
- next
- unless (
- defined( $defs{$_}{SECTIONSTATES} )
- && grep { $hash->{NAME} eq $_ }
- split( /,/, $defs{$_}{SECTIONSTATES} )
- );
- push @SECTIONSTATES, $_;
- }
- if ( scalar @SECTIONSTATES ) {
- $hash->{SECTIONSTATES} = join( ",", @SECTIONSTATES );
- }
- elsif ( $hash->{SECTIONSTATES} ) {
- delete $hash->{SECTIONSTATES};
- }
- if ( $hash->{SECTIONSTATES} ) {
- $ret .= "," if ($ret);
- $ret .= $hash->{SECTIONSTATES};
- }
- }
- if ( $hash->{TYPE} eq "HOMESTATE" || $hash->{TYPE} eq "SECTIONSTATE" ) {
- my @ROOMSTATES;
- foreach ( devspec2array("TYPE=ROOMSTATE") ) {
- next
- unless (
- (
- defined( $defs{$_}{HOMESTATES} )
- && grep { $hash->{NAME} eq $_ }
- split( /,/, $defs{$_}{HOMESTATES} )
- )
- || (
- defined( $defs{$_}{SECTIONSTATES} )
- && grep { $hash->{NAME} eq $_ }
- split( /,/, $defs{$_}{SECTIONSTATES} )
- )
- );
- push @ROOMSTATES, $_;
- }
- if ( scalar @ROOMSTATES ) {
- $hash->{ROOMSTATES} = join( ",", @ROOMSTATES );
- }
- elsif ( $hash->{ROOMSTATES} ) {
- delete $hash->{ROOMSTATES};
- }
- if ( $hash->{ROOMSTATES} ) {
- $ret .= "," if ($ret);
- $ret .= $hash->{ROOMSTATES};
- }
- }
- if ( $hash->{RESIDENTS} ) {
- $ret .= "," if ($ret);
- $ret .= $hash->{RESIDENTS};
- }
- return HOMESTATEtk_findDummySlaves( $hash, $ret );
- }
- sub HOMESTATEtk_findDummySlaves($;$);
- sub HOMESTATEtk_findDummySlaves($;$) {
- my ( $hash, $ret ) = @_;
- $ret = "" unless ($ret);
- return $ret;
- }
- sub HOMESTATEtk_devStateIcon($) {
- my ($hash) = @_;
- $hash = $defs{$hash} if ( ref($hash) ne 'HASH' );
- return undef if ( !$hash );
- my $name = $hash->{NAME};
- my $lang =
- lc( AttrVal( $name, "Lang", AttrVal( "global", "language", "EN" ) ) );
- my $langUc = uc($lang);
- my @devStateIcon;
- # mode
- my $i = 0;
- foreach ( @{ $UConv::daytimes{en} } ) {
- push @devStateIcon, "$_:$UConv::daytimes{icons}[$i++]:toggle";
- }
- unless ( $lang eq "en" && defined( $UConv::daytimes{$lang} ) ) {
- $i = 0;
- foreach ( @{ $UConv::daytimes{$lang} } ) {
- push @devStateIcon, "$_:$UConv::daytimes{icons}[$i++]:toggle";
- }
- }
- # security
- $i = 0;
- foreach ( @{ $stateSecurity{en} } ) {
- push @devStateIcon, "$_:$stateSecurity{icons}[$i++]";
- }
- unless ( $lang eq "en" && defined( $UConv::daytimes{$lang} ) ) {
- $i = 0;
- foreach ( @{ $stateSecurity{$lang} } ) {
- push @devStateIcon, "$_:$stateSecurity{icons}[$i++]";
- }
- }
- return join( " ", @devStateIcon );
- }
- sub HOMESTATEtk_GetDaySchedule($;$$$$$) {
- my ( $hash, $time, $totalTemporalHours, $lang, @srParams ) = @_;
- my $name = $hash->{NAME};
- $lang = (
- $attr{global}{language}
- ? $attr{global}{language}
- : "EN"
- ) unless ($lang);
- return undef
- unless ( !$time || $time =~ /^\d{10}(?:\.\d+)?$/ );
- my $ret = UConv::GetDaytime( $time, $totalTemporalHours, $lang, @srParams );
- # consider user defined vacation days
- my $holidayDevs = AttrVal( $name, "HolidayDevices", "" );
- foreach my $holidayDev ( split( /,/, $holidayDevs ) ) {
- next
- unless ( IsDevice( $holidayDev, "holiday" )
- && AttrVal( "global", "holiday2we", "" ) ne $holidayDev );
- my $date = sprintf( "%02d-%02d", $ret->{monISO}, $ret->{mday} );
- my $tod = holiday_refresh( $holidayDev, $date );
- $date =
- sprintf( "%02d-%02d", $ret->{'-1'}{monISO}, $ret->{'-1'}{mday} );
- my $ytd = holiday_refresh( $holidayDev, $date );
- $date = sprintf( "%02d-%02d", $ret->{1}{monISO}, $ret->{1}{mday} );
- my $tom = holiday_refresh( $holidayDev, $date );
- if ( $tod ne "none" ) {
- $ret->{iswe} += 3;
- $ret->{isholiday} += 2;
- $ret->{day_desc} = $tod unless ( $ret->{isholiday} == 3 );
- $ret->{day_desc} .= ", $tod" if ( $ret->{isholiday} == 3 );
- }
- if ( $ytd ne "none" ) {
- $ret->{'-1'}{isholiday} += 2;
- $ret->{'-1'}{day_desc} = $ytd
- unless ( $ret->{'-1'}{isholiday} == 3 );
- $ret->{'-1'}{day_desc} .= ", $ytd"
- if ( $ret->{'-1'}{isholiday} == 3 );
- }
- if ( $tom ne "none" ) {
- $ret->{1}{isholiday} += 2;
- $ret->{1}{day_desc} = $tom;
- $ret->{1}{day_desc} = $tom unless ( $ret->{1}{isholiday} == 3 );
- $ret->{1}{day_desc} .= ", $tom"
- if ( $ret->{1}{isholiday} == 3 );
- }
- }
- return $ret;
- }
- sub HOMESTATEtk_UpdateReadings (@) {
- my ($hash) = @_;
- my $name = $hash->{NAME};
- my $TYPE = $hash->{TYPE};
- my $t = $hash->{'.t'};
- my $state = ReadingsVal( $name, "state", "" );
- my $security = ReadingsVal( $name, "security", "" );
- my $daytime = ReadingsVal( $name, "daytime", "" );
- my $mode = ReadingsVal( $name, "mode", "" );
- my $autoMode =
- HOMESTATEtk_GetIndexFromArray( ReadingsVal( $name, "autoMode", "on" ),
- $stateOnoff{en} );
- my $lang =
- lc( AttrVal( $name, "Lang", AttrVal( "global", "language", "EN" ) ) );
- my $langUc = uc($lang);
- # presence
- my $state_home = 0;
- my $state_gotosleep = 0;
- my $state_asleep = 0;
- my $state_awoken = 0;
- my $state_absent = 0;
- my $state_gone = 0;
- my $wayhome = 0;
- my $wayhomeDelayed = 0;
- my $wakeup = 0;
- foreach my $internal ( "RESIDENTS", "SECTIONSTATES", "ROOMSTATES" ) {
- next unless ( $hash->{$internal} );
- foreach my $presenceDev ( split( /,/, $hash->{$internal} ) ) {
- my $state = ReadingsVal( $presenceDev, "state", "gone" );
- $state_home++ if ( $state eq "home" );
- $state_gotosleep++ if ( $state eq "gotosleep" );
- $state_asleep++ if ( $state eq "asleep" );
- $state_awoken++ if ( $state eq "awoken" );
- $state_absent++ if ( $state eq "absent" );
- $state_gone++ if ( $state eq "gone" || $state eq "none" );
- my $wayhome = ReadingsVal( $presenceDev, "wayhome", 0 );
- $wayhome++ if ($wayhome);
- $wayhomeDelayed++ if ( $wayhome == 2 );
- my $wakeup = ReadingsVal( $presenceDev, "wakeup", 0 );
- $wakeup++ if ($wakeup);
- }
- }
- $state_home = 1
- unless ( $hash->{RESIDENTS}
- || $hash->{SECTIONSTATES}
- || $hash->{ROOMSTATES} );
- # autoMode
- if ( $autoMode && $mode ne $daytime ) {
- my $im = HOMESTATEtk_GetIndexFromArray( $mode, $UConv::daytimes{en} );
- my $id =
- HOMESTATEtk_GetIndexFromArray( $daytime, $UConv::daytimes{en} );
- if (
- $mode eq "" || (
- # follow daymode throughout the day until midnight
- ( $im < $id && $id != 6 )
- # first change after midnight
- || ( $im >= 4 && $id == 6 )
- # morning
- || ( $im == 6 && $id >= 0 && $id <= 3 )
- )
- )
- {
- readingsBulkUpdate( $hash, "lastMode", $mode ) if ( $mode ne "" );
- $mode = $daytime;
- readingsBulkUpdate( $hash, "mode", $mode );
- unless ( $lang eq "en" ) {
- my $modeL = ReadingsVal( $name, "mode_$langUc", "" );
- my $daytimeL = ReadingsVal( $name, "daytime_$langUc", "" );
- readingsBulkUpdate( $hash, "lastMode_$langUc", $modeL )
- if ( $modeL ne "" );
- readingsBulkUpdate( $hash, "mode_$langUc", $daytimeL )
- if ( $daytimeL ne "" );
- }
- }
- }
- #
- # security calculation
- #
- my $newsecurity;
- # unsecured
- if ( $state_home > 0 && $mode !~ /^night|midevening$/ ) {
- $newsecurity = "unlocked";
- }
- # locked
- elsif ($state_home > 0
- || $state_awoken > 0
- || $state_gotosleep > 0
- || $wakeup > 0 )
- {
- $newsecurity = "locked";
- }
- # night
- elsif ( $state_asleep > 0 ) {
- $newsecurity = "protected";
- }
- # secured
- elsif ( $state_absent > 0 || $wayhome > 0 ) {
- $newsecurity = "secured";
- }
- # extended
- else {
- $newsecurity = "guarded";
- }
- if ( $newsecurity ne $security ) {
- readingsBulkUpdate( $hash, "lastSecurity", $security )
- if ( $security ne "" );
- $security = $newsecurity;
- readingsBulkUpdate( $hash, "security", $security );
- unless ( $lang eq "en" ) {
- my $securityL = ReadingsVal( $name, "security_$langUc", "" );
- readingsBulkUpdate( $hash, "lastSecurity_$langUc", $securityL )
- if ( $securityL ne "" );
- $securityL =
- $stateSecurity{$lang}
- [ HOMESTATEtk_GetIndexFromArray( $security, $stateSecurity{en} )
- ];
- readingsBulkUpdate( $hash, "security_$langUc", $securityL );
- }
- }
- #
- # state calculation:
- # combine security and mode
- #
- my $newstate;
- my $statesrc;
- # mode
- if ( $security =~ m/^unlocked|locked/ ) {
- $newstate = $mode;
- $statesrc = "mode";
- }
- # security
- else {
- $newstate = $security;
- $statesrc = "security";
- }
- if ( $newstate ne $state ) {
- readingsBulkUpdate( $hash, "lastState", $state ) if ( $state ne "" );
- $state = $newstate;
- readingsBulkUpdate( $hash, "state", $state );
- unless ( $lang eq "en" ) {
- my $stateL = ReadingsVal( $name, "state_$langUc", "" );
- readingsBulkUpdate( $hash, "lastState_$langUc", $stateL )
- if ( $stateL ne "" );
- $stateL = ReadingsVal( $name, $statesrc . "_$langUc", "" );
- readingsBulkUpdate( $hash, "state_$langUc", $stateL );
- }
- }
- }
- 1;
|