diff --git a/fhem/FHEM/98_DOIF.pm b/fhem/FHEM/98_DOIF.pm new file mode 100644 index 000000000..42a7828d1 --- /dev/null +++ b/fhem/FHEM/98_DOIF.pm @@ -0,0 +1,1214 @@ +############################################## +# 98_DOIF +# +# This file is part of fhem. +# +# Fhem 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 +# (at your option) any later version. +# +# Fhem 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. +# +# You should have received a copy of the GNU General Public License +# along with fhem. If not, see . +# +# $Id$ +############################################################################## + + +package main; +use strict; +use warnings; + + + +########################## +sub +DOIF_Initialize($) +{ + my ($hash) = @_; + $hash->{DefFn} = "DOIF_Define"; + #$hash->{SetFn} = "DOIF_Set"; + $hash->{UndefFn} = "DOIF_Undef"; + $hash->{AttrFn} = "DOIF_Attr"; + $hash->{NotifyFn} = "DOIF_Notify"; + $hash->{AttrList} = "disable:0,1 loglevel:0,1,2,3,4,5,6 wait do:always cmdState state"; +} + + + +sub +GetBlockDoIf ($$) +{ + my ($cmd,$match) = @_; + my $count=0; + my $first_pos=0; + my $last_pos=0; + my $err=""; + while($cmd =~ /$match/g) { + if (substr($cmd,pos($cmd)-1,1) eq substr($match,2,1)) { + $count++; + $first_pos=pos($cmd) if ($count == 1); + } elsif (substr($cmd,pos($cmd)-1,1) eq substr($match,4,1)) { + $count--; + } + if ($count < 0) + { + $err="right bracket without left bracket"; + return ("",substr($cmd,pos($cmd)-1),$err,""); + } + + if ($count == 0) { + $last_pos=pos($cmd); + last; + } + } + if ($count > 0) { + $err="no right bracket"; + return ("",substr($cmd,$first_pos-1),$err); + } + if ($first_pos) { + return (substr($cmd,0,$first_pos-1),substr($cmd,$first_pos,$last_pos-$first_pos-1),"",substr($cmd,$last_pos)); + } else { + return ($cmd,"","",""); + } +} + +sub +InternalDoIf($$$) +{ + my ($name,$internal,$regExp)=@_; + my $r=""; + my $element; + $r=$defs{$name}{$internal}; + if ($regExp) { + $element = ($r =~ /$regExp/) ? $1 : ""; + } else { + $element=$r; + } + return($element); + +} + +sub +ReadingValDoIf($$$) +{ + my ($name,$reading,$regExp)=@_; + my $r=""; + my $element; + $r=$defs{$name}{READINGS}{$reading}{VAL}; + if ($regExp) { + $element = ($r =~ /$regExp/) ? $1 : ""; + } else { + $element=$r; + } + return($element); +} + +sub +EvalAllDoIf($) +{ + my ($tailBlock)= @_; + my $eval=""; + my $beginning; + my $err; + my $cmd=""; + my $ret=""; + + while ($tailBlock ne "") { + ($beginning,$eval,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\{\}]'); + return ($eval,$err) if ($err); + if ($eval) { + if (substr($eval,0,1) eq "(") { + my $ret = eval $eval; + return($eval." ",$@) if ($@); + $eval=$ret; + } else { + $eval="{".$eval."}"; + } + } + $cmd.=$beginning.$eval; + } + return ($cmd,""); +} + +sub ReplaceReadingDoIf($) +{ + my ($element) = @_; + my $beginning; + my $tailBlock; + my $err; + my $regExp=""; + my ($name,$reading,$format)=split(":",$element); + my $internal=""; + if ($name) { + #return ($name,"unknown Device") if(!$defs{$name}); + if ($reading) { + $internal = substr($reading,1) if (substr($reading,0,1) eq "\&"); + if ($format) { + if ($format eq "d") { + $regExp = '(-?\d+(\.\d+)?)'; + } elsif (substr($format,0,1) eq '[') { + ($beginning,$regExp,$err,$tailBlock)=GetBlockDoIf($format,'[\[\]]'); + return ($regExp,$err) if ($err); + return ($regExp,"no round brackets in regular expression") if ($regExp !~ /.*\(.*\)/); + } else { + return($format,"unknown expression format"); + } + } + if ($internal) { + return("InternalDoIf('$name','$internal','$regExp')","",$name,undef,$internal); + } else { + return("ReadingValDoIf('$name','$reading','$regExp')","",$name,$reading,undef); + } + } else { + return("InternalDoIf('$name','STATE','$regExp')","",$name,undef,'STATE'); + } + } +} + +sub AddItemDoIf($$) +{ + my ($items,$item)=@_; + if (!$items) { + $items=" $item "; + } elsif ($items !~ / $item /) { + $items.="$item "; + } + return $items; +} + +sub ReplaceAllReadingsDoIf($$$$) +{ + my ($hash,$tailBlock,$condition,$eval)= @_; + my $block=""; + my $beginning; + my $err; + my $cmd=""; + my $ret=""; + my $device=""; + my @timerarray; + my $nr; + my $timer=""; + my $event=0; + my $definition=$tailBlock; + my $reading; + my $internal; + while ($tailBlock ne "") { + ($beginning,$block,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\[\]]'); + return ($block,$err) if ($err); + if ($block ne "") { + if ($condition >= 0) { + ($timer,$err)=DOIF_CheckTimers($hash,$block,$condition,\@timerarray); + return($timer,$err) if ($err); + if ($timer) { + $cmd.=$beginning.$timer; + $event=1; + next; + } + } + if ($block =~ /:/ or ($block =~ /[a-z]/i and $block =~ /^[a-z0-9._]*$/i)) + { + ($block,$err,$device,$reading,$internal)=ReplaceReadingDoIf($block); + return ($block,$err) if ($err); + if ($eval) { + return ($block,"reading does not exist: [$device:$reading]") if (defined ($reading) and !$defs{$device}{READINGS}{$reading}); + return ($block,"internal does not exist: [$device:$internal]") if (defined ($internal) and !$defs{$device}{$internal}); + my $ret = eval $block; + return($block." ",$@) if ($@); + $block=$ret; + } + if ($condition >= 0) { + $hash->{devices}{$condition} = AddItemDoIf($hash->{devices}{$condition},$device); + $hash->{devices}{all} = AddItemDoIf($hash->{devices}{all},$device); + $hash->{readings}{$condition} = AddItemDoIf($hash->{readings}{$condition},"$device:$reading") if (defined ($reading)); + $hash->{internals}{$condition} = AddItemDoIf($hash->{internals}{$condition},"$device:$internal") if (defined ($internal)); + $hash->{readings}{all} = AddItemDoIf($hash->{readings}{all},"$device:$reading") if (defined ($reading)); + $hash->{internals}{all} = AddItemDoIf($hash->{internals}{all},"$device:$internal") if (defined ($internal)); + $event=1; + } elsif ($condition == -2) { + $hash->{state}{device} = AddItemDoIf($hash->{state}{device},$device) if ($device ne $hash->{NAME}); + } + } else { + $block="[".$block."]"; + } + } + $cmd.=$beginning.$block; + } + return ($definition,"no state, reading or time in condition") if ($condition >=0 and $event == 0); + return ($cmd,""); +} + +sub +ParseCommandsDoIf($$$) +{ + my($hash,$tailBlock,$eval) = @_; + my $pn=$hash->{NAME}; + my $currentBlock=""; + my $beginning=""; + my $err=""; + my $pos=0; + my $last_error=""; + my $ifcmd; + my $ret; + + while ($tailBlock ne "") { + if ($tailBlock=~ /^\s*\{/) { # perl block + ($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\{\}]'); + return ($currentBlock,$err) if ($err); + $currentBlock="{".$currentBlock."}"; + } elsif ($tailBlock =~ /^\s*IF/) { + my $ifcmd=""; + ($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\(\)]'); #condition + return ($currentBlock,$err) if ($err); + $ifcmd.=$beginning."(".$currentBlock.")"; + ($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\(\)]'); #if case + return ($currentBlock,$err) if ($err); + $ifcmd.=$beginning."(".$currentBlock.")"; + if ($tailBlock =~ /^\s*ELSE/) { + ($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\(\)]'); #else case + return ($currentBlock,$err) if ($err); + $ifcmd.=$beginning."(".$currentBlock.")"; + } + $currentBlock=$ifcmd; + } else { + if ($tailBlock =~ /^\s*\(/) { # remove bracket + ($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\(\)]'); + return ($currentBlock,$err) if ($err); + #$tailBlock=substr($tailBlock,pos($tailBlock)) if ($tailBlock =~ /^\s*,/g); + } elsif ($tailBlock =~ /,/g) { + $pos=pos($tailBlock)-1; + $currentBlock=substr($tailBlock,0,$pos); + $tailBlock=substr($tailBlock,$pos+1); + } else { + $currentBlock=$tailBlock; + $tailBlock=""; + } + if ($currentBlock ne "") { + ($currentBlock,$err)=ReplaceAllReadingsDoIf($hash,$currentBlock,-1,$eval); + return ($currentBlock,$err) if ($err); + ($currentBlock,$err)=EvalAllDoIf($currentBlock); + return ($currentBlock,$err) if ($err); + } + } + if ($eval) { + if ($ret = AnalyzeCommandChain(undef,$currentBlock)) { + Log3 $pn,2 , "$pn: $currentBlock: $ret"; + $last_error.="$currentBlock: $ret "; + } + } + $tailBlock=substr($tailBlock,pos($tailBlock)) if ($tailBlock =~ /^\s*,/g); + } + return("",$last_error); +} + +sub +DOIF_CheckTimers($$$$) +{ + my $i=0; + my @nrs; + my $nr; + my $days=""; + my $err; + my ($hash,$block,$condition,$timerarray)=@_; + #if ($block =~ /^(([0-2][0-9](:[0-5][0-9]){1,2})|(\{.*\}))(-([0-2][0-9](:[0-5][0-9]){1,2})|-({.*})|$)/) { + if ($block =~ /^((\{.*\})|([0-2][0-9](:[0-5][0-9]){1,2}))(\|[0-8]+$|-([0-2][0-9](:[0-5][0-9]){1,2})|-({.*})|$)(\|[0-8]+$|$)/) { + my ($timer,$days)=split(/\|/,$block); + foreach my $time (split(/-/,$timer)) { + $time .=":00" if ($time =~ m/^[0-2][0-9]:[0-5][0-9]$/); + $nr=$hash->{helper}{last_timer}; + $nrs[$i]=$nr; + $i++; + $hash->{timer}{$nr}=0; + $hash->{time}{$nr}=$time; + $hash->{timeCond}{$nr}=$condition; + $hash->{days}{$nr}=$days if ($days); + ${$timerarray}[$nr]={hash=>$hash,nr=>$nr}; + $err=(DOIF_SetTimer("DOIF_TimerTrigger",\${$timerarray}[$nr])); + return($hash->{time}{$nr},$err) if ($err); + $hash->{timers}{$condition}.=" $nr "; + $hash->{timerfunc}{$nr}=\${$timerarray}[$nr]; + $nr++; + $hash->{helper}{last_timer}=$nr; + } + $days = "" if (!$days); + if ($i == 2) { + $block='DOIF_time($hash->{realtime}{'.$nrs[0].'},$hash->{realtime}{'.$nrs[1].'},$wday,$hms,"'.$days.'")'; + } else { + $block='DOIF_time_once($hash->{timer}{'.$nrs[0].'},$wday,"'.$days.'")'; + #$block=' $hash->{timer}{'.$nrs[0].'} '; + } + return ($block,""); + } + return("",""); +} + +sub +DOIF_time($$$$$) +{ + my $ret=0; + my ($begin,$end,$wday,$hms,$days)=@_; + my $we=DOIF_we($wday); + if ($end gt $begin) { + if ($hms ge $begin and $hms lt $end) { + $ret=1; + } + } else { + if ($hms ge $begin) { + $ret=1; + } elsif ($hms lt $end) { + $wday=1 if ($wday-- == -1); + $we=DOIF_we($wday); + $ret=1; + } + } + if ($ret == 1) { + return 1 if (!$days or $days =~ /$wday/ or ($days =~ /7/ and $we) or ($days =~ /8/ and !$we)); + } + return 0; +} + +sub +DOIF_time_once($$$) +{ + my $ret; + my ($flag,$wday,$days)=@_; + my $we=DOIF_we($wday); + if ($flag) { + return 1 if (!$days or $days =~ /$wday/ or ($days =~ /7/ and $we) or ($days =~ /8/ and !$we)); + } + return 0; +} + +############################ +sub +DOIF_SetState($$$$) +{ + my ($hash,$nr,$event,$last_error)=@_; + my $pn=$hash->{NAME}; + my $cmdNr=""; + my $cmd=""; + my $err=""; + my $attr=AttrVal($hash->{NAME},"cmdState",""); + my $state=AttrVal($hash->{NAME},"state",""); + my @cmdState=split(/\|/,$attr); + $nr=ReadingsVal($pn,"cmd_nr",0)-1 if (!$event); + if ($nr!=-1) { + $cmdNr=$nr+1; + if ($attr) { + $cmd=$cmdState[$nr] if (defined ($cmdState[$nr])); + } else { + $cmd="cmd_$cmdNr"; + } + } + readingsBeginUpdate ($hash); + if ($event) { + readingsBulkUpdate($hash,"cmd_nr",$cmdNr); + readingsBulkUpdate($hash,"cmd_event",$event); + if ($last_error) { + readingsBulkUpdate($hash,"error",$last_error); + } else { + delete ($defs{$hash->{NAME}}{READINGS}{error}); + } + } + if ($state) { + my $stateblock='\['.$pn.'\]'; + $state =~ s/$stateblock/$cmd/g; + ($state,$err)=ReplaceAllReadingsDoIf($hash,$state,-1,1); + if ($err) { + Log3 $pn,2 , "$pn: error in state: $err" if ($err); + $state=$err; + } else { + ($state,$err)=EvalAllDoIf($state); + if ($err) { + Log3 $pn,2 , "$pn: error in state: $err" if ($err); + $state=$err; + } + } + } else { + $state=$cmd; + } + readingsBulkUpdate($hash, "state", $state); + readingsEndUpdate ($hash, 1); +} + +sub +DOIF_we($) { + my ($wday)=@_; + my $we = (($wday==0 || $wday==6) ? 1 : 0); + if(!$we) { + my $h2we = $attr{global}{holiday2we}; + $we = 1 if($h2we && $value{$h2we} && $value{$h2we} ne "none"); + } + return $we; +} + +sub +DOIF_CheckCond($$) +{ + my ($hash,$condition) = @_; + my $err=""; + my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime; + my $hms = sprintf("%02d:%02d:%02d", $hour, $min, $sec); + my $hm = sprintf("%02d:%02d", $hour, $min); + my $device; + my $reading; + my $internal; + my $we=DOIF_we($wday); + + $month++; + $year+=1900; + if (defined ($hash->{readings}{$condition})) { + foreach my $devReading (split(/ /,$hash->{readings}{$condition})) { + ($device,$reading)=(split(":",$devReading)); + return (0,"reading does not exist: [$device:$reading]") if ($devReading and !$defs{$device}{READINGS}{$reading}); + } + } + if (defined ($hash->{internals}{$condition})) { + foreach my $devInternal (split(/ /,$hash->{internals}{$condition})) { + ($device,$internal)=(split(":",$devInternal)); + return (0,"internal does not exist: [$device:$internal]") if ($devInternal and !$defs{$device}{$internal}); + } + } + my $ret = eval $hash->{condition}{$condition}; + if($@){ + $err = "perl error in condition: $hash->{condition}{$condition}: $@"; + $ret = 0; + } + return ($ret,$err); +} + +sub +DOIF_cmd ($$$) +{ + my ($hash,$nr,$event)=@_; + my $pn = $hash->{NAME}; + my $ret; + my $cmd; + my $err=""; + if ($hash->{do}{$nr}) { + ($cmd,$err)=ParseCommandsDoIf($hash,$hash->{do}{$nr},1); + } + DOIF_SetState ($hash,$nr,$event,$err); + return undef; +} + + +sub +DOIF_Trigger ($$$) +{ + my ($hash,$device,$timerNr)= @_; + my $ret; + my $err; + my $doelse=0; + my $event; + my $pn=$hash->{NAME}; + my $max_cond=keys %{$hash->{condition}}; + my $last_cond=ReadingsVal($pn,"cmd_nr",0)-1; + for (my $i=0; $i<$max_cond;$i++) { + if ($device eq "") {# timer + next if (!defined ($hash->{timers}{$i})); + next if ($hash->{timers}{$i} !~ / $timerNr /); + $event="timer_".($timerNr+1); + } else { #event + next if (!defined ($hash->{devices}{$i})); + next if ($hash->{devices}{$i} !~ / $device /); + $event="$device"; + } + if (($ret,$err)=DOIF_CheckCond($hash,$i)) { + if ($err) { + Log3 $hash->{Name},2,"$hash->{NAME}: $err"; + readingsSingleUpdate ($hash, "error", $err,1); + return undef; + } + if ($ret) { + if (DOIF_SetSleepTimer($hash,$last_cond,$i,$device,$timerNr)) { + DOIF_cmd ($hash,$i,$event); + return 1; + } else { + return undef; + } + } else { + $doelse = 1; + } + } + } + if ($doelse) { #DOELSE + if (defined ($hash->{do}{$max_cond})) { #DOELSE does exist + if (DOIF_SetSleepTimer($hash,$last_cond,$max_cond,$device,$timerNr)) { + DOIF_cmd ($hash,$max_cond,$event) ; + return 1; + } + } + elsif ($max_cond == 1) { + if (DOIF_SetSleepTimer($hash,$last_cond,$max_cond,$device,$timerNr)) { + DOIF_SetState($hash,$max_cond,$event,""); + return 1; + } + } + } + return undef; +} + +sub +DOIF_Notify($$) +{ + my ($hash, $dev) = @_; + my $pn = $hash->{NAME}; + return "" if($attr{$pn} && $attr{$pn}{disable}); + return "" if (!$hash->{devices}{all} and !$hash->{state}{device}) ; + return "" if (!$dev->{NAME}); + my $device; + my $reading; + my $internal; + my $ret; + + if (($hash->{devices}{all}) and $hash->{devices}{all} =~ / $dev->{NAME} /) { + if ($hash->{readings}{all}) { + foreach my $item (split(/ /,$hash->{readings}{all})) { + ($device,$reading)=(split(":",$item)); + readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_".$reading,$defs{$device}{READINGS}{$reading}{VAL},0) if ($item and $device eq $dev->{NAME} and $defs{$device}{READINGS}{$reading}); + } + } + if ($hash->{internals}{all}) { + foreach my $item (split(/ /,$hash->{internals}{all})) { + ($device,$internal)=(split(":",$item)); + readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_".$internal,$defs{$device}{$internal},0) if ($item and $device eq $dev->{NAME} and $defs{$device}{$internal}); + } + } + $ret=DOIF_Trigger($hash,$dev->{NAME},-1); + } + if (($hash->{state}{device}) and $hash->{state}{device} =~ / $dev->{NAME} / and !$ret) { + DOIF_SetState($hash,"","",""); + } + return undef; +} + +sub +DOIF_TimerTrigger ($) +{ +my ($timer)=@_; + my $nr=${$timer}->{nr}; + my $hash=${$timer}->{hash}; + my $ret; + if (!AttrVal($hash->{NAME},"disable","")) {$hash->{timer}{$nr}=1; + $ret=DOIF_Trigger ($hash,"",$nr); + $hash->{timer}{$nr}=0; + } + DOIF_SetTimer("DOIF_TimerTrigger",$timer); + return($ret); +} + +sub +DOIF_SetTimer($$) +{ + my ($func, $timer) = @_; + my $nr=${$timer}->{nr}; + my $hash=${$timer}->{hash}; + my $timeStr=$hash->{time}{$nr}; + my $cond=$hash->{timeCond}{$nr}; + my ($err, $h, $m, $s, $fn) = GetTimeSpec($timeStr); + return $err if($err); + my $second = $h*3600+$m*60+$s; + my $now = time(); + my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now); + my $isdst_now=$isdst; + my $sec_today = $hour*3600+$min*60+$sec; + my $midnight = $now-$sec_today; + my $next_time = $midnight+$second; + $next_time+=86400 if ($sec_today>=$second); + ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($next_time); + if ($isdst_now != $isdst) { + if ($isdst_now == 1) { + $next_time+=3600 if ($isdst == 0); + } else { + $next_time-=3600 if ($isdst == 1); + } + } + my $next_time_str=strftime("%d.%m.%Y %H:%M:%S",localtime($next_time)); + $next_time_str.="\|".$hash->{days}{$nr} if ($hash->{days}{$nr}); + readingsSingleUpdate ($hash,"timer_".($nr+1)."_c".($cond+1),$next_time_str,0); + $hash->{realtime}{$nr}=strftime("%H:%M:%S",localtime($next_time)); + RemoveInternalTimer($timer); + InternalTimer($next_time, $func, $timer, 0); + return undef; +} + +sub +DOIF_SetSleepTimer($$$$$) +{ + my ($hash,$last_cond,$nr,$device,$timerNr)=@_; + my $pn = $hash->{NAME}; + return 1 if ($timerNr == -2); #Sleeptrigger + if ($hash->{helper}{sleeptimer} != -1 and $hash->{helper}{sleeptimer} != $nr) { + RemoveInternalTimer($hash); + #delete ($defs{$hash->{NAME}}{READINGS}{wait_timer}); + readingsSingleUpdate ($hash, "wait_timer", "no timer",1); + $hash->{helper}{sleeptimer}=-1; + } + + if ($timerNr >= 0) {#Timer + if ($last_cond != $nr or AttrVal($pn,"do","") eq "always") { + return 1; + } else { + return 0; + } + } + if ($hash->{helper}{sleeptimer} == -1 and ($last_cond != $nr or AttrVal($pn,"do","") eq "always")) { + my @sleeptimer=split(/:/,AttrVal($pn,"wait","")); + if ($sleeptimer[$nr]) { + my $next_time = time()+$sleeptimer[$nr]; + $hash->{helper}{sleeptimer}=$nr; + $hash->{helper}{sleepdevice}=$device; + my $cmd_nr=$nr+1; + readingsSingleUpdate ($hash,"wait_timer",strftime("%d.%m.%Y %H:%M:%S cmd_$cmd_nr $device",localtime($next_time)),1); + InternalTimer($next_time, "DOIF_SleepTrigger",$hash, 0); + return 0; + } else { + return 1; + } + } else { + return 0; + } +} + +sub +DOIF_SleepTrigger ($) +{ + my ($hash)=@_; + $hash->{helper}{sleeptimer}=-1; + if (!AttrVal($hash->{NAME},"disable","")) { + DOIF_Trigger($hash,$hash->{helper}{sleepdevice},-2); + } + #delete ($defs{$hash->{NAME}}{READINGS}{wait_timer}); + readingsSingleUpdate ($hash, "wait_timer", "no timer",1); + return undef; +} + +############################# +sub +CmdDoIf($$) +{ + my ($hash, $tail) = @_; + my $cond=""; + my $err=""; + my $if_cmd=""; + my $if_cmd_ori=""; + my $else_cmd=""; + my $else_cmd_ori=""; + my $tailBlock; + my $eval=""; + my $beginning; + my $i=0; + my $last_do; + + if (!$tail) { + $tail=""; + } else { + $tail =~ s/\n//g; + } + + if (defined $hash->{helper}) #def modify + { + RemoveInternalTimer($hash); + my $max_timer=keys %{$hash->{timerfunc}}; + for (my $i=0; $i<$max_timer;$i++) + { + RemoveInternalTimer ($hash->{timerfunc}{$i}); + } + delete ($hash->{helper}); + delete ($hash->{condition}); + delete ($hash->{do}); + delete ($hash->{devices}); + delete ($hash->{time}); + delete ($hash->{timer}); + delete ($hash->{timers}); + delete ($hash->{timeCond}); + delete ($hash->{realtime}); + delete ($hash->{days}); + delete ($hash->{readings}); + delete ($hash->{internals}); + delete ($defs{$hash->{NAME}}{READINGS}); + readingsSingleUpdate ($hash,"state","initialized",1); + } + #$hash->{STATE} = 'initialized'; + $hash->{helper}{last_timer}=0; + + while ($tail ne "") { + return($tail, "no left bracket of condition") if ($tail !~ /^ *\(/); + #condition + ($beginning,$cond,$err,$tail)=GetBlockDoIf($tail,'[\(\)]'); + return ($cond,$err) if ($err); + ($cond,$err)=ReplaceAllReadingsDoIf($hash,$cond,$i,0); + return ($cond,$err) if ($err); + return ($tail,"no condition") if ($cond eq ""); + $hash->{condition}{$i}=$cond; + #DOIF + $if_cmd_ori=""; + if ($tail =~ /^\s*\(/) { + ($beginning,$if_cmd_ori,$err,$tail)=GetBlockDoIf($tail,'[\(\)]'); + return ($if_cmd_ori,$err) if ($err); + ($if_cmd,$err)=ParseCommandsDoIf($hash,$if_cmd_ori,0); + return ($if_cmd,$err) if ($err); + #return ($tail,"no commands") if ($if_cmd eq ""); + } + $hash->{do}{$i}=$if_cmd_ori; + $last_do=$i; + if (length($tail)) { + $tail =~ /^\s*DOELSEIF/g; + if (pos($tail)) { + $tail=substr($tail,pos($tail)); + if (!length($tail)) { + return ($tail,"no DOELSEIF block"); + } + } else { + last if ($tail =~ /^\s*DOELSE/); + return ($tail,"expected DOELSEIF or DOELSE"); + } + } + $i++; + } + #DOELSE + if (length($tail)) { + $tail =~ /^\s*DOELSE/g; + if (pos($tail)) { + $tail=substr($tail,pos($tail)); + } else { + return ($tail,"expected DOELSE"); + } + if ($tail =~ /^\s*\(/) { + ($beginning,$else_cmd_ori,$err,$tail)=GetBlockDoIf($tail,'[\(\)]'); + return ($else_cmd_ori,$err) if ($err); + ($else_cmd,$err)=ParseCommandsDoIf($hash,$else_cmd_ori,0); + return ($else_cmd,$err) if ($err); + } + $hash->{do}{$last_do+1}=$else_cmd_ori; + } + $hash->{helper}{sleeptimer}=-1; + return("","") +} + +sub +DOIF_Define($$$) +{ + my ($hash, $def) = @_; + my ($name, $type, $cmd) = split(/[\s]+/, $def, 3); + my ($msg,$err)=CmdDoIf($hash,$cmd); + if ($err ne "") { + $msg=$cmd if (!$msg); + my $errmsg="$name $type: $err: $msg"; + return $errmsg; + } else { + return undef; + } +} + +################################# + +sub +DOIF_Attr(@) +{ + my @a = @_; + my $hash = $defs{$a[1]}; + if($a[0] eq "set" && $a[2] eq "disable") + { + if($a[3] eq "0") { + readingsSingleUpdate ($hash,"state","initialized",1); + delete ($defs{$hash->{NAME}}{READINGS}{cmd_nr}); + delete ($defs{$hash->{NAME}}{READINGS}{cmd_event}); + } elsif($a[3] eq "1") { + readingsSingleUpdate ($hash,"state","disabled",1); + } + } elsif($a[0] eq "del" && $a[2] eq "disable") { + readingsSingleUpdate ($hash,"state","initialized",1); + delete ($defs{$hash->{NAME}}{READINGS}{cmd_nr}); + delete ($defs{$hash->{NAME}}{READINGS}{cmd_event}); + } elsif($a[0] eq "set" && $a[2] eq "state") { + delete ($hash->{state}{device}); + my ($block,$err)=ReplaceAllReadingsDoIf($hash,$a[3],-2,0); + return $err if ($err); + } elsif($a[0] eq "set" && $a[2] eq "wait") { + RemoveInternalTimer($hash); + #delete ($defs{$hash->{NAME}}{READINGS}{wait_timer}); + readingsSingleUpdate ($hash, "wait_timer", "no timer",1); + $hash->{helper}{sleeptimer}=-1; + } + return undef; +} + +sub +DOIF_Undef +{ + my ($hash, $name) = @_; + $hash->{DELETED} = 1; + RemoveInternalTimer($hash); + my $max_timer=keys %{$hash->{timerfunc}}; + for (my $i=0; $i<$max_timer;$i++) + { + RemoveInternalTimer ($hash->{timerfunc}{$i}); + } + return undef; +} + + + +sub +DOIF_Set($@) +{ + my ($hash, @a) = @_; + my $pn = $hash->{NAME}; + my $ret=""; + return $ret; +} + + +1; + +=pod +=begin html + + +

DOIF

+ +=end html +=begin html_DE + + +

DOIF

+ +=end html_DE +=cut \ No newline at end of file