FHEM Forum

FHEM => Anfängerfragen => Thema gestartet von: StefanStrobel am 17 Dezember 2013, 20:17:11

Titel: Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 17 Dezember 2013, 20:17:11
Ich habe nun seit ein paar Monate Fhem auf einer FritzBox 7390 mit einem CUL und einem Enocean Stick, ESA2000 Sensoren an meinen Stromzählern und inzwischen auch eine serielle Anbindung an meine Waterkotte Wärmepumpe.

Das Modul für die Wärmepumpe habe ich als Einstiegsprojekt aus verschiedenen Vorlagen zusammengebaut. Die Analyse des Protokolls war glücklicherweise schon in verschiedenen Foren veröffentlicht.

Falls jemand auch so eine Wärmepumpe hat, hier mein Modul.
Da es mein erstes Perl-Programm war, bin ich für Optimierungshinweise dankbar.

#########################################################################
# fhem Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
# Vorlage: Modul WHR962, diverse Foreneinträge sowie Artikel über Auswertung der
# Wärmepumpe mit Linux / Perl im Linux Magazin aus 2010
# insbesondere:
#      http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=2  (Speicheradressen-Liste)
#      http://www.ip-symcon.de/forum/threads/2092-ComPort-und-Waterkotte-abfragen                      (Protokollbeschreibung)
#      http://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=4    (Beispiel Befehls-Strings)
#
# Benutzung auf eigenes Risiko!   
# use at your own risk. It works for me but it could destroy your heating if things go very wrong.
#                      

package main;

use strict;                         
use warnings;                       
use Time::HiRes qw(gettimeofday);   

#
# list of Readings / values that can explicitely be requested
# from the WP with the GET command
# more could be added from the hash %frameReadings if needed
#
my %WKRCD4_gets = ( 
   "Hzg-TempBasisSoll"   => "Hzg-TempBasisSoll",
   "WW-Temp-Soll"      => "Temp-WW-Soll"
);

# list of Readings / values that can be written to the WP
# I included just one for testing.
# more could be added but testing is required
#
my %WKRCD4_sets = ( 
   "Hzg-TempBasisSoll"   => "Hzg-TempBasisSoll"
);

