diff --git a/fhem/CHANGED b/fhem/CHANGED index 57b565810..8f4ce01a9 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -546,7 +546,7 @@ - feature: Command save retains now the order of the old config file - feature: List parameter added (list .* RFR_MSGCNT) -- =DATE= (4.9) +- 2010-03-13 (4.9) - bugfix: changed the fhem prompt from FHZ> to fhem> - bugfix: CUL_RFR fixes (chaining RFR's should work) - bugfix: Path in the examples fixed (got corrupted) @@ -576,3 +576,6 @@ - feature: pgm3: DBLog added for everything except UserDefs (Gerhard Pfeffer / MartinH) - feature: pgm2 style changes, SVG in background, optional compression + +- =DATE= (5.0) + - feature: KM271: Read only diff --git a/fhem/FHEM/00_KM271.pm b/fhem/FHEM/00_KM271.pm new file mode 100755 index 000000000..c19ac98d3 --- /dev/null +++ b/fhem/FHEM/00_KM271.pm @@ -0,0 +1,450 @@ +############################################## +package main; + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday); + +sub KM271_Read($); +sub KM271_Ready($); +sub KM271_OpenDev($); +sub KM271_CloseDev($); +sub KM271_SimpleWrite(@); +sub KM271_SimpleRead($); +sub KM271_crc($); +sub KM271_setbits($$); +sub KM271_Reading($$); + +my %sets = ( +); + +my $stx = pack('H*', "02"); +my $dle = pack('H*', "10"); +my $etx = pack('H*', "03"); +my $nak = pack('H*', "15"); +my $logmode = pack('H*', "EE00001003FD"); + +# Thx to Himtronics +# http://www.mikrocontroller.net/topic/141831 +# http://www.mikrocontroller.net/attachment/63563/km271-protokoll.txt +# Buderus documents: 63011376, 63011377, 63011378 +# http://www.buderus.de/pdf/unterlagen/0063061377.pdf +my %km271_trhash = +( + "8000" => 'Betriebswerte_1_HK1', # 76, 4 [repeat] + "8001" => 'Betriebswerte_2_HK1', # 0 (22:33), 2 (7:33) + "8002" => 'Vorlaufsolltemperatur_HK1', # 50-65 + "8003" => 'Vorlaufisttemperatur_HK1', # Schwingt um soll herum + "8004" => 'Raumsolltemperatur_HK1', # 34 (22:33) 42 (7:33) + "8005" => 'Raumisttemperatur_HK1', + "8006" => 'Einschaltoptimierungszeit_HK1', + "8007" => 'Ausschaltoptimierungszeit_HK1', + "8008" => 'Pumpenleistung_HK1', # 0/100 == Ladepumpe + "8009" => 'Mischerstellung_HK1', + "800a" => 'nicht_belegt', + "800b" => 'nicht_belegt', + "800c" => 'Heizkennlinie_HK1_bei_+_10_Grad', # bei Umschaltung tag/nacht + "800d" => 'Heizkennlinie_HK1_bei_0_Grad', # bei Umschaltung tag/nacht + "800e" => 'Heizkennlinie_HK1_bei_-_10_Grad', # bei Umschaltung tag/nacht + "800f" => 'nicht_belegt', + "8010" => 'nicht_belegt', + "8011" => 'nicht_belegt', + + "8112" => 'Betriebswerte_1_HK2', + "8113" => 'Betriebswerte_1_HK2', + "8114" => 'Vorlaufsolltemperatur_HK2', + "8115" => 'Vorlaufisttemperatur_HK2', + "8116" => 'Raumsolltemperatur_HK2', + "8117" => 'Raumisttemperatur_HK2', + "8118" => 'Einschaltoptimierungszeit_HK2', + "8119" => 'Ausschaltoptimierungszeit_HK2', + "811a" => 'Pumpenleistung_HK2', + "811b" => 'Mischerstellung_HK2', + "811c" => 'nicht_belegt', + "811d" => 'nicht_belegt', + "811e" => 'Heizkennlinie_HK2_bei_+_10_Grad', # == HK1 - (1 bis 3) + "811f" => 'Heizkennlinie_HK2_bei_0_Grad', # == HK1 - (1 bis 3) + "8120" => 'Heizkennlinie_HK2_bei_-_10_Grad', # == HK1 - (1 bis 3) + "8121" => 'nicht_belegt', + "8122" => 'nicht_belegt', + "8123" => 'nicht_belegt', + + "8424" => 'Betriebswerte_1_WW', + "8425" => 'Betriebswerte_2_WW', # 0 64 96 104 225 228 + "8426" => 'Warmwassersolltemperatur', # 10/55 + "8427" => 'Warmwasseristtemperatur', # 32-55 + "8428" => 'Warmwasseroptimierungszeit', + "8429" => 'Ladepumpe', # 0 1 (an/aus?) + + # 1377, page 13 + "882a" => 'Kesselvorlaufsolltemperatur', + "882b" => 'Kesselvorlaufisttemperatur', # == Vorlaufisttemperatur_HK1 + "882c" => 'Brennereinschalttemperatur', # 5-81 + "882d" => 'Brennerausschalttemperatur', # 19-85 + "882e" => 'Kesselintegral_1', # 0-23 + "882f" => 'Kesselintegral_2', # 0-255 + "8830" => 'Kesselfehler', + "8831" => 'Kesselbetrieb', # 0 2 32 34 + "8832" => 'Brenneransteuerung', # 0 1 (an/aus?) + "8833" => 'Abgastemperatur', + "8834" => 'modulare_Brenner_Stellwert', + "8835" => 'nicht_belegt', + "8836" => 'Brennerlaufzeit_1_Minuten_Byte2', + "8837" => 'Brennerlaufzeit_1_Minuten_Byte1', # 176 + "8838" => 'Brennerlaufzeit_1_Minuten_Byte0', # 0-255 (Minuten) + "8839" => 'Brennerlaufzeit_2_Minuten_Byte2', + "883a" => 'Brennerlaufzeit_2_Minuten_Byte1', + "883b" => 'Brennerlaufzeit_2_Minuten_Byte0', + + # 1377, page 16 + "893c" => 'Aussentemperatur', # 0 1 254 255 + "893d" => 'gedaempfte_Aussentemperatur', # 0 1 2 + "893e" => 'Versionsnummer_VK', + "893f" => 'Versionsnummer_NK', + "8940" => 'Modulkennung', + "8941" => 'nicht_belegt', +); + + +# Do not generate fhem events for the following high volume telegrams +# the % represents the relative nr of messages in an unfiltered stream. +# You can switch them on with attr all_km271_events +my %km271_ignore = ( + "Vorlaufisttemperatur_HK1" => 1, # 23% + "Kesselvorlaufisttemperatur" => 1, # 23%, same as Vorlaufisttemperatur_HK1 + "Kesselintegral_1" => 1, # 8%, ?? + "Kesselintegral_2" => 1, # 38%, ?? +); + +my @km271_Betriebswerte_1_HK = ( + "Ausschaltoptimierung", "Einschaltoptimierung", "Automatik", + "Warmwasservorrang", "Estrichtrocknung", "Ferien", "Frostschutz", "Manuell", +); +my @km271_Betriebswerte_2_HK = ( + "Sommer", "Tag", "keine Kommunikation mit FB", "FB fehlerhhaft", + "Fehler Vorlauffühler", "maximaler Vorlauf", "externer Störeingang", "frei", +); +my @km271_Betriebswerte_1_WW = ( + "Automatik", "Desinfektion", "Nachladung", "Ferien", "Fehler Desinfektion", + "Fehler Fuehler", "Fehler WW bleibt kalt", "Fehler Anode", +); +my @km271_Betriebswerte_2_WW = ( + "Laden", "Manuell", "Nachladen", "Ausschaltoptimierung", + "Einschaltoptimierung", "Tag", "Warm", "Vorrang", +); +my @km271_Kesselbetrieb = ( + "Tag", "Automatik", "Sommer", "Bit3", "Bit4", "Bit5", "Bit6", "Bit7", +); + + + +sub +KM271_Initialize($) +{ + my ($hash) = @_; + + $hash->{ReadFn} = "KM271_Read"; + $hash->{ReadyFn} = "KM271_Ready"; + + $hash->{DefFn} = "KM271_Define"; + $hash->{UndefFn} = "KM271_Undef"; + $hash->{SetFn} = "KM271_Set"; + $hash->{AttrList}= "do_not_notify:1,0 all_km271_events loglevel:0,1,2,3,4,5,6"; +} + +##################################### +sub +KM271_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + + return "wrong syntax: define KM271 [devicename|none]" + if(@a != 3); + + KM271_CloseDev($hash); + my $name = $a[0]; + my $dev = $a[2]; + + if($dev eq "none") { + Log 1, "KM271 device is none, commands will be echoed only"; + return undef; + } + + $hash->{DeviceName} = $dev; + my $ret = KM271_OpenDev($hash); + return $ret; +} + + +##################################### +sub +KM271_Undef($$) +{ + my ($hash, $arg) = @_; + KM271_CloseDev($hash); + return undef; +} + +##################################### +sub +KM271_Set($@) +{ + my ($hash, @a) = @_; + + return "\"set KM271\" needs at least one parameter" if(@a < 2); + return "Unknown argument $a[1], choose one of " . join(" ", sort keys %sets) + if(!defined($sets{$a[1]})); + + my $name = shift @a; + my $type = shift @a; + my $arg = join("", @a); + + return undef; +} + + +##################################### +# called from the global loop, when the select for hash->{FD} reports data +sub +KM271_Read($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + + my $buf = KM271_SimpleRead($hash); + Log GetLogLevel($name,5), "KM271 RAW: " . unpack('H*', $buf); + + if(!defined($buf)) { + Log 1, "$name: EOF"; + KM271_CloseDev($hash); + return; + } + + $buf = unpack('H*', $buf); + if($buf eq "02") { + $hash->{PARTIAL} = ""; + KM271_SimpleWrite($hash, $dle); + return; + } + + $hash->{PARTIAL} .= $buf; + my $len = length($hash->{PARTIAL}); + return if($hash->{PARTIAL} !~ m/^(.*)1003(..)$/); + my ($data, $crc) = ($1, $2); + if(KM271_crc($data) ne $crc) { + Log 1, "Wrong CRC in $hash->{PARTIAL}: $crc vs. ". KM271_crc($data); + $hash->{PARTIAL} = ""; + KM271_SimpleWrite($hash, $nak); + return; + } + KM271_SimpleWrite($hash, $dle); + + $data =~ s/1010/10/g; + if($data =~ m/^(8...)(..)/) { + my ($fn, $arg) = ($1, $2); + + my $msg = $km271_trhash{$fn}; + $msg = "UNKNOWN_$fn" if(!$msg); + my $tn = TimeNow(); + my $val = hex($arg); + my $ignore = $km271_ignore{$msg}; + + + if($msg =~ m/Aussentemperatur/) { + $val = $val-256 if($val > 128); + + } elsif($msg =~ m/Brennerlaufzeit_(.)_Minuten_Byte(.)/) { + my ($idx, $no) = ($1, $2); + + if($no == 2 || $no == 1) { + $ignore = 1; + + } else { + $msg = "Brennerlaufzeit_${idx}_Minuten"; + $val = KM271_Reading($hash, $msg . "_Byte2") * 65536 + + KM271_Reading($hash, $msg . "_Byte1") * 256 + + $val; + } + + } elsif($msg =~ m/Betriebswerte_1_HK/) { + $val = KM271_setbits($val, \@km271_Betriebswerte_1_HK); + + } elsif($msg =~ m/Betriebswerte_2_HK/) { + $val = KM271_setbits($val, \@km271_Betriebswerte_2_HK); + + } elsif($msg =~ m/Betriebswerte_1_WW/) { + $val = KM271_setbits($val, \@km271_Betriebswerte_1_WW); + + } elsif($msg =~ m/Betriebswerte_2_WW/) { + $val = KM271_setbits($val, \@km271_Betriebswerte_2_WW); + + } elsif($msg =~ m/Brenneransteuerung/) { + $val = ($val ? "an" : "aus"); + + } elsif($msg =~ m/Kesselbetrieb/) { + $val = KM271_setbits($val, \@km271_Kesselbetrieb); + + } + + Log GetLogLevel($name,4), "KM271 $name: $msg $val"; + $hash->{READINGS}{$msg}{TIME} = $tn; + $hash->{READINGS}{$msg}{VAL} = $val; + if(KM271_attr($name, "all_km271_events") || !$ignore) { + DoTrigger($name, "$msg: $val"); + } + + } elsif($data eq "04000701c4024192") { + # No data message + + } else { + Log 1, "$name: UNKNOWN $data"; + + } + $hash->{PARTIAL} = ""; +} + +##################################### +sub +KM271_Ready($) +{ + my ($hash) = @_; + + # This is relevant for windows/USB only + my $po = $hash->{Dev}; + my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags) = $po->status; + return ($InBytes>0); +} + +######################## +sub +KM271_SimpleWrite(@) +{ + my ($hash, $msg) = @_; + $hash->{Dev}->write($msg); +} + +######################## +sub +KM271_SimpleRead($) +{ + my ($hash) = @_; + + return $hash->{Dev}->input() if($hash->{Dev}); + return undef; +} + +######################## +sub +KM271_CloseDev($) +{ + my ($hash) = @_; + my $name = $hash->{NAME}; + my $dev = $hash->{DeviceName}; + + return if(!$dev); # "none" + + if($hash->{Dev}) { + $hash->{Dev}->close() ; + delete($hash->{Dev}); + + } + delete($selectlist{"$name.$dev"}); + delete($readyfnlist{"$name.$dev"}); + delete($hash->{FD}); +} + +######################## +sub +KM271_OpenDev($) +{ + my ($hash) = @_; + my $dev = $hash->{DeviceName}; + my $name = $hash->{NAME}; + my $po; + + $hash->{PARTIAL} = ""; + Log 3, "KM271 opening $name device $dev"; + + if ($^O=~/Win/) { + require Win32::SerialPort; + $po = new Win32::SerialPort ($dev); + } else { + require Device::SerialPort; + $po = new Device::SerialPort ($dev); + } + + if(!$po) { + Log(3, "Can't open $dev: $!"); + return ""; + } + $hash->{Dev} = $po; + if( $^O =~ /Win/ ) { + $readyfnlist{"$name.$dev"} = $hash; + } else { + $hash->{FD} = $po->FILENO; + delete($readyfnlist{"$name.$dev"}); + $selectlist{"$name.$dev"} = $hash; + } + + $po->reset_error(); + $po->baudrate(2400); + $po->databits(8); + $po->parity('none'); + $po->stopbits(1); + $po->handshake('none'); + $po->write($logmode); + + $hash->{STATE} = "Initialized"; + + Log 3, "$dev opened"; + return undef; +} + +sub +KM271_setbits($$) +{ + my ($val, $arr) = @_; + my $bit = 1; + my @ret; + + for(my $idx = 0; $idx < 8; $idx++) { + push(@ret, $arr->[$idx]) if($val & $bit); + $bit *= 2; + } + return "keine Bits gesetzt" if(!@ret); + return join(",", @ret); +} + +sub +KM271_crc($) +{ + my $in = shift; + my $x = 0; + foreach my $a (split("", pack('H*', $in))) { + $x ^= ord($a); + } + $x ^= 0x10; + $x ^= 0x03; + return sprintf("%02x", $x); +} + +sub +KM271_attr($$) +{ + my ($name, $attr) = @_; + return $attr{$name}{$attr} if($attr{$name} && $attr{$name}{$attr}); + return ""; +} + +sub +KM271_Reading($$) +{ + my ($hash, $msg) = @_; + return $hash->{READINGS}{$msg}{VAL} + if($hash->{READINGS} && $hash->{READINGS}{$msg}); + return 0; +} + + +1; diff --git a/fhem/contrib/README b/fhem/contrib/README index 4b1291bf2..5caf1d499 100755 --- a/fhem/contrib/README +++ b/fhem/contrib/README @@ -56,4 +56,6 @@ Peter's RRD support. See the HOWTO - serial.pm Serial line analyzer - +- km271.pl + Plain Buderus Logamatic 2107 communication module (KM271) logger + See the 00_KM271.pm fhem module for its successor. diff --git a/fhem/contrib/km271.pl b/fhem/contrib/km271.pl new file mode 100644 index 000000000..5bbcfaebb --- /dev/null +++ b/fhem/contrib/km271.pl @@ -0,0 +1,192 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday); + +sub kmcrc($); +sub fmt_now(); + + +my $stx = pack('H*', "02"); +my $dle = pack('H*', "10"); +my $etx = pack('H*', "03"); +my $nak = pack('H*', "15"); +my $logmode = pack('H*', "EE00001003FD"); + +# Thx to Himtronics +# http://www.mikrocontroller.net/topic/141831 +# http://www.mikrocontroller.net/attachment/63563/km271-protokoll.txt +# Buderus documents: 63011376, 63011377, 63011378 +# http://www.buderus.de/pdf/unterlagen/0063061377.pdf +my %trhash = +( + "8000" => 'Betriebswerte_1_HK1', # 76, 4 [repeat] + "8001" => 'Betriebswerte_2_HK1', # 0 (22:33), 2 (7:33) + "8002" => 'Vorlaufsolltemperatur_HK1', # 50-65 + "8003" => 'Vorlaufisttemperatur_HK1', # Schwingt um soll herum + "8004" => 'Raumsolltemperatur_HK1', # 34 (22:33) 42 (7:33) + "8005" => 'Raumisttemperatur_HK1', + "8006" => 'Einschaltoptimierungszeit_HK1', + "8007" => 'Ausschaltoptimierungszeit_HK1', + "8008" => 'Pumpenleistung_HK1', # 0/100 == Ladepumpe + "8009" => 'Mischerstellung_HK1', + "800a" => 'nicht_belegt', + "800b" => 'nicht_belegt', + "800c" => 'Heizkennlinie_HK1_bei_+_10_Grad', # bei Umschaltung tag/nacht + "800d" => 'Heizkennlinie_HK1_bei_0_Grad', # bei Umschaltung tag/nacht + "800e" => 'Heizkennlinie_HK1_bei_-_10_Grad', # bei Umschaltung tag/nacht + "800f" => 'nicht_belegt', + "8010" => 'nicht_belegt', + "8011" => 'nicht_belegt', + + "8112" => 'Betriebswerte_1_HK2', + "8113" => 'Betriebswerte_1_HK2', + "8114" => 'Vorlaufsolltemperatur_HK2', + "8115" => 'Vorlaufisttemperatur_HK2', + "8116" => 'Raumsolltemperatur_HK2', + "8117" => 'Raumisttemperatur_HK2', + "8118" => 'Einschaltoptimierungszeit_HK2', + "8119" => 'Ausschaltoptimierungszeit_HK2', + "811a" => 'Pumpenleistung_HK2', + "811b" => 'Mischerstellung_HK2', + "811c" => 'nicht_belegt', + "811d" => 'nicht_belegt', + "811e" => 'Heizkennlinie_HK2_bei_+_10_Grad', # == HK1 - (1 bis 3) + "811f" => 'Heizkennlinie_HK2_bei_0_Grad', # == HK1 - (1 bis 3) + "8120" => 'Heizkennlinie_HK2_bei_-_10_Grad', # == HK1 - (1 bis 3) + "8121" => 'nicht_belegt', + "8122" => 'nicht_belegt', + "8123" => 'nicht_belegt', + + "8424" => 'Betriebswerte_1_WW', + "8425" => 'Betriebswerte_2_WW', # 0 64 96 104 225 228 + "8426" => 'Warmwassersolltemperatur', # 10/55 + "8427" => 'Warmwasseristtemperatur', # 32-55 + "8428" => 'Warmwasseroptimierungszeit', + "8429" => 'Ladepumpe', # 0 1 (an/aus?) + + # 1377, page 13 + "882a" => 'Kesselvorlaufsolltemperatur', + "882b" => 'Kesselvorlaufisttemperatur', # == Vorlaufisttemperatur_HK1 + "882c" => 'Brennereinschalttemperatur', # 5-81 + "882d" => 'Brennerausschalttemperatur', # 19-85 + "882e" => 'Kesselintegral_1', # 0-23 + "882f" => 'Kesselintegral_2', # 0-255 + "8830" => 'Kesselfehler', + "8831" => 'Kesselbetrieb', # 0 2 32 34 + "8832" => 'Brenneransteuerung', # 0 1 (an/aus?) + "8833" => 'Abgastemperatur', + "8834" => 'modulare_Brenner_Stellwert', + "8835" => 'nicht_belegt', + "8836" => 'Brennerlaufzeit_1_Stunden_2', + "8837" => 'Brennerlaufzeit_1_Stunden_1', # 176 + "8838" => 'Brennerlaufzeit_1_Stunden_0', # 0-255 (Minuten) + "8839" => 'Brennerlaufzeit_2_Stunden_2', + "883a" => 'Brennerlaufzeit_2_Stunden_1', + "883b" => 'Brennerlaufzeit_2_Stunden_0', + + # 1377, page 16 + "893c" => 'Aussentemperatur', # 0 1 254 255 + "893d" => 'gedaempfte_Aussentemperatur', # 0 1 2 + "893e" => 'Versionsnummer_VK', + "893f" => 'Versionsnummer_NK', + "8940" => 'Modulkennung', + "8941" => 'nicht_belegt', +); + + +die("Usage: km271.pl \n") if(int(@ARGV) != 1); + +require Device::SerialPort; +my $po = new Device::SerialPort($ARGV[0]); +die("Can't open $ARGV[0]: $!\n") if(!$po); + +$po->reset_error(); +$po->baudrate(2400); +$po->databits(8); +$po->parity('none'); +$po->stopbits(1); +$po->handshake('none'); + +my $fdin = $po->FILENO; +printf("Setting device into logmode\n"); +$po->write($logmode); + + +$| = 1; +my $tbuf = ""; + +for(;;) { + my ($rout, $rin) = ('', ''); + + vec($rin, $fdin, 1) = 1; + + my $nfound = select($rout=$rin, undef, undef, undef); + die("Select error: $!\n") if(!defined($nfound) || $nfound < 0); + + if(vec($rout, $fdin, 1)) { + my $buf = $po->input(); + if(!defined($buf)) { + printf("EOF on dev\n"); + exit(1); + } + + $buf = unpack('H*', $buf); + #printf("%s DEV %s\n", fmt_now(), $buf); + if($buf eq "02") { + $tbuf = ""; + $po->write($dle); + next; + } + + $tbuf .= $buf; + my $len = length($tbuf); + next if($tbuf !~ m/^(.*)1003(..)$/); + my ($data, $crc) = ($1, $2); + if(kmcrc($data) ne $crc) { + printf("Wrong CRC in $tbuf ($crc vs. %s)\n", kmcrc($data)); + $tbuf = ""; + $po->write($nak); + next; + } + $po->write($dle); + + $data =~ s/1010/10/g; + if($data =~ m/^(8...)(..)/) { + my ($fn, $arg) = ($1, $2); + printf("%s %s %d\n", fmt_now(), $trhash{$fn}, hex($arg)); + } elsif($data eq "04000701c4024192") { + # No data message + } else { + printf("%s UNKNOWN %s\n", fmt_now(), $data); + } + $tbuf = ""; + + } +} + +sub +kmcrc($) +{ + my $in = shift; + my $x = 0; + foreach my $a (split("", pack('H*', $in))) { + $x ^= ord($a); + } + $x ^= 0x10; + $x ^= 0x03; + return sprintf("%02x", $x); +} + +sub +fmt_now() +{ + my $now = gettimeofday()+0.0; + my @t = localtime($now); + my $t = sprintf("%04d-%02d-%02d_%02d:%02d:%02d.%03d", + $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0], + ($now-int($now)) * 1000); + return $t; +} + diff --git a/fhem/docs/commandref.html b/fhem/docs/commandref.html index 393ec538b..fc451cfff 100644 --- a/fhem/docs/commandref.html +++ b/fhem/docs/commandref.html @@ -73,40 +73,42 @@ CUL   CUL_EM   CUL_FHTTK   - CUL_WS   CUL_RFR   + CUL_WS   + DS18S20   DbLog   EM   EMEM   EMGZ   EMWZ   + FHEMRENDERER   + FHEMWEB   FHT   FHZ   FS20   HMS   - FHEMWEB   IPWE   + KM271   KS300   + LGTV   LIRC   M232   M232Counter   M232Voltage   OWFS   OWTEMP   - DS18S20   SCIVT   - structure   - WS2000   - WS3600   SISPM   SIS_PMS   - WS300   - Weather   USF1000   + WS2000   + WS300   + WS3600   + Weather   X10   + structure   xxLG7000   - LGTV   - FHEMRENDERER   + @@ -2160,6 +2162,138 @@ A line ending with \ will be concatenated with the next one, so long lines
+ +

KM271

+ + + + + Define + +
+ + Set + +
+ + Get + +
+ + Attributes + +
+ + +

KS300