mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-25 09:49:20 +00:00
MAX: Rewrite faking of WallThermostat/ShutterContact
git-svn-id: https://svn.fhem.de/fhem/trunk@2731 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
7c8aa8240f
commit
5e9f17e51b
@ -87,6 +87,7 @@ MAX_Define($$)
|
||||
my ($hash, $def) = @_;
|
||||
my @a = split("[ \t][ \t]*", $def);
|
||||
my $name = $hash->{NAME};
|
||||
return "name \"$name\" is reserved for internal use" if($name eq "fakeWallThermostat" or $name eq "fakeShutterContact");
|
||||
return "wrong syntax: define <name> MAX addr"
|
||||
if(int(@a)!=4 || $a[3] !~ m/^[A-F0-9]{6}$/i);
|
||||
|
||||
@ -368,14 +369,30 @@ MAX_Set($@)
|
||||
|
||||
} elsif($setting ~~ ["associate", "deassociate"]) {
|
||||
my $dest = $args[0];
|
||||
if(exists($defs{$dest})) {
|
||||
return "Destination is not a MAX device" if($defs{$dest}{TYPE} ne "MAX");
|
||||
$dest = $defs{$dest}{addr};
|
||||
my $destType;
|
||||
if($dest eq "fakeWallThermostat") {
|
||||
return "IODev is not CUL_MAX" if($hash->{IODev}->{TYPE} ne "CUL_MAX");
|
||||
$dest = AttrVal($hash->{IODev}->{NAME}, "fakeWTaddr", "111111");
|
||||
return "Invalid fakeWTaddr attribute set (must not be 000000)" if($dest eq "000000");
|
||||
$destType = MAX_TypeToTypeId("WallMountedThermostat");
|
||||
|
||||
} elsif($dest eq "fakeShutterContact") {
|
||||
return "IODev is not CUL_MAX" if($hash->{IODev}->{TYPE} ne "CUL_MAX");
|
||||
$dest = AttrVal($hash->{IODev}->{NAME}, "fakeSCaddr", "222222");
|
||||
return "Invalid fakeSCaddr attribute set (must not be 000000)" if($dest eq "000000");
|
||||
$destType = MAX_TypeToTypeId("ShutterContact");
|
||||
|
||||
} else {
|
||||
return "No MAX device with address $dest" if(!exists($modules{MAX}{defptr}{$dest}));
|
||||
if(exists($defs{$dest})) {
|
||||
return "Destination is not a MAX device" if($defs{$dest}{TYPE} ne "MAX");
|
||||
$dest = $defs{$dest}{addr};
|
||||
} else {
|
||||
return "No MAX device with address $dest" if(!exists($modules{MAX}{defptr}{$dest}));
|
||||
}
|
||||
my $destType = MAX_TypeToTypeId($modules{MAX}{defptr}{$dest}{type});
|
||||
Log 2, "Warning: Device do not have same groupid" if($hash->{groupid} != $modules{MAX}{defptr}{$dest}{groupid});
|
||||
}
|
||||
my $destType = MAX_TypeToTypeId($modules{MAX}{defptr}{$dest}{type});
|
||||
Log 2, "Warning: Device do not have same groupid" if($hash->{groupid} != $modules{MAX}{defptr}{$dest}{groupid});
|
||||
|
||||
Log GetLogLevel($hash->{NAME}, 5), "Using dest $dest, destType $destType";
|
||||
if($setting eq "associate") {
|
||||
return ($hash->{IODev}{Send})->($hash->{IODev},"AddLinkPartner",$hash->{addr},sprintf("%s%02x", $dest, $destType));
|
||||
@ -446,7 +463,11 @@ MAX_Set($@)
|
||||
my $assoclist;
|
||||
#Build list of devices which this device can be associated to
|
||||
if($hash->{type} =~ /HeatingThermostat.*/) {
|
||||
$assoclist = join(",", map { defined($_->{type}) && $_->{type} ~~ ["HeatingThermostat", "HeatingThermostatPlus", "WallMountedThermostat", "ShutterContact"] ? $_->{NAME} : () } values %{$modules{MAX}{defptr}});
|
||||
$assoclist = join(",", map { defined($_->{type}) && $_->{type} ~~ ["HeatingThermostat", "HeatingThermostatPlus", "WallMountedThermostat", "ShutterContact"] && $_ != $hash ? $_->{NAME} : () } values %{$modules{MAX}{defptr}});
|
||||
if($hash->{IODev}->{TYPE} eq "CUL_MAX") {
|
||||
$assoclist .= "," if(length($assoclist));
|
||||
$assoclist .= "fakeWallThermostat,fakeShutterContact";
|
||||
}
|
||||
} elsif($hash->{type} ~~ ["ShutterContact", "WallMountedThermostat"]) {
|
||||
$assoclist = join(",", map { defined($_->{type}) && $_->{type} =~ /HeatingThermostat.*/ ? $_->{NAME} : () } values %{$modules{MAX}{defptr}});
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ CUL_MAX_Initialize($)
|
||||
$hash->{UndefFn} = "CUL_MAX_Undef";
|
||||
$hash->{ParseFn} = "CUL_MAX_Parse";
|
||||
$hash->{SetFn} = "CUL_MAX_Set";
|
||||
$hash->{AttrFn} = "CUL_MAX_Attr";
|
||||
$hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 " .
|
||||
"showtime:1,0 loglevel:0,1,2,3,4,5,6 ".
|
||||
$readingFnAttributes;
|
||||
@ -66,12 +67,18 @@ CUL_MAX_Define($$)
|
||||
$hash->{sendQueue} = [];
|
||||
AssignIoPort($hash);
|
||||
|
||||
if(CUL_MAX_Check($hash)) {
|
||||
if(CUL_MAX_Check($hash) >= 152) {
|
||||
#Doing this on older firmware disables MAX mode
|
||||
IOWrite($hash, "", "Za". $hash->{addr});
|
||||
#Append to initString, so this is resend if cul disappears and then reappears
|
||||
$hash->{IODev}{initString} .= "\nZa". $hash->{addr};
|
||||
}
|
||||
if(CUL_MAX_Check($hash) >= 153) {
|
||||
#Doing this on older firmware disables MAX mode
|
||||
my $cmd = "Zw". CUL_MAX_fakeWTaddr($hash);
|
||||
IOWrite($hash, "", $cmd);
|
||||
$hash->{IODev}{initString} .= "\n".$cmd;
|
||||
}
|
||||
|
||||
#This interface is shared with 00_MAXLAN.pm
|
||||
$hash->{Send} = \&CUL_MAX_Send;
|
||||
@ -111,11 +118,33 @@ CUL_MAX_Check($@)
|
||||
#Looks like "V 1.49 CUL868"
|
||||
$version =~ m/V (.*)\.(.*) .*/;
|
||||
my ($major_version,$minorversion) = ($1, $2);
|
||||
if($major_version == 1 and $minorversion < 52) {
|
||||
Log 2, "The current firmware of the CUL has known bugs with respect to MAX! support. Please update.";
|
||||
return 0;
|
||||
my $version = 100*$major_version + $minorversion;
|
||||
if($version < 153) {
|
||||
Log 2, "You are using an old version of the CUL firmware, which has known bugs with respect to MAX! support. Please update.";
|
||||
}
|
||||
return 1;
|
||||
return $version;
|
||||
}
|
||||
|
||||
sub
|
||||
CUL_MAX_Attr(@)
|
||||
{
|
||||
my ($hash, $action, $name, $attr, $value) = @_;
|
||||
if ($action eq "set") {
|
||||
return "No such attribute" if($attr ne "fakeWTaddr" && $attr ne "fakeSCaddr");
|
||||
return "Invalid value" if($value !~ /^[0-9a-fA-F]{6}$/);
|
||||
}
|
||||
}
|
||||
|
||||
sub
|
||||
CUL_MAX_fakeWTaddr($)
|
||||
{
|
||||
return AttrVal(@_[0]->{NAME}, "fakeWTaddr", "111111");
|
||||
}
|
||||
|
||||
sub
|
||||
CUL_MAX_fakeSCaddr($)
|
||||
{
|
||||
return AttrVal(@_[0]->{NAME}, "fakeSCaddr", "222222");
|
||||
}
|
||||
|
||||
sub
|
||||
@ -132,6 +161,41 @@ CUL_MAX_Set($@)
|
||||
} elsif($setting eq "broadcastTime") {
|
||||
CUL_MAX_BroadcastTime($hash, 1);
|
||||
|
||||
} elsif($setting ~~ ["fakeSC", "fakeWT"]) {
|
||||
return "Invalid number of arguments" if(@args == 0);
|
||||
my $dest = $args[0];
|
||||
#$dest may be either a name or an address
|
||||
if(exists($defs{$dest})) {
|
||||
return "Destination is not a MAX device" if($defs{$dest}{TYPE} ne "MAX");
|
||||
$dest = $defs{$dest}{addr};
|
||||
} else {
|
||||
return "No MAX device with address $dest" if(!exists($modules{MAX}{defptr}{$dest}));
|
||||
}
|
||||
|
||||
if($setting eq "fakeSC") {
|
||||
return "Invalid number of arguments" if(@args != 2);
|
||||
return "Invalid fakeSCaddr attribute set (must not be 000000)" if(CUL_MAX_fakeSCaddr($hash) eq "000000");
|
||||
|
||||
my $state = $args[1] ? "12" : "10";
|
||||
return CUL_MAX_Send($hash, "ShutterContactState",$dest,$state, flags => "06", src => CUL_MAX_fakeSCaddr($hash));
|
||||
|
||||
} elsif($setting eq "fakeWT") {
|
||||
return "Invalid number of arguments" if(@args != 3);
|
||||
return "desiredTemperature is invalid" if($args[1] < 4.5 || $args[2] > 30.5);
|
||||
return "Invalid fakeWTaddr attribute set (must not be 000000)" if(CUL_MAX_fakeWTaddr($hash) eq "000000");
|
||||
|
||||
$args[2] = 0 if($args[2] < 0); #Clamp temperature to minimum of 0 degree
|
||||
|
||||
#Encode into binary form
|
||||
my $arg2 = int(10*$args[2]);
|
||||
#First bit is 9th bit of temperature, rest is desiredTemperature
|
||||
my $arg1 = (($arg2&0x100)>>1) | (int(2*$args[1])&0x7F);
|
||||
$arg2 &= 0xFF; #only take the lower 8 bits
|
||||
|
||||
return CUL_MAX_Send($hash,"WallThermostatControl",$dest,
|
||||
sprintf("%02x%02x",$arg1,$arg2),flags => "04", src => CUL_MAX_fakeWTaddr($hash));
|
||||
}
|
||||
|
||||
} else {
|
||||
return "Unknown argument $setting, choose one of pairmode broadcastTime";
|
||||
}
|
||||
@ -172,16 +236,20 @@ CUL_MAX_Parse($$)
|
||||
if(exists($msgId2Cmd{$msgTypeRaw})) {
|
||||
|
||||
if($msgType eq "Ack") {
|
||||
return $shash->{NAME} if($src eq $shash->{addr}); #Ignore packets generated by culfw's auto-Ack
|
||||
#Ignore packets generated by culfw's auto-Ack
|
||||
return $shash->{NAME} if($src eq $shash->{addr});
|
||||
return $shash->{NAME} if($src eq CUL_MAX_fakeWTaddr($hash));
|
||||
return $shash->{NAME} if($src eq CUL_MAX_fakeSCaddr($hash));
|
||||
|
||||
Dispatch($shash, "MAX,$isToMe,Ack,$src,$payload", {RAWMSG => $rmsg});
|
||||
|
||||
return $shash->{NAME} if(!$isToMe);
|
||||
return $shash->{NAME} if(!@{$shash->{sendQueue}}); #we are not waiting for any Ack
|
||||
|
||||
my $packet = $shash->{sendQueue}[0];
|
||||
if($packet->{dst} eq $src and $packet->{cnt} == hex($msgcnt)) {
|
||||
if($packet->{src} eq $dst and $packet->{dst} eq $src and $packet->{cnt} == hex($msgcnt)) {
|
||||
Log $ll5, "Got matching ack";
|
||||
$packet->{sent} = 2;
|
||||
my $isnak = unpack("C",pack("H*",$payload)) & 0x80;
|
||||
$packet->{sent} = $isnak ? 3 : 2;
|
||||
return $shash->{NAME};
|
||||
}
|
||||
|
||||
@ -273,6 +341,7 @@ CUL_MAX_Send(@)
|
||||
my $timeout = gettimeofday()+$ackTimeout;
|
||||
my $aref = $hash->{sendQueue};
|
||||
push(@{$aref}, { "packet" => $packet,
|
||||
"src" => $src,
|
||||
"dst" => $dst,
|
||||
"cnt" => hex($msgcnt),
|
||||
"time" => $timeout,
|
||||
@ -348,6 +417,9 @@ CUL_MAX_SendQueueHandler($)
|
||||
Dispatch($hash, "MAX,1,Ack$packet->{cmd},$packet->{dst},$packet->{callbackParam}", {RAWMSG => ""});
|
||||
}
|
||||
splice @{$hash->{sendQueue}}, 0, 1; #Remove from array
|
||||
|
||||
} elsif( $packet->{sent} == 3 ) { #Got nack
|
||||
splice @{$hash->{sendQueue}}, 0, 1; #Remove from array
|
||||
}
|
||||
|
||||
return if(!@{$hash->{sendQueue}}); #everything done
|
||||
|
Loading…
x
Reference in New Issue
Block a user