2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-08 01:14:19 +00:00

MAX: Move parsing to 10_MAX for reuse by CUL_MAX

git-svn-id: https://svn.fhem.de/fhem/trunk@2163 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
mgehre 2012-11-23 07:32:50 +00:00
parent 8769dabf0b
commit d1ff00567c
2 changed files with 78 additions and 70 deletions

View File

@ -10,7 +10,6 @@ use Data::Dumper;
use POSIX; use POSIX;
sub MAXLAN_Parse($$); sub MAXLAN_Parse($$);
sub MAXLAN_ParseDateTime($$$);
sub MAXLAN_Read($); sub MAXLAN_Read($);
sub MAXLAN_Write($$); sub MAXLAN_Write($$);
sub MAXLAN_ReadAnswer($); sub MAXLAN_ReadAnswer($);
@ -255,22 +254,6 @@ MAXLAN_Read($)
} }
} }
sub
MAXLAN_ParseDateTime($$$)
{
my ($byte1,$byte2,$byte3) = @_;
my $day = $byte1 & 0x1F;
my $month = (($byte1 & 0xE0) >> 4) | ($byte2 >> 7);
my $year = $byte2 & 0x3F;
my $time = ($byte3 & 0x3F);
if($time%2){
$time = int($time/2).":30";
}else{
$time = int($time/2).":00";
}
return { "day" => $day, "month" => $month, "year" => $year, "time" => $time, "str" => "$day.$month.$year $time" };
}
sub sub
MAXLAN_SendMetadata($) MAXLAN_SendMetadata($)
{ {
@ -432,20 +415,28 @@ MAXLAN_Parse($$)
return if(@args < 2); return if(@args < 2);
my $bindata = decode_base64($args[1]); my $bindata = decode_base64($args[1]);
return "Invalid C: response, not enough data" if(length($bindata) < 18); if(length($bindata) < 18) {
Log 1, "Invalid C: response, not enough data";
return "Invalid C: response, not enough data";
}
#Parse the first 18 bytes, those are send for every device #Parse the first 18 bytes, those are send for every device
my ($len,$addr,$devicetype,$groupid,$firmware,$testresult,$serial) = unpack("CH6CCCCa[10]", $bindata); my ($len,$addr,$devicetype,$groupid,$firmware,$testresult,$serial) = unpack("CH6CCCCa[10]", $bindata);
Log $ll5, "len $len, addr $addr, devicetype $devicetype, firmware $firmware, testresult $testresult, groupid $groupid, serial $serial";
$len = $len+1; #The len field itself was not counted $len = $len+1; #The len field itself was not counted
Dispatch($hash, "MAX,define,$addr,$device_types{$devicetype},$serial,$groupid", {RAWMSG => $rmsg}); Dispatch($hash, "MAX,define,$addr,$device_types{$devicetype},$serial,$groupid", {RAWMSG => $rmsg});
return "Invalid C: response, len does not match" if($len != length($bindata)); if($len != length($bindata)) {
Log 1, "Invalid C: response, len does not match";
return "Invalid C: response, len does not match";
}
#devicetype: Cube = 0, HeatingThermostat = 1, HeatingThermostatPlus = 2, WallMountedThermostat = 3, ShutterContact = 4, PushButton = 5 #devicetype: Cube = 0, HeatingThermostat = 1, HeatingThermostatPlus = 2, WallMountedThermostat = 3, ShutterContact = 4, PushButton = 5
#Seems that ShutterContact does not have any configdata #Seems that ShutterContact does not have any configdata
if($devicetype == 0){#Cube if($devicetype == 0){#Cube
#TODO: there is a lot of data left to interpret #TODO: there is a lot of data left to interpret
Log $ll5, "len $len, addr $addr, devicetype $devicetype, firmware $firmware, testresult $testresult, groupid $groupid, serial $serial";
}elsif($devicetype == 1){#HeatingThermostat }elsif($devicetype == 1){#HeatingThermostat
my ($comforttemp,$ecotemp,$maxsetpointtemp,$minsetpointtemp,$tempoffset,$windowopentemp,$windowopendur,$boost,$decalcifiction,$maxvalvesetting,$valveoffset) = unpack("CCCCCCCCCCC",substr($bindata,18)); my ($comforttemp,$ecotemp,$maxsetpointtemp,$minsetpointtemp,$tempoffset,$windowopentemp,$windowopendur,$boost,$decalcifiction,$maxvalvesetting,$valveoffset) = unpack("CCCCCCCCCCC",substr($bindata,18));
my $boostValve = ($boost & 0x1F) * 5; my $boostValve = ($boost & 0x1F) * 5;
@ -458,13 +449,12 @@ MAXLAN_Parse($$)
$minsetpointtemp=$minsetpointtemp/2.0; $minsetpointtemp=$minsetpointtemp/2.0;
$windowopentemp=$windowopentemp/2.0; $windowopentemp=$windowopentemp/2.0;
$windowopendur=$windowopendur*5; $windowopendur=$windowopendur*5;
Log $ll5, "len $len, addr $addr, devicetype $devicetype, groupid $groupid, serial $serial, comfortemp $comforttemp, ecotemp $ecotemp, boostValve $boostValve, boostDuration $boostDuration, tempoffset $tempoffset, $minsetpointtemp minsetpointtemp, maxsetpointtemp $maxsetpointtemp, windowopentemp $windowopentemp, windowopendur $windowopendur"; Log $ll5, "comfortemp $comforttemp, ecotemp $ecotemp, boostValve $boostValve, boostDuration $boostDuration, tempoffset $tempoffset, $minsetpointtemp minsetpointtemp, maxsetpointtemp $maxsetpointtemp, windowopentemp $windowopentemp, windowopendur $windowopendur";
Dispatch($hash, "MAX,HeatingThermostatConfig,$addr,$ecotemp,$comforttemp,$boostValve,$boostDuration,$tempoffset,$maxsetpointtemp,$minsetpointtemp,$windowopentemp,$windowopendur", {RAWMSG => $rmsg}); Dispatch($hash, "MAX,HeatingThermostatConfig,$addr,$ecotemp,$comforttemp,$boostValve,$boostDuration,$tempoffset,$maxsetpointtemp,$minsetpointtemp,$windowopentemp,$windowopendur", {RAWMSG => $rmsg});
}elsif($devicetype == 4){#ShutterContact TODO }elsif($devicetype == 4){#ShutterContact TODO
Log 2, "ShutterContact send some configuration, but none was expected" if($len > 18); Log 2, "ShutterContact send some configuration, but none was expected" if($len > 18);
Log $ll5, "len $len, addr $addr, devicetype $devicetype, firmware $firmware, testresult $testresult, groupid $groupid, serial $serial";
}else{ #TODO }else{ #TODO
Log $ll5, "Got configdata for unimplemented devicetype $devicetype: len $len, addr $addr, devicetype $devicetype, groupid $groupid, serial $serial"; Log 2, "Got configdata for unimplemented devicetype $devicetype";
} }
#Check if it is already recorded in devices #Check if it is already recorded in devices
@ -489,47 +479,25 @@ MAXLAN_Parse($$)
while(length($bindata)){ while(length($bindata)){
my ($len,$addr,$errframetype,$bits1) = unpack("CH6Ca",$bindata); my ($len,$addr,$errframetype,$bits1) = unpack("CH6Ca",$bindata);
my $unkbit1 = vec($bits1,0,1); my $unkbit1 = vec($bits1,0,1);
my $unkbit2 = vec($bits1,2,1); my $initialized = vec($bits1,1,1); #I never saw this beeing 0
my $initialized = vec($bits1,1,1); my $answer = vec($bits1,2,1); #answer to what?
my $rferror1 = vec($bits1,3,1); my $rferror1 = vec($bits1,3,1); # if 1 then see errframetype
my $valid = vec($bits1,4,1); my $valid = vec($bits1,4,1); #is the status following the common header valid
my $unkbit3 = vec($bits1,5,1); my $unkbit2 = vec($bits1,5,1);
my $unkbit4 = vec($bits1,6,2); my $unkbit3 = vec($bits1,6,2);
Log 5, "bindata: ".unpack("H*",substr($bindata,0,$len+1)); #+1 because the len field is not counted Log 5, "len $len, addr $addr, initialized $initialized, valid $valid, rferror $rferror1, errframetype $errframetype, answer $answer, unkbit ($unkbit1,$unkbit2,$unkbit3)";
Log 5, "len $len, addr $addr, initialized $initialized, valid $valid, rferror $rferror1, errframetype $errframetype, unkbit ($unkbit1,$unkbit2,$unkbit3,$unkbit4)";
my $payload = unpack("H*",substr($bindata,6,$len-6+1)); #+1 because the len field is not counted
if($valid) { if($valid) {
my $shash = $modules{MAX}{defptr}{$addr}; my $shash = $modules{MAX}{defptr}{$addr};
if(!$shash) { if(!$shash) {
Log 2, "Got List response for undefined device with addr $addr"; Log 2, "Got List response for undefined device with addr $addr";
}elsif($shash->{type} eq "HeatingThermostat"){ }elsif($shash->{type} eq "HeatingThermostat"){
my ($bits2,$valveposition,$temperaturesetpoint,$until1,$until2,$until3) = unpack("aCCCCC",substr($bindata,6)); Dispatch($hash, "MAX,HeatingThermostatState,$addr,$payload", {RAWMSG => $rmsg});
my $ctrlmode = vec($bits2, 0, 2);
my $dstsetting = vec($bits2, 3, 1);
my $rferror = vec($bits2, 6, 1);
my $battery = vec($bits2, 7, 1);
my $untilStr = MAXLAN_ParseDateTime($until1,$until2,$until3)->{str};
my $curTemp = $until2/10;
#If the control mode is not "temporary", the cube sends the current (measured) temperature
$curTemp = "" if($ctrlmode == 2 || $curTemp == 0);
$untilStr = "" if($ctrlmode != 2);
$temperaturesetpoint = $temperaturesetpoint/2.0; #convert to degree celcius
Log 5, "battery $battery, rferror $rferror, dstsetting $dstsetting, ctrlmode $ctrlmode, valveposition $valveposition %, temperaturesetpoint $temperaturesetpoint, until $untilStr, curTemp $curTemp";
Dispatch($hash, "MAX,HeatingThermostatState,$addr,$temperaturesetpoint,$ctrlmode,$untilStr,$battery,$rferror,$dstsetting,$valveposition,$curTemp", {RAWMSG => $rmsg});
}elsif($shash->{type} eq "ShutterContact"){ }elsif($shash->{type} eq "ShutterContact"){
my $bits2 = substr($bindata,6,1); Dispatch($hash, "MAX,ShutterContactState,$addr,$payload", {RAWMSG => $rmsg});
my $isopen = vec($bits2,0,2) == 0 ? 0 : 1;
my $unkbit5 = vec($bits2,2,4);
my $rferror = vec($bits2,6,1);
my $battery = vec($bits2,7,1);
Log 5, "ShutterContact isopen $isopen, rferror $rferror, battery $battery, unkbits $unkbit5";
Dispatch($hash, "MAX,ShutterContactState,$addr,$isopen,$battery,$rferror", {RAWMSG => $rmsg});
}else{ }else{
Log 2, "Got status for unimplemented device type $shash->{type}"; Log 2, "Got status for unimplemented device type $shash->{type}";
} }

View File

@ -15,7 +15,7 @@ sub MAX_Set($@);
sub MAX_MD15Cmd($$$); sub MAX_MD15Cmd($$$);
sub MAX_DateTime2Internal($); sub MAX_DateTime2Internal($);
my @ctrl_modes = ( "auto", "manual", "temporary" ); my @ctrl_modes = ( "auto", "manual", "temporary", "boost" );
my %interfaces = ( my %interfaces = (
"Cube" => undef, "Cube" => undef,
@ -167,6 +167,23 @@ MAX_Set($@)
} }
} }
#############################
sub
MAX_ParseDateTime($$$)
{
my ($byte1,$byte2,$byte3) = @_;
my $day = $byte1 & 0x1F;
my $month = (($byte1 & 0xE0) >> 4) | ($byte2 >> 7);
my $year = $byte2 & 0x3F;
my $time = ($byte3 & 0x3F);
if($time%2){
$time = int($time/2).":30";
}else{
$time = int($time/2).":00";
}
return { "day" => $day, "month" => $month, "year" => $year, "time" => $time, "str" => "$day.$month.$year $time" };
}
############################# #############################
sub sub
MAX_Parse($$) MAX_Parse($$)
@ -201,28 +218,48 @@ MAX_Parse($$)
} }
} elsif($msgtype eq "HeatingThermostatState") { } elsif($msgtype eq "HeatingThermostatState") {
my $settemp = $args[0];
my $mode = $ctrl_modes[$args[1]]; my ($bits2,$valveposition,$temperaturesetpoint,$until1,$until2,$until3) = unpack("aCCCCC",pack("H*",$args[0]));
my $until = $args[2]; my $mode = vec($bits2, 0, 2); #
my $batterylow = $args[3]; my $dstsetting = vec($bits2, 3, 1); #is automatically switching to DST activated
my $rferror = $args[4]; my $langateway = vec($bits2, 4, 1); #??
my $dstsetting = $args[5]; my $panel = vec($bits2, 5, 1); #1 if the heating thermostat is locked for manually setting the temperature at the device
my $valveposition = $args[6]; my $rferror = vec($bits2, 6, 1); #communication with link partner (what does that mean?)
my $measuredTemperature = ""; my $batterylow = vec($bits2, 7, 1); #1 if battery is low
$measuredTemperature = $args[7] if(@args > 7);
my $untilStr = MAX_ParseDateTime($until1,$until2,$until3)->{str};
my $measuredTemperature = $until2/10;
#If the control mode is not "temporary", the cube sends the current (measured) temperature
$measuredTemperature = "" if($mode == 2 || $measuredTemperature == 0);
$untilStr = "" if($mode != 2);
$temperaturesetpoint = $temperaturesetpoint/2.0; #convert to degree celcius
Log 5, "battery $batterylow, rferror $rferror, panel $panel, langateway $langateway, dstsetting $dstsetting, mode $mode, valveposition $valveposition %, temperaturesetpoint $temperaturesetpoint, until $untilStr, curTemp $measuredTemperature";
#my $settemp = $args[0];
#my $mode = $ctrl_modes[$args[1]];
#my $until = $args[2];
#my $batterylow = $args[3];
#my $rferror = $args[4];
#my $dstsetting = $args[5];
#my $valveposition = $args[6];
#my $measuredTemperature = "";
#The HeatingThermostat uses the temperatureOffset during control
#but does not apply it to measuredTemperature before sending it to us
$measuredTemperature += $shash->{temperatureOffset} if($measuredTemperature ne "" and exists($shash->{temperatureOffset}));
$shash->{mode} = $mode; $shash->{mode} = $mode;
$shash->{rferror} = $rferror; $shash->{rferror} = $rferror;
$shash->{dstsetting} = $dstsetting; $shash->{dstsetting} = $dstsetting;
if($mode eq "temporary"){ if($mode eq "temporary"){
$shash->{until} = "$until"; $shash->{until} = "$untilStr";
}else{ }else{
delete($shash->{until}); delete($shash->{until});
} }
readingsBeginUpdate($shash); readingsBeginUpdate($shash);
readingsBulkUpdate($shash, "battery", $batterylow ? "low" : "ok"); readingsBulkUpdate($shash, "battery", $batterylow ? "low" : "ok");
readingsBulkUpdate($shash, "desiredTemperature", $settemp); readingsBulkUpdate($shash, "desiredTemperature", $temperaturesetpoint);
readingsBulkUpdate($shash, "valveposition", $valveposition); readingsBulkUpdate($shash, "valveposition", $valveposition);
if($measuredTemperature ne "") { if($measuredTemperature ne "") {
readingsBulkUpdate($shash, "temperature", $measuredTemperature); readingsBulkUpdate($shash, "temperature", $measuredTemperature);
@ -230,9 +267,12 @@ MAX_Parse($$)
readingsEndUpdate($shash, 0); readingsEndUpdate($shash, 0);
}elsif($msgtype eq "ShutterContactState"){ }elsif($msgtype eq "ShutterContactState"){
my $isopen = $args[0]; my $bits = pack("H2",$args[0]);
my $batterylow = $args[1]; my $isopen = vec($bits,0,2) == 0 ? 0 : 1;
my $rferror = $args[2]; my $unkbits = vec($bits,2,4);
my $rferror = vec($bits,6,1);
my $batterylow = vec($bits,7,1);
Log 5, "ShutterContact isopen $isopen, rferror $rferror, battery $batterylow, unkbits $unkbits";
$shash->{rferror} = $rferror; $shash->{rferror} = $rferror;