diff --git a/fhem/FHEM/10_IT.pm b/fhem/FHEM/10_IT.pm new file mode 100644 index 000000000..65b7b83f2 --- /dev/null +++ b/fhem/FHEM/10_IT.pm @@ -0,0 +1,242 @@ +###################################################### +# InterTechno Switch Manager as FHM-Module +# +# (c) Olaf Droegehorn / DHS-Computertechnik GmbH +# +# Published under GNU GPL License +######################################################package main; + +use strict; +use warnings; + + +my %codes = ( + "XMIToff" => "off", + "XMITon" => "on", + "XMITdimup" => "dimup", + "XMITdimdown" => "dimdown", + "99" => "on-till", + +); + +my %it_c2b; + +my $it_simple ="off on"; +my %models = ( + itremote => 'sender', + itswitch => 'simple', + itdimmer => 'dimmer', +); + +sub +IT_Initialize($) +{ + my ($hash) = @_; + + foreach my $k (keys %codes) { + $it_c2b{$codes{$k}} = $k; + } + +# $hash->{Match} = ""; + $hash->{SetFn} = "IT_Set"; + $hash->{StateFn} = "IT_SetState"; + $hash->{DefFn} = "IT_Define"; + $hash->{UndefFn} = "IT_Undef"; +# $hash->{ParseFn} = "IT_Parse"; + $hash->{AttrList} = "IODev switch_rfmode:1,0 do_not_notify:1,0 ignore:0,1 dummy:1,0 model;itremote,itswitch,itdimmer loglevel:0,1,2,3,4,5,6"; + +} + +##################################### +sub +IT_SetState($$$$) +{ + my ($hash, $tim, $vt, $val) = @_; + + $val = $1 if($val =~ m/^(.*) \d+$/); + return "Undefined value $val" if(!defined($it_c2b{$val})); + return undef; +} + +############################# +sub +IT_Do_On_Till($@) +{ + my ($hash, @a) = @_; + return "Timespec (HH:MM[:SS]) needed for the on-till command" if(@a != 3); + + my ($err, $hr, $min, $sec, $fn) = GetTimeSpec($a[2]); + return $err if($err); + + my @lt = localtime; + my $hms_till = sprintf("%02d:%02d:%02d", $hr, $min, $sec); + my $hms_now = sprintf("%02d:%02d:%02d", $lt[2], $lt[1], $lt[0]); + if($hms_now ge $hms_till) { + Log 4, "on-till: won't switch as now ($hms_now) is later than $hms_till"; + return ""; + } + + my @b = ($a[0], "on"); + IT_Set($hash, @b); + my $tname = $hash->{NAME} . "_till"; + CommandDelete(undef, $tname) if($defs{$tname}); + CommandDefine(undef, "$tname at $hms_till set $a[0] off"); + +} + +################################### +sub +IT_Set($@) +{ + my ($hash, @a) = @_; + my $ret = undef; + my $na = int(@a); + + return "no set value specified" if($na < 2 || $na > 3); + + my $c = $it_c2b{$a[1]}; + if(!defined($c)) { + + # Model specific set arguments + if(defined($attr{$a[0]}) && defined($attr{$a[0]}{"model"})) { + my $mt = $models{$attr{$a[0]}{"model"}}; + return "Unknown argument $a[1], choose one of " + if($mt && $mt eq "sender"); + return "Unknown argument $a[1], choose one of $it_simple" + if($mt && $mt eq "simple"); + } + return "Unknown argument $a[1], choose one of " . + join(" ", sort keys %it_c2b); + + } + + return IT_Do_On_Till($hash, @a) if($a[1] eq "on-till"); + + return "Bad time spec" if($na == 3 && $a[2] !~ m/^\d*\.?\d+$/); + + my $v = join(" ", @a); + + my $message = "is".uc($hash->{XMIT}.$hash->{$c}); + my $io = $hash->{IODev}; + + ## Do we need to change RFMode to SlowRF?? + if(defined($attr{$a[0]}) && defined($attr{$a[0]}{"switch_rfmode"})) { + if ($attr{$a[0]}{"switch_rfmode"} eq "1") { # do we need to change RFMode of IODev + my $ret = CallFn($io->{NAME}, "AttrFn", "set", ($io->{NAME}, "rfmode", "SlowRF")); + } + } + + ## Log that we are going to switch InterTechno + Log GetLogLevel($a[0],2), "IT set $v"; + (undef, $v) = split(" ", $v, 2); # Not interested in the name... + + ## Send Message to IODev and wait for correct answer + my $msg = CallFn($io->{NAME}, "GetFn", $io, (" ", "raw", $message)); + if ($msg =~ m/raw => $message/) { + Log 4, "Answer from $io->{NAME}: $msg"; + } else { + Log 2, "IT IODev device didn't answer is command correctly: $msg"; + } + + ## Do we need to change RFMode back to HomeMatic?? + if(defined($attr{$a[0]}) && defined($attr{$a[0]}{"switch_rfmode"})) { + if ($attr{$a[0]}{"switch_rfmode"} eq "1") { # do we need to change RFMode of IODev + my $ret = CallFn($io->{NAME}, "AttrFn", "set", ($io->{NAME}, "rfmode", "HomeMatic")); + } + } + + + ########################## + # Look for all devices with the same code, and set state, timestamp + my $code = "$hash->{XMIT}"; + my $tn = TimeNow(); + foreach my $n (keys %{ $modules{IT}{defptr}{$code} }) { + + my $lh = $modules{IT}{defptr}{$code}{$n}; + $lh->{CHANGED}[0] = $v; + $lh->{STATE} = $v; + $lh->{READINGS}{state}{TIME} = $tn; + $lh->{READINGS}{state}{VAL} = $v; + } + return $ret; +} + +############################# +sub +IT_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + my $u = "wrong syntax: define IT 10-bit-housecode " . + "off-code on-code [dimup-code] [dimdown-code]"; + + return $u if(int(@a) < 5); + return "Define $a[0]: wrong IT-Code format: specify a 10 digits 0/1/f " + if( ($a[2] !~ m/^[f0-1]{10}$/i) ); + + return "Define $a[0]: wrong ON format: specify a 2 digits 0/1/f " + if( ($a[3] !~ m/^[f0-1]{2}$/i) ); + + return "Define $a[0]: wrong OFF format: specify a 2 digits 0/1/f " + if( ($a[4] !~ m/^[f0-1]{2}$/i) ); + + my $housecode = $a[2]; + my $oncode = $a[3]; + my $offcode = $a[4]; + + $hash->{XMIT} = lc($housecode); + $hash->{$it_c2b{"on"}} = lc($oncode); + $hash->{$it_c2b{"off"}} = lc($offcode); + + if (int(@a) > 5) { + return "Define $a[0]: wrong dimup-code format: specify a 2 digits 0/1/f " + if( ($a[5] !~ m/^[f0-1]{2}$/i) ); + $hash->{$it_c2b{"dimup"}} = lc($a[5]); + + if (int(@a) == 7) { + return "Define $a[0]: wrong dimdown-code format: specify a 2 digits 0/1/f " + if( ($a[6] !~ m/^[f0-1]{2}$/i) ); + $hash->{$it_c2b{"dimdown"}} = lc($a[6]); + } + } else { + $hash->{$it_c2b{"dimup"}} = "00"; + $hash->{$it_c2b{"dimdown"}} = "00"; + } + + my $code = lc($housecode); + my $ncode = 1; + my $name = $a[0]; + + $hash->{CODE}{$ncode++} = $code; + $modules{IT}{defptr}{$code}{$name} = $hash; + + AssignIoPort($hash); +} + +############################# +sub +IT_Undef($$) +{ + my ($hash, $name) = @_; + + foreach my $c (keys %{ $hash->{CODE} } ) { + $c = $hash->{CODE}{$c}; + + # As after a rename the $name my be different from the $defptr{$c}{$n} + # we look for the hash. + foreach my $dname (keys %{ $modules{IT}{defptr}{$c} }) { + delete($modules{IT}{defptr}{$c}{$dname}) + if($modules{IT}{defptr}{$c}{$dname} == $hash); + } + } + return undef; +} + +sub +IT_Parse($$) +{ + +} + +1;