# Definition of the values that can be read / written
# with the relative address, number of bytes and
# format to be used in sprintf when formatting the value
# unpack code to be used in pack / unpack commands
# min / max for setting values
#
my %frameReadings = (
'Versions-Nummer'        => { addr => 0x0000, bytes => 0x0002,                  unp => 'n' },
'Temp-Aussen'            => { addr => 0x0008, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Ruecklauf-Soll'    => { addr => 0x0014, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Ruecklauf'         => { addr => 0x0018, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Vorlauf'           => { addr => 0x001C, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-WW-Soll'           => { addr => 0x0020, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-WW'                => { addr => 0x0024, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Raum'              => { addr => 0x0028, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-WQuelle-Ein'       => { addr => 0x0030, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-WQuelle-Aus'       => { addr => 0x0034, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Verdampfer'        => { addr => 0x0038, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Kondensator'       => { addr => 0x003C, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Temp-Saugleitung'       => { addr => 0x0040, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Druck-Verdampfer'       => { addr => 0x0048, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Druck-Kondensator'      => { addr => 0x004C, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-TempEinsatz'        => { addr => 0x00F4, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 15.0, max => 20.0 },
'Hzg-TempBasisSoll'      => { addr => 0x00F8, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 20.0, max => 24.0 },
'Hzg-KlSteilheit'        => { addr => 0x00FC, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 15.0, max => 30.0 },
'Hzg-KlBegrenz'          => { addr => 0x0100, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-TempRlSoll'         => { addr => 0x0050, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-TempRlIst'          => { addr => 0x0054, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-TmpRaumSoll'        => { addr => 0x0105, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-RaumEinfluss'       => { addr => 0x0109, bytes => 0x0001,                  unp => 'C' },
'Hzg-ExtAnhebung'        => { addr => 0x010A, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => -5.0, max => 5.0 },
'Hzg-Zeit-Ein'           => { addr => 0x010E, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC'},
'Hzg-Zeit-Aus'           => { addr => 0x0111, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Hzg-AnhebungEin'        => { addr => 0x0114, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Hzg-AnhebungAus'        => { addr => 0x0117, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Hzg-St2Begrenz'         => { addr => 0x011A, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Hzg-Hysterese'          => { addr => 0x011E, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 1.0, max => 3.0  },
'Hzg-PumpenNachl'        => { addr => 0x0122, bytes => 0x0001,                  unp => 'C',  min => 0,   max => 120  },
'Klg-Abschaltung'        => { addr => 0x0123, bytes => 0x0001,                  unp => 'C' },
'Klg-Temp-Einsatz'       => { addr => 0x0124, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Klg-TeBasisSoll'        => { addr => 0x0128, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Klg-KlSteilheit'        => { addr => 0x012C, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Klg-KlBegrenz'          => { addr => 0x0130, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Klg-KlSollwert'         => { addr => 0x0058, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Klg-Temp-Rl'            => { addr => 0x005C, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Ww-Abschaltung'         => { addr => 0x0134, bytes => 0x0001 },
'Ww-Zeit-Ein'            => { addr => 0x0135, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Ww-Zeit-Aus'            => { addr => 0x0138, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Ww-Temp-Ist'            => { addr => 0x0060, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Ww-Temp-Soll'           => { addr => 0x013b, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 35, max => 55 },
'Ww-Hysterese'           => { addr => 0x0143, bytes => 0x0004, fmat => '%0.1f', unp => 'f<', min => 5,  max => 10},
'Uhrzeit'                => { addr => 0x0064, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Datum'                  => { addr => 0x0067, bytes => 0x0003, fmat => '%02d.%02d.%02d', unp => 'CCC'},
'BetrStundenKompressor'  => { addr => 0x006A, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'BetrStundenHzgPu'       => { addr => 0x006E, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'BetrStundenWwPu'        => { addr => 0x0072, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'BetrStundenSt2'         => { addr => 0x0076, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },
'Zeit'                   => { addr => 0x0064, bytes => 0x0006, fmat=> '%4$02d.%5$02d.%6$02d %3$02d:%2$02d:%1$02d', unp => 'CCCCCC'},
'SetBetriebsMode'        => { addr => 0x014E, bytes => 0x0003,              unp => 'N', pack => 'xC*'},
'Display-Zeile-1'        => { addr => 0x008E, bytes => 0x0002,              unp => 'n' },
'Display-Zeile-2'        => { addr => 0x0090, bytes => 0x0001,              unp => 'C' },
'Status-Gesamt'          => { addr => 0x00D2, bytes => 0x0001,              unp => 'C' },
'Status-Heizung'         => { addr => 0x00D4, bytes => 0x0003,                  unp => 'B24' },
'Status-Kuehlung'        => { addr => 0x00DA, bytes => 0x0003,                  unp => 'B24' },
'Mode-Heizung'           => { addr => 0x00DF, bytes => 0x0001,                  unp => 'B8' },
'Mode-Kuehlung'          => { addr => 0x00E0, bytes => 0x0001,                  unp => 'B8' },
'Mode-Warmwasser'        => { addr => 0x00E1, bytes => 0x0001,                  unp => 'B8' }
);

#
# FHEM module intitialisation
# defines the functions to be called from FHEM
#########################################################################
sub WKRCD4_Initialize($)
{
   my ($hash) = @_;

   require "$attr{global}{modpath}/FHEM/DevIo.pm";

   $hash->{ReadFn}  = "WKRCD4_Read";
   $hash->{ReadyFn} = "WKRCD4_Ready";
   $hash->{DefFn}   = "WKRCD4_Define";
   $hash->{UndefFn} = "WKRCD4_Undef";
   $hash->{SetFn}   = "WKRCD4_Set";
   $hash->{GetFn}   = "WKRCD4_Get";
   $hash->{AttrList} =
     "do_not_notify:1,0 loglevel:0,1,2,3,4,5,6 " . $readingFnAttributes;
}

#
# Define command
# init internal values, open device,
# set internal timer to send read command / wakeup
#########################################################################                           #
sub WKRCD4_Define($$)
{
   my ( $hash, $def ) = @_;
   my @a = split( "[ \t][ \t]*", $def );

   return "wrong syntax: define <name> WKRCD4 [devicename|none] interval"
     if ( @a < 3 );

   DevIo_CloseDev($hash);
   my $name = $a[0];
   my $dev  = $a[2];
   my $interval  = 60;
   
   if ( $dev eq "none" ) {
      Log3 undef, 1, "WKRCD4 device is none, commands will be echoed only";
      return undef;
   }
   
   if(int(@a) == 4) {
      $interval= $a[3];
      if ($interval < 20) {
         return "interval too small, please use something > 20, default is 60";
      }
   }

   $hash->{buffer}          = "";
   
   $hash->{DeviceName}       = $dev;
   $hash->{INTERVAL}         = $interval;

   $hash->{SerialRequests}      = 0;
   $hash->{SerialGoodReads}    = 0;
   $hash->{SerialBadReads}    = 0;

   # send wakeup string (read 2 values preceeded with AT)
   $hash->{LastRequestAdr}      = 8;
   $hash->{LastRequestLen}    = 4;
   $hash->{LastRequest}         = gettimeofday();
   my $ret = DevIo_OpenDev( $hash, 0, "WKRCD4_Wakeup" );
   
   # initial read after 3 secs, there timer is set to interval for update and wakeup
   InternalTimer(gettimeofday()+3, "WKRCD4_GetUpdate", $hash, 0);   

   return $ret;
}

#
# undefine command when device is deleted
#########################################################################
sub WKRCD4_Undef($$)   
{                     
   my ( $hash, $arg ) = @_;       
   DevIo_CloseDev($hash);         
   RemoveInternalTimer($hash);   
   return undef;                 
}   


#
# Encode the data to be sent to the device (0x10 gets doubled)
#########################################################################
sub Encode10 (@) {
   my @a = ();
   for my $byte (@_) {
      push @a, $byte;
      push @a, $byte if $byte == 0x10;
   }
   return @a;
}

#
# create a command for the WP as byte array
#########################################################################
sub WPCMD($$$$;@)
{
   my ($hash, $cmd, $addr, $len, @value ) = @_;
   my $name = $hash->{NAME};
   my @frame = ();
   
   if ($cmd eq "read") {
      @frame = (0x01, 0x15, Encode10($addr>>8, $addr%256), Encode10($len>>8, $len%256));   
   } elsif ($cmd eq "write") {
      @frame = (0x01, 0x13, Encode10($addr>>8, $addr%256), Encode10(@value));
   } else {
      Log3 $name, 3, "undefined cmd ($cmd) in WPCMD";
      return 0;
   }
   my $crc = CRC16(@frame);
   return (0xff, 0x10, 0x02, @frame, 0x10, 0x03, $crc >> 8, $crc % 256, 0xff);
}

#
# GET command
#########################################################################
sub WKRCD4_Get($@)
{
   my ( $hash, @a ) = @_;
   return "\"get WKRCD4\" needs at least an argument" if ( @a < 2 );

   my $name = shift @a;
   my $attr = shift @a;
   my $arg = join("", @a);
   
   if(!$WKRCD4_gets{$attr}) {
      my @cList = keys %WKRCD4_gets;
      return "Unknown argument $attr, choose one of " . join(" ", @cList);
   }

   # get Hash pointer for the attribute requested from the global hash
   my $properties = $frameReadings{$WKRCD4_sets{$attr}};
   if(!$properties) {
      return "No Entry in frameReadings found for $attr";
   }

   # get details about the attribute requested from its hash
   my $addr  = $properties->{addr};
   my $bytes = $properties->{bytes};
   Log3 $name, 4, sprintf ("Read %02x bytes starting from %02x for $attr", $bytes, $addr);

   # create command for WP
   my $cmd = pack('C*', WPCMD($hash, 'read', $addr, $bytes));

   # set internal variables to track what is happending
   $hash->{LastRequestAdr} = $addr;
   $hash->{LastRequestLen} = $bytes;
   $hash->{LastRequest}     = gettimeofday();
   $hash->{SerialRequests}++;

   Log3 $name, 4, "Get -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
   DevIo_SimpleWrite( $hash, $cmd , 0 );
   
   return sprintf ("Read %02x bytes starting from %02x", $bytes, $addr);
}
   
#
# SET command
#########################################################################
sub WKRCD4_Set($@)
{
   my ( $hash, @a ) = @_;
   return "\"set WKRCD4\" needs at least an argument" if ( @a < 2 );

   my $name = shift @a;
   my $attr = shift @a;
   my $arg = join("", @a);
   
   if(!defined($WKRCD4_sets{$attr})) {
      my @cList = keys %WKRCD4_sets;
      return "Unknown argument $attr, choose one of " . join(" ", @cList);
   }

   # get Hash pointer for the attribute requested from the global hash
   my $properties = $frameReadings{$WKRCD4_sets{$attr}};
   if(!$properties) {
      return "No Entry in frameReadings found for $attr";
   }

   # get details about the attribute requested from its hash
   my $addr  = $properties->{addr};
   my $bytes = $properties->{bytes};
   my $min   = $properties->{min};
   my $max   = $properties->{max};
   my $unp   = $properties->{unp};
   
    return "a numerical value between $min and $max is expected, got $arg instead"
        if($arg !~ m/^[\d.]+$/ || $arg < $min || $arg > $max);
   
   # convert string to value needed for command
   my $vp      = pack($unp, $arg);
   my @value = unpack ('C*', $vp);
   
   Log3 $name, 4, sprintf ("Write $attr: %02x bytes starting from %02x with %s (%s) packed with $unp", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
   my $cmd = pack('C*', WPCMD($hash, 'write', $addr, $bytes, @value));
   
   # set internal variables to track what is happending
   $hash->{LastRequestAdr} = $addr;
   $hash->{LastRequestLen} = $bytes;
   $hash->{LastRequest}     = gettimeofday();
   $hash->{SerialRequests}++;
   Log3 $name, 4, "Set -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
   DevIo_SimpleWrite( $hash, $cmd , 0 );
   
   return sprintf ("Wrote %02x bytes starting from %02x with %s (%s)", $bytes, $addr, unpack ('H*', $vp), unpack ($unp, $vp));
}



#########################################################################
# called from the global loop, when the select for hash->{FD} reports data
sub WKRCD4_Read($)
{
   my ($hash) = @_;
   my $name = $hash->{NAME};
   
   # read from serial device
   my $buf = DevIo_SimpleRead($hash);      
   return "" if ( !defined($buf) );

   # convert to hex string to make parsing with regex easier
   $hash->{buffer} .= unpack ('H*', $buf);   
   Log3 $name, 5, "Current buffer content: " . $hash->{buffer};

   # did we already get a full frame?
   if ($hash->{buffer} =~ "ff1002(.{4})(.*)1003(.{4})ff(.*)")
   {
      my $msg   = $1;
      my $frame = $msg . $2;
      my $crc   = $3;
      
      Log3 $name, 4, "Match msg: " .$msg . " " . $frame . " CRC " . $crc . " Rest " . $4;
      $hash->{buffer} = $4;

      # convert frame contents to byte array
      my @aframe = unpack ('C*', pack ('H*', $frame));
      
      # calculate CRC and compare with CRC from read
      my $crc2 = sprintf("%04x",CRC16(@aframe));
      if ($crc eq $crc2)
      {
         Log3 $name, 4, "CRC Ok.";
         $hash->{SerialGoodReads}++;
         
         # reply to read request ?
         if ($msg eq "0017") {
            my @data;
            for(my $i=0,my $offset=2;$offset<=$#aframe;$offset++,$i++)
            {
               # remove duplicate 0x10 (frames are encoded like this)
               if (($aframe[$offset]==16)&&($aframe[$offset+1]==16)) { $offset++; }
               $data[$i] = $aframe[$offset];
            }   
            Log3 $name, 4, "Parse with relative request start " . $hash->{LastRequestAdr} . " Len " . $hash->{LastRequestLen};
            # extract values from data
            parseReadings($hash, @data);         
         } elsif ($msg eq "0011") {
            # reply to write
         } else {
            Log3 $name, 3, "Unknown Msg type " . $msg . " in " . $hash->{buffer};
         }
      } else
      {
         Log3 $name, 3, "Bad CRC from WP: " . $crc . " berechnet: " . $crc2 . " Frame ". $frame;
         $hash->{SerialBadReads} ++;
      };
      @aframe = ();
   } else {
      Log3 $name, 5, "NoMatch: " . $hash->{buffer};
   };
   return "";
}

#
# copied from other FHEM modules
#########################################################################
sub WKRCD4_Ready($)
{
   my ($hash) = @_;

   return DevIo_OpenDev( $hash, 1, undef )
     if ( $hash->{STATE} eq "disconnected" );

   # This is relevant for windows/USB only
   my $po = $hash->{USBDev};
   my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po->status;
   return ( $InBytes > 0 );
}

#
# send wakeup /at least my waterkotte WP doesn't respond otherwise
#########################################################################
sub WKRCD4_Wakeup($)
{
   my ($hash) = @_;
   my $name = $hash->{NAME};
   
   $hash->{SerialRequests}++;
   
   $hash->{LastRequestAdr} = 8;
   $hash->{LastRequestLen} = 4;
   $hash->{LastRequest}     = gettimeofday();
   
   my $cmd = "41540D100201150008000410037EA010020115003000041003FDC3100201150034000410037D90";
   DevIo_SimpleWrite( $hash, $cmd , 1 );
   
   Log3 $name, 5, "sent wakeup string: " . $cmd . " done.";
   return undef;
}

#
# request new data from WP
###################################
sub WKRCD4_GetUpdate($)
{
   my ($hash) = @_;
   my $name = $hash->{NAME};
   
   InternalTimer(gettimeofday()+$hash->{INTERVAL}, "WKRCD4_GetUpdate", $hash, 1);
   InternalTimer(gettimeofday()+$hash->{INTERVAL}/2, "WKRCD4_Wakeup", $hash, 1);

   $hash->{SerialRequests}++;
   
   my $cmd = pack('C*', WPCMD($hash, 'read', 0, 0x170));
   $hash->{LastRequestAdr} = 0;
   $hash->{LastRequestLen} = 0x170;
   $hash->{LastRequest}     = gettimeofday();
   DevIo_SimpleWrite( $hash, $cmd , 0 );
   
   Log3 $name, 5, "GetUpdate -> Call DevIo_SimpleWrite: " . unpack ('H*', $cmd);
   
   return 1;
}

#
# calculate CRC16 for communication with the WP
#####################################################################################################
sub CRC16
{
    my $CRC = 0;
    my $POLY  = 0x800500;

    for my $byte (@_, 0, 0) {
        $CRC |= $byte;
        for (0 .. 7) {
            $CRC <<= 1;
            if ($CRC & 0x1000000) { $CRC ^= $POLY; }
            $CRC &= 0xffffff;
        }
    }
    return $CRC >> 8;
}


#
# get Values out of data read
#####################################################################################################
sub parseReadings
{
    my ($hash, @data) = @_;
     my $name = $hash->{NAME};
 
   my $reqStart = $hash->{LastRequestAdr};
   my $reqLen    = $hash->{LastRequestLen};
   
   # get enough bytes?
    if (@data >= $reqLen)
    {
      readingsBeginUpdate($hash);
      # go through all possible readings from global hash
        while (my ($reading, $property) = each(%frameReadings))
        {
         my $addr  = $property->{addr};
         my $bytes = $property->{bytes};
         
         # is reading inside data we got?
            if (($addr >= $reqStart) &&
             ($addr + $bytes <= $reqStart + $reqLen))
            {
            my $Idx = $addr - $reqStart;
            # get relevant slice from data array
            my @slice = @data[$Idx .. $Idx + $bytes - 1];
            
            # convert according to rules in global hash or defaults
            my $pack   = ($property->{pack}) ? $property->{pack} : 'C*';
            my $unpack = ($property->{unp})  ? $property->{unp}  : 'H*';
            my $fmat   = ($property->{fmat}) ? $property->{fmat} : '%s';
            #my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice))) . " packed with $pack, unpacked with $unpack, (hex " . unpack ('H*', pack ('C*', @slice)) . ") format $fmat";
            my $value = sprintf ($fmat, unpack ($unpack, pack ($pack, @slice)));
            
            readingsBulkUpdate( $hash, $reading, $value );
            Log3 $name, 4, "parse set reading $reading to $value" if (@data <= 20);
            }
        }
      readingsEndUpdate( $hash, 1 );
   }
    else
    {
        Log3 $name, 3, "Data len smaller than requested ($reqLen) : " . unpack ('H*', pack ('C*', @data));
        return 0;
    }
}

1;

Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 17 Dezember 2013, 21:03:06
Anbei noch ein Screenshot mit Grafiken, die man aus den Daten so einer Wärmepumpe erzeugen kann
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Dr. Boris Neubert am 20 Dezember 2013, 17:51:12
Hallo Stefan,

wenn Du das Modul bitte als Datei hier an Deinen Beitrag anhängst, packe ich es nach contrib.

Viele Grüße
Boris
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 21 Dezember 2013, 22:48:25
Anbei das Modul als Datei

Gruss und vielen Dank
    Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Dr. Boris Neubert am 22 Dezember 2013, 15:52:20
Hallo,

ist jetzt im contrib.

Viele Grüße
Boris
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Mietzi67 am 05 Oktober 2014, 12:34:49
Hallo Stefan,

sowas suche ich schon lange, vielen Dank! Hat auf Anhieb funktioniert.
Kannst Du bitte für Laien ein paar Codeschnipsel für die Plots zu Verfügung stellen?

Besten Dank,
Frank
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 05 Oktober 2014, 15:14:59
Hallo Frank,

freut mich wenn das Modul auch bei Dir gut funktioniert.
Die neueste Version ist übrigens im contrib.
Die Plots kannst Du Dir am einfachsten selbst zusammenklicken. Das ist viel einfacher als es in manchen alten Posts scheint.
Du wählst einfach Dein Filelog der Wärmepumpe aus und clickst dann auf den Link "Create SVG plot"
Dann geht alles sehr elegant über den Plot-Editor (angehängtes Bild)

Gruss
   Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Mietzi67 am 06 Oktober 2014, 21:57:09
Hallo Stefan,

danke für den Tipp. Die WP loggt jetzt fleissig in FHEM-Plots.
Musste dabei so meine Erfahrungen mit Datenmengen sammeln. Mit komplettem Log erreicht man ca. 3MB in 24h, daraus zu plotten bringt die FB7390 ziemlich an die Grenze ihrer Rechenleistung :o . Also Logdateien splitten ist angesagt.

Was mir noch vorschwebt: ich möchte ein Übersichtsbild der WP mittels FLOORPLAN visualisieren (ähnlich wie in der Waterkotte Software).
Hast Du eine Anregung, wie man die Readings der Variablen dem FLOORPLAN übergeben kann? (möglichst einzeln auswählbar)

Viele Grüße,
Frank
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 10 Oktober 2014, 18:57:26
Hallo Frank,

mit Floorplan habe ich leider auch noch nichts gemacht.
Wenn Du es hinbekommen hast, wäre es nett wenn Du es hier posten könntest :-)

Gruss
   Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: ak323 am 26 Mai 2015, 21:13:00
Hi Stefan,
ich will diesen Thread mal wieder hoch holen ...

Ich habe eine Waterkotte Ai1QE mit WWPR (Nachfolger vom CD4) und will diese über ModBus an FHEM anbinden.
Ich vermute Du nutzt auch ModBus RTU zur Kommunikation mit der Waterkotte ? Über RS485 oder RS232 ?

Zu Deinem Skrip habe ich eine Frage:
'Temp-Aussen'            => { addr => 0x0008, bytes => 0x0004, fmat => '%0.1f', unp => 'f<' },

"addr => 0x0008" ist die ModBus Adresse des Wertes welchen Du auslesen willst ? Korrekt ?
Beim WWPR sind die Adressen entsprechend anders aber auch 16 bit gem. Doku.

Ich habe eine Liste der Register des WWPR - theoretisch könnte ich Dein Script ja als Basis nehmen und nur die Register-Adressen anpassen ...  oder: hat das vielleicht schon mal jemand gemacht ?

Viele Grüße ak323
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: PEPITO82 am 27 Mai 2015, 08:20:48
Hallo ak323,

ich habe auch eine Waterkotte Ai1QE mit WWPR plus Webinterface.
Zur Kommunikation benutze ich Modbus TCP Modul aus folgendem Faden: http://forum.fhem.de/index.php/topic,12655.0.html
Für mich war auch der Wiki-Artikel zum Dimplex Wärmepumpenmanager hilfreich: http://www.fhemwiki.de/wiki/Dimplex_W%C3%A4rmepumpenmanager

Ich kann damit alle Werte die ich sonst nur im Webinterface hatte abfragen.
Außerdem kann ich den Heizbetrieb bzw. Warmwasser an- und ausschalten.
Vor allem letzteres war mir wichtig, da der WWPR keine zwei voneinander getrennten Zeiträume zulässt.
Dies ist nun möglich.

Vielleicht helfen Dir die Infos ja ein wenig weiter.

Viele Grüße

Peter

Vielleicht helfen Dir ja diese Infos.
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: ak323 am 27 Mai 2015, 15:03:17
Danke Peter !

Das Webinterface für die Waterkotte ist nur so verdampt teuer !
Das Dimplex pcoWeb kostet 300€, Waterkotte soweit ich weiß mehr als 450€ netto ...

Ich wollte halt das Dimplex Modbus Interface LWPM410 nehmen ... gibts für 115€ ....

VG, ak323
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: PEPITO82 am 27 Mai 2015, 15:27:56
Gibt es nicht vielleicht noch eine andere Variante, den Regler seriell auszulesen?

Habe meine Wärmepumpe gekauft als das neue Modell auf den Markt kam und das pcoweb als Dreingabe nachverhandelt.
Dieses wurde mir damals für 259 Euro netto angeboten.
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 28 Mai 2015, 18:09:36
Hallo,

Die CD4 Steuerung hatte leider noch kein Modbus.
Für Modbus habe ich aber im letzten Jahr ein neues Modul geschrieben, das sich recht leicht für die neueren Waterkotte Wärmepumpen verwenden lässt. Es funktioniert sowohl mit Modbus RTU über rs232 oder rs485 als auch mit Modbus TCP.
Siehe http://forum.fhem.de/index.php/topic,25315.0.html

Schau mal das Modul ModbusSET an. Es verwendet das generische Basismodul "Modbus" und definiert eigentlich nur die Register. Wenn Du die Daten für die neue Waterkotte  Wärmepumpe hast, kannst Du einfach ModbusSET als Vorlage nehmen. Alternativ könntest Du auch erst mal ein paar einzelne Werte mit dem Modul ModbusAttr definieren. Das basiert auf dem gleichen Basismodul. In der Commandref sind die Details beschrieben und im Wiki steht noch einiges mehr dazu:
http://www.fhemwiki.de/wiki/Modbus sowie http://www.fhemwiki.de/wiki/ModbusSET oder auch http://www.fhemwiki.de/wiki/ModbusAttr.
Ich persönlich würde ModbusSET nehmen und die Register anpassen. So sind auch die Module für verschiedene Stromzähler mit Modbus-Inteface entstanden.

Gruß
    Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: ak323 am 20 April 2016, 23:09:00
Hallo Stefan.
Nach fast nem Jahr habe ich mir jetzt endlich eine Modbus Interface-Karte für meine Waterkotte Ai1QE gegönnt und eingebaut. WWPR natürlich...
Ich versuche jetzt die Modbus Kommunikation zum Auslesen der mir bekannten Register zum Laufen zu bekommen ...
Leider scheitere ich gerade ein wenig dran !

Meinen USB - RS485 Converter habe ich so eingebunden:
define ModbusRS485 Modbus /dev/ttyUSB0@19200,8,N,2
define Waterkotte ModbusAttr 1 30


Und meiner Waterkotte mit der ID1 ein Abfrageintervall von 30s gegeben ...

Jetzt komme ich aber nicht weiter die Register auszulesen. Bspw. ist die Außentemperatur im Register 1 abgelegt ..
Wie definier ich nun die Abfrage .. ?

Stehe auf dem Schlauch ... Danke für Deine Hilfe !

ak323
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 23 April 2016, 09:04:03
Hallo aka323,

Marco (froy.de) hat die Waterkotte AI schon mit ModbusAttr am Laufen:
https://forum.fhem.de/index.php/topic,46944.msg397399.html#msg397399
Frag ihn doch mal ob er nicht die ganze Konfig posten kann.

Gruss
    Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: ak323 am 23 April 2016, 23:49:10
Danke Stefan für die Info.
Ich schätze Marco hat eine Waterkotte Ai1 mit der WPCU Steuerung .. meine Ai1QE hat den WWPR ..
Ich frage ihn mal an, vielleicht kann man das ja leicht anpassen ...

Ich habe jetzt Erfolg gehabt und kann nun die Register auslesen !
Ich verwende Deine ModbusSET als Vorlagen für meine ModbusWWPR ... Ich komme an alle Register ran .. muß jetzt nur noch an der Darstellung in FHEM arbeiten ...

Viele Grüße, ak323
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: ak323 am 30 April 2016, 22:21:33
Hi, ich habe mein Modbus Modul für die Wärmepumpen mit WWPR hier veröffentlicht:
https://forum.fhem.de/index.php/topic,52864.0.html (https://forum.fhem.de/index.php/topic,52864.0.html)
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: DodiHudori am 08 Januar 2017, 17:01:38
Hallo Stefan,

kannst du mir verraten wie du deine Waterkotte ans Netzwerk bekommen hast?
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 08 Januar 2017, 21:27:16
Dort wo die ganzen Kabel angeschlossen werden, ist auch ein Modem bzw. Rs232-Anschluss vorgesehen.
Im Modul habe ich am Anfang auch einige Links zu weiteren Infos hinterlegt.

Gruß
   Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 23 Februar 2017, 09:06:59
Guten Morgen zusammen!

Ich habe mir schon einen Wolf gesucht, aber ich bekomme das Gerät nicht definiert. Wenn ich versuche,die Wärmepumpe wie im Wiki angegeben über diesen Befehl:
define WP WKRCD4 /dev/vcom1@9600 60
anzulegen, dann bekomme ich nur die Fehlermeldung:
Unknown module WKRCD4

Im Ordner "/opt/fhem/contrib" finde ich die Datei "98_WKRCD4.pm". Ich habe auch schon wie verrückt gesucht, ob und wie ich Module aus dem contrib installieren/aktivieren muss, aber leider bis jetzt ohne Erfolg.

Kann mir bitte jemand einen Schubs in die richtige Richtung geben? Wo liegt mein Fehler und was mache ich falsch?

Vielen Dank schon mal für die Hilfe und dem Ersteller des Moduls für das Modul selbst! ;)
Bernd
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 23 Februar 2017, 21:07:49
Hallo,

Einfach das Modul aus dem contrib-Verzeichnis ins FHEM-Verzeichnis zu den anderen Modulen kopieren und dann Fhem neu starten. Dann sollte es klappen.

Gruß
   Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 24 Februar 2017, 12:52:18
Ahhhhhh ok - danke schön!
Das habe ich so nirgends gefunden. Und ich habe wirklich lange gesucht und versucht, bis ich hier gefragt habe. Da ist vielleicht aber auch die Wiki Seite https://wiki.fhem.de/wiki/Kategorie:Modul_(Contrib) (https://wiki.fhem.de/wiki/Kategorie:Modul_(Contrib)) etwas mager. Könnte dort vielleicht jemand einen kleinen Hinweis hinterlassen? Das wäre schon super.
Auch in der Einsteiger PDF findet sich das Wort "contrib" nur einmal:
ZitatEinchecken in den Zweig ,,contrib". Hier eingecheckte Module werden nicht in die fhemDistribution
aufgenommen, werden nicht über ,,update" verteilt und erscheinen auch nicht in
der commandref. Möchte ein user dieses Modul verwenden, muss es manuell aus dem SVN
heruntergeladen werden.
Jetzt im Nachhinein erscheint mir das alles logisch - das gebe ich zu - aber vorher stand ich wie ein Ochse vorm Berg. Auch ein Bekannter, der schon mehrere Jahre Erfahrung mit Fhem hat, konnte mir nicht sagen, wie man so ein Modul benutzt (hat er wahrscheinlich selber nie gebraucht).

Jetzt scheint die Definition zu funktionieren. Aber Fhem stürzt mir kurz später ab. Ich denke jedoch, dass dies an meiner RS232 liegt - ich habe mir ein RS232-LAN-Gateway USR-TCP232-302 gekauft und dies erstmal testweise über das Terminal vor dem define der Wärmepumpe in Fhem eingebunden:
sudo socat pty,link=/dev/vcom1,raw,echo=0 tcp:192.168.178.19:20108

Ich denke, dass ich mir erstmal den Raspi schnappen und direkt an die Wärmepumpe anschließen muss. Danach kann ich dann schauen, wo das Problem mit dem Gateway liegt.

Vielen Dank, dass du mir den gewünschten Schubs gegeben hast! ;)
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 09 Mai 2020, 22:56:11
Soooooo, einige Jahre später habe ich meine Waterkotte mit Resümat CD4 endlich mal korrekt eingebunden (jaaaa, ich habe es bis jetzt liegen lassen...).
Eine Sache ist mir aufgefallen: Der Status bleibt auf "WP idle", wenn die Warmwasser-Bereitung läuft. Ist das so gewollt? Die anderen Modi habe ich noch nicht testen können - weder Heizung, noch Kühlung. Muss ich mal ein bisschen die Einstellungen verändern und schauen, was dann mit dem Status passiert...

Was anderes: Kann ich irgendwie den Störungsfall mitbekommen? Ich würde mir gerne eine Push-Message schicken, wenn die WP aus irgendeinem Grund auf Störung gehen sollte.

Ansonsten sehr schönes Modul! Vielen Dank dafür!

Grüße, Cluni
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 10 Mai 2020, 13:03:55
Hallo Cluni,

Das Modul fragt die Waterkotte-Steuerung regelmäßig ab. Dabei kann man den Status nicht direkt abfragen, sondern nur die aktuelle Anzeige und die wechselt auch automatisch, so dass man den aktuellen Status eine ganze Weile verpassen kann (soweit ich mich erinnere - Meine Steuerung ist inzwischen kaputt gegangen und ich habe sie gegen eine neuere mit Modbus-Interface ausgetauscht)

Gruß
    Stefan

Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 11 Mai 2020, 11:07:49
Hallo Stefan,

vielen Dank für deine schnelle Antwort. Beim Modus Heizung bekomme ich z.B. "Heizung 28.9" (also mit der Temperatur des Vorlaufs). Scheint beim Warmwasser nicht so zu sein. Dann muss ich mir das mal in deinem Code ansehen.

Wie sich die drei Bytes von "Status-Heizung" zusammen setzen, kannst du mir nicht auf Anhieb sagen, oder? Darin ist nicht zufällig etwas enthalten, worüber man einen Ausfall bemerken könnte?

Gruß Bernd
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 11 Mai 2020, 11:52:53
Habe gerade mal ein wenig geschaut. Kann ich Dinge aus der Speicher-Adressen-Liste auf der Seite https://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=2 (https://www.haustechnikdialog.de/Forum/t/6144/Waterkotte-5017-3-an-den-Computer-anschliessen?page=2) einfach bei dir in das Array "$frameReadings" hinzufügen? Es gibt ja die Adressen:
0x0091 0x0003 07.00 Ausfall Zeit
0x0094 0x0003 07.01 Ausfall Datum
0x0097 0x0001 07.02 Ausfall Betriebszustaende
0x0098 0x0001 07.03 Ausfall DO Buffer
0x0099 0x0001 07.04 Ausfall DI Buffer
0x009A 0x0001 07.05 Ausfall AI Error
0x009B 0x0001 07.06 Ausfall AI DI
0x009C 0x0004 07.07 Ausfall AI Temp Aussen
0x00A0 0x0004 07.08 Ausfall AI Temp WQ Ein
0x00A4 0x0004 07.09 Ausfall AI Temp WQ Aus
0x00A8 0x0004 07.10 Ausfall AI Temp Verdampfer
0x00AC 0x0004 07.11 Ausfall AI Temp Heizung Ein
0x00B0 0x0004 07.12 Ausfall AI Temp Heizung Aus
0x00B4 0x0004 07.13 Ausfall AI Temp Kondensation
0x00B8 0x0004 07.14 Ausfall AI Temp Warmwasser
0x00BC 0x0001 07.15 Ausfall Term AI Error
0x00BD 0x0001 07.16 Ausfall Term AI Di
0x00BE 0x0004 07.17 Ausfall AI Temp Raum

Mit der Ausfallzeit und dem -datum könnte man ja schon arbeiten.

Würde es also reichen, wenn ich die Zeilen:
'Ausfall-Uhrzeit'        => { addr => 0x0091, bytes => 0x0003, fmat => '%3$02d:%2$02d:%1$02d', unp => 'CCC' },
'Ausfall-Datum'          => { addr => 0x0094, bytes => 0x0003, fmat => '%02d.%02d.%02d', unp => 'CCC'}

in deinem Array anhängen würde?

Gruß Bernd

EDIT: Hab's ausprobiert - scheint zu gehen. Oder fehlen mir noch wichtige zusätzliche Änderungen?
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 11 Mai 2020, 13:33:23
Den Fehler, dass bei der Warmwasserbereitung "WP Idle" angezeigt wurde, habe ich auch gefunden:

        my $Status = "WP idle";
        if (ReadingsVal($name, "Heizung", 0)) {
            $Status = sprintf ("Heizung %s", ReadingsVal ($name, "Temp-Vorlauf", 0));
        } elsif (ReadingsVal($name, "Kuehlung", 0)) {
            $Status = sprintf ("Kühlung %s", ReadingsVal ($name, "Temp-Vorlauf", 0));
        } elsif (ReadingsVal($name, "Kuehlung", 0)) {
            $Status = sprintf ("Warmwasser %s", ReadingsVal ($name, "Temp-WW", 0));
        }
        $Status = encode ("utf8", $Status);
        readingsBulkUpdate( $hash, "Status", $Status);
        readingsEndUpdate( $hash, 1 );


Im letzten elsif muss natürlich "Warmwasser" statt "Kuehlung" beim Auslesen der Readings stehen...
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 11 Mai 2020, 16:56:47
Hallo Cluni,

den Fix übernehme ich gerne. Dann checke ich einen neue Version ein.
In den Status-Bytes steht vermutlich auch noch was brauchbares drin.
Meine neue Steuerung von Waterkotte hat ähnliche Bytes, aber vermutlich ist das weder dokumentiert noch übertragbar.

Gruss
    Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: Cluni am 11 Mai 2020, 17:05:03
Hi Stefan,

warte nur erst noch. Ich implementiere noch das eine oder andere.

Oder soll ich die Weiterentwicklung übernehmen? Natürlich bleibst du mit drin! ;)

Gruß Bernd
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: StefanStrobel am 11 Mai 2020, 17:16:39
Hallo Bernd,

Du kannst das WKRCD4-Modul gerne übernehmen.
Ich habe die Steuerung ja selbst nicht mehr und bin mit der Weiterentwicklung der Module HTTPMOD, Modbus, Arducounter etc. genug beschäftigt :-)

Gruss
   Stefan
Titel: Antw:Modul für Waterkotte Wärmepumpe mit Resümat CD4 Steuerung
Beitrag von: alealdata am 11 Mai 2020, 17:20:53
Hi Stefan,

hättest du eine genauere Bezeichnung deines Modbus Interfaces für mich?