From bfb54c671496e5e7f18eac909a092b7f10390606 Mon Sep 17 00:00:00 2001 From: adamwit <> Date: Tue, 9 Dec 2014 19:12:41 +0000 Subject: [PATCH] 89_VCONTROL.pm: new module to control viessman heatings via optolink adapter git-svn-id: https://svn.fhem.de/fhem/trunk@7177 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/89_VCONTROL.pm | 1548 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1548 insertions(+) create mode 100644 fhem/FHEM/89_VCONTROL.pm diff --git a/fhem/FHEM/89_VCONTROL.pm b/fhem/FHEM/89_VCONTROL.pm new file mode 100644 index 000000000..3fea5d144 --- /dev/null +++ b/fhem/FHEM/89_VCONTROL.pm @@ -0,0 +1,1548 @@ +################################################################################# +# +# $Id$ +# +# FHEM Module for Viessman Vitotronic200 / Typ KW1 und KW2 +# +# Derived from 89_VCONTROL.pm: Copyright (C) Adam WItalla +# +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The GNU General Public License may also be found at http://www.gnu.org/licenses/gpl-2.0.html . +# +########################### +#package main; + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday); +use Time::Local; + +# Helper Constants +use constant NO_SEND => 9999; +use constant POLL_ACTIVE => 1; +use constant POLL_PAUSED => 0; +use constant READ_ANSWER => 1; +use constant READ_UNDEF => 0; +use constant GET_TIMER_ACTIVE => 1; +use constant GET_TIMER_PAUSED => 0; +use constant GET_CONFIG_ACTIVE => 1; +use constant GET_CONFIG_PAUSED => 0; + +#Poll Parameter +my $defaultPollInterval = 180; +my $last_cmd = 0; +my $poll_now = POLL_PAUSED; +my $get_timer_now = GET_TIMER_PAUSED; +my $get_config_now = GET_CONFIG_PAUSED; +my $command_config_file = ""; +#Send Parameter +my $send_now = NO_SEND; +my $send_additonal_param=""; + +#Get Parameter +#Answer Parameter +my $read_now = READ_UNDEF; + +#actually used command list +my @cmd_list; +my @poll_cmd_list; +my @write_cmd_list; +my @timer_cmd_list; +my @set_cmd_list; +my @get_timer_cmd_list; +#remember days for daystart values +my %DayHash; + +#States the Heater can be set to +my @mode = ("WW","RED","NORM","H+WW","H+WW FS","ABSCHALT"); +my $temp_mode=0; + +###################################################################################### +sub VCONTROL_1ByteUParse($$); +sub VCONTROL_1ByteSParse($$); +sub VCONTROL_2ByteSParse($$); +sub VCONTROL_2ByteUParse($$); +sub VCONTROL_2BytePercentParse($$); +sub VCONTROL_4ByteParse($$); +sub VCONTROL_timerParse($); +sub VCONTROL_ModusParse($); +sub VCONTROL_DateParse($); +sub VCONTROL_1ByteUConv($); +sub VCONTROL_1ByteSConv($); +sub VCONTROL_2ByteUConv($); +sub VCONTROL_2ByteSConv($); +sub VCONTROL_DateConv($); +sub VCONTROL_TimerConv($$); +sub VCONTROL_Clear($); +sub VCONTROL_Read($); +sub VCONTROL_Ready($); +sub VCONTROL_Parse($$$$); +sub VCONTROL_Poll($); +sub VCONTROL_CmdConfig($); + +sub +VCONTROL_Initialize($) +{ + my ($hash) = @_; + + require "$attr{global}{modpath}/FHEM/DevIo.pm"; + + $hash->{ReadFn} = "VCONTROL_Read"; + #$hash->{WriteFn} = "VCONTROL_Write"; + $hash->{ReadyFn} = "VCONTROL_Ready"; + $hash->{DefFn} = "VCONTROL_Define"; + $hash->{UndefFn} = "VCONTROL_Undef"; + $hash->{SetFn} = "VCONTROL_Set"; + $hash->{GetFn} = "VCONTROL_Get"; + $hash->{StateFn} = "VCONTROL_SetState"; + $hash->{ShutdownFn} = "VCONTROL_Shutdown"; + $hash->{AttrList} = "disable:0,1 setList closedev:0,1 ". $readingFnAttributes; +} + +##################################### +# define VIESSMANN [] + +sub +VCONTROL_Define($$) +{ + my ($hash, $def) = @_; + my @a = split("[ \t][ \t]*", $def); + my $po; + + if (@a != 4 && @a != 5) { + my $msg = "wrong syntax: define VCONTROL []"; + Log3 undef, 2, $msg; + return $msg; + } + + #Close Device to initialize properly + ###USB + if (index($a[2], ':') == -1) { + delete $hash->{USBDev}; + delete $hash->{FD}; + } + DevIo_CloseDev($hash); + + my $name = $a[0]; + my $dev = $a[2]; + + #check existence of config_file + if($a[3]){ + $command_config_file = $a[3]; + + if(-e $command_config_file){ + Log3 $name, 3, "VCONTROL: Define open DATEI '$command_config_file'"; + VCONTROL_CmdConfig($command_config_file); + } + else { + my $msg = "config file $command_config_file does not exist"; + Log3 undef, 2, $msg; + return $msg; + } + } + + #set command list to poll list + @cmd_list = @poll_cmd_list; + + #use configured Pollinterval if given + if($a[4]){ + $hash->{INTERVAL} = $a[4]; + } + else { + $hash->{INTERVAL} = $defaultPollInterval; + } + + $hash->{STATE} = "defined"; + $hash->{DeviceName} = $dev; + $hash->{PARTIAL} = ""; + + #Opening USB Device + Log3($name, 3, "VCONTROL opening VCONTROL device $dev"); + + ###USB + if (index($a[2], ':') == -1) { + + if ($^O=~/Win/) { + require Win32::SerialPort; + $po = new Win32::SerialPort ($dev); + } else { + require Device::SerialPort; + $po = new Device::SerialPort ($dev); + } + if(!$po) { + my $msg = "Can't open $dev: $!"; + Log3($name, 3, $msg) if($hash->{MOBILE}); + return $msg if(!$hash->{MOBILE}); + $readyfnlist{"$name.$dev"} = $hash; + return ""; + } + Log3($name, 3, "VCONTROL opened VCONTROL device $dev"); + + $hash->{USBDev} = $po; + if( $^O =~ /Win/ ) { + $readyfnlist{"$name.$dev"} = $hash; + } else { + $hash->{FD} = $po->FILENO; + delete($readyfnlist{"$name.$dev"}); + $selectlist{"$name.$dev"} = $hash; + } + + #Initialize to be able to receive data + VCONTROL_DoInit($hash, $po); + + } + else { + DevIo_OpenDev($hash, 0, undef); + VCONTROL_DoInit($hash, undef); + } + + + #set Internal Timer on Polling Interval + InternalTimer(gettimeofday()+1, "VCONTROL_Poll", $hash, 0); + return undef; + +} + +##################################### +# Input is hexstring +## This function will not be used until now! +#sub +#VCONTROL_Write($$) +#{ +# my ($hash,$fn,$msg) = @_; +# my $name = $hash->{NAME}; +# +# return if(!defined($fn)); +# +# my $bstring; +# $bstring = "$fn$msg"; +# Log3 $name, 5, "$hash->{NAME} sending $bstring"; +# +# DevIo_SimpleWrite($hash, $bstring, 1); +#} + + +##################################### +sub +VCONTROL_Undef($$) +{ + my ($hash, $arg) = @_; + my $name = $hash->{NAME}; + + foreach my $d (sort keys %defs) { + if(defined($defs{$d}) && + defined($defs{$d}{IODev}) && + $defs{$d}{IODev} == $hash) + { + my $lev = ($reread_active ? 4 : 2); + Log3 $name, $lev, "deleting port for $d"; + delete $defs{$d}{IODev}; + } + } + + DevIo_CloseDev($hash); + return undef; +} + +##################################### +sub +VCONTROL_Poll($) +{ + my $hash = shift; + #global Module Trigger that Polling is started + $poll_now=POLL_ACTIVE; + InternalTimer(gettimeofday()+$hash->{INTERVAL}, "VCONTROL_Poll", $hash, 0); +} + +##################################### +sub +VCONTROL_Shutdown($) +{ + my ($hash) = @_; + return undef; +} + +##################################### +sub +VCONTROL_SetState($$$$) +{ + my ($hash, $tim, $vt, $val) = @_; + return undef; +} + +sub +VCONTROL_Clear($) +{ + my $hash = shift; + my $buf; + + # clear buffer: + if($hash->{USBDev}) { + while ($hash->{USBDev}->lookfor()) { + $buf = DevIo_SimpleRead($hash); + } + } + if($hash->{TCPDev}) { + # TODO + return $buf; + } +} + +##################################### +sub +VCONTROL_DoInit($$) +{ + #Initialisation -> Send one 0x04 so the heating started to send 0x05 Synchonity-Bytes + my ($hash,$po) = @_; + my $name = $hash->{NAME}; + my $init = pack('H*', "04"); + + if ($po) + { + #set USB Device Parameter + $po->reset_error(); + $po->baudrate(4800); + $po->databits(8); + $po->parity('even'); + $po->stopbits(2); + $po->handshake('none'); + $po->write_settings; + } + $defs{$name}{STATE} = "Initialized"; + + DevIo_SimpleWrite($hash, $init, 0); + + Log3 $name, 3,"VCONTROL: Initialization"; + + return undef; +} + + +##################################### +# called from the global loop, when the select for hash->{FD} reports data +sub +VCONTROL_Read($) +{ + + my ($hash) = @_; + my $name = $hash->{NAME}; + Log3 $name, 5,"VCONTROL_READ"; + # count the commands to send for complete poll sequence + my $cmdcount = @cmd_list; + + #Read on Device + my $mybuf = DevIo_SimpleRead($hash); + + #USB device is disconnected try to connect again + if(!defined($mybuf) || length($mybuf) == 0) { + my $dev = $hash->{DeviceName}; + Log3 $name, 3,"VCONTROL: USB device $dev disconnected, waiting to reappear"; + $hash->{USBDev}->close(); + DoTrigger($name, "DISCONNECTED"); + + delete($hash->{USBDev}); + delete($selectlist{"$name.$dev"}); + $readyfnlist{"$name.$dev"} = $hash; # Start polling + $hash->{STATE} = "disconnected"; + + # Without the following sleep the open of the device causes a SIGSEGV, + # and following opens block infinitely. Only a reboot helps. + sleep(5); + return ""; + } + + #msg read on device + my $hexline = unpack('H*', $mybuf); + Log3 $name, 5,"VCONTROL: VCONTROL_Read '$hexline'"; + + #Append data to partial data we got before + + #ADW: 05 muss auch angehängt werden! + if ( $read_now == READ_ANSWER && $poll_now == POLL_ACTIVE ){ +# if ( $read_now == READ_ANSWER && $poll_now == POLL_ACTIVE && $hexline ne "05"){ + $hexline = $hash->{PARTIAL}.$hexline; + #if not received all bytes exit an read next + my $receive_len = hex(substr($cmd_list[$last_cmd][1],8,2))*2; + if ( length($hexline) < $receive_len ){ + Log3 $name, 5,"VCONTROL: VCONTROL_Read receive_len < $receive_len, $hexline"; + $hash->{PARTIAL} = $hexline; + return""; + } + } + + #exit if no poll period + #exit if no set command send + if ($poll_now == POLL_PAUSED && $send_now == NO_SEND ){ + return ""; } + + my $sendbuf=""; + #End of Poll Interval + if ($poll_now == POLL_ACTIVE && $last_cmd == $cmdcount) + { + Log3 $name, 5, "VCONTROL: End of Poll"; + $poll_now = POLL_PAUSED; + $last_cmd = 0; + @cmd_list = @poll_cmd_list; + $hash->{PARTIAL} = ""; + + #activate timer get list if questioned + if ($get_timer_now == GET_TIMER_ACTIVE && $send_now == NO_SEND ){ + @cmd_list = @get_timer_cmd_list; + VCONTROL_Poll($hash); + $get_timer_now = GET_TIMER_PAUSED; + } + + #reload config file if questioned + if ($get_config_now == GET_CONFIG_ACTIVE ){ + VCONTROL_CmdConfig($command_config_file); + @cmd_list = @poll_cmd_list; + $get_config_now = GET_CONFIG_PAUSED; + } + + my $closeAfterPoll = AttrVal($name, "closedev", "0"); + ###if Attribut to close after poll -> close + if ($closeAfterPoll == 1) { + delete $hash->{USBDev}; + delete $hash->{FD}; + Log3 $name, 3, "VCONTROL: USB device closed"; + } + + return ""; + }; + + #exit if buffer just filled with 0x05 but not for mode (0x05 is a definde mode state) + my $bufflen = length($hexline); + my $buffhalflen = $bufflen/2; + + if ( $bufflen > 2 && $hexline =~ /(05){$buffhalflen,}/ && $cmd_list[$last_cmd][2] ne "mode"){ + Log3 $name, 5, "VCONTROL: exit if buffer just filled with 0x05"; + $hash->{PARTIAL} = ""; + $read_now = READ_UNDEF; + return ""; } + + #if one 05 received we can send command + if ( length($hexline) == 2 && $hexline eq "05" && $read_now == READ_UNDEF) + { + my $sendstr =""; + #set next poll command + if ($poll_now == POLL_ACTIVE ){ + Log3 $name, 5, "VCONTROL: Setze sendstr"; + $sendstr = $cmd_list[$last_cmd][1]; + } + + # no polling active but set command was given + if ($poll_now == POLL_PAUSED && $send_now != NO_SEND ){ + $sendstr = $write_cmd_list[$send_now][2]."$send_additonal_param"; + } + + if ( $sendstr && $sendstr ne "" ){ + Log3 $name, 5, "VCONTROL: send '$sendstr'"; + $sendbuf = pack('H*', "$sendstr"); + + #Send on Device + DevIo_SimpleWrite($hash, $sendbuf, 0); + + #we have send cmd next receive should be answer + $read_now = READ_ANSWER; + } + else { #wenn wir hier reinrutschen ist etwas mit den listen durcheinander geraten, workaround reset der liste und der commands! + Log3 $name, 5, "VCONTROL: List reset!"; + $poll_now = POLL_PAUSED; + $last_cmd = 0; + @cmd_list = @poll_cmd_list; + $hash->{PARTIAL} = ""; + $get_timer_now = GET_TIMER_PAUSED; + $get_config_now = GET_CONFIG_PAUSED; + } + } + elsif ( $read_now == READ_ANSWER) #we expect answer on before send command + { + if ($poll_now == POLL_ACTIVE && $hexline ne "05"){ + VCONTROL_Parse($hash,$last_cmd,$hexline,0); + $last_cmd++; + $temp_mode = 0; + } + #if the mode is requestet and 0x05 is received + #try again to be sure that 0x05 is not the sync byte + elsif ($poll_now == POLL_ACTIVE && $cmd_list[$last_cmd][2] eq "mode" && substr("$hexline",0,2) eq "05" ){ + Log3 $name, 5, "VCONTROL: check temp_mode"; + if ($temp_mode < 5){ + $temp_mode++; + Log3 $name, 5, "VCONTROL: set temp_mode = $temp_mode"; + } + elsif ($temp_mode == 5){ + $temp_mode = 0; + VCONTROL_Parse($hash,$last_cmd,$hexline,0); + Log3 $name, 5, "VCONTROL: set mode = ABSCHALT"; + $last_cmd++; + } + } + + #parse answer on set command + if ($poll_now == POLL_PAUSED && $send_now != NO_SEND ){ + VCONTROL_Parse($hash,$send_now,$hexline,1) if ($hexline ne "05"); + } + $read_now = READ_UNDEF; + $hash->{PARTIAL} = ""; + } +} + +##################################### +sub +VCONTROL_Parse($$$$) +{ + my ($hash, $cmd, $hexline,$answer) = @_; + + my $value = ""; + my $valuename = ""; + my $pn = $hash->{NAME}; + + if ($answer == 0){ + if ($cmd_list[$cmd][2] eq "1ByteU"){ + $value = VCONTROL_1ByteUParse(substr($hexline, 0, 2),$cmd_list[$cmd][3]) if (length($hexline) > 1); + } elsif ($cmd_list[$cmd][2] eq "1ByteS"){ + $value = VCONTROL_1ByteSParse(substr($hexline, 0, 2),$cmd_list[$cmd][3]) if (length($hexline) > 1); + } elsif ($cmd_list[$cmd][2] eq "2ByteS"){ + $value = VCONTROL_2ByteSParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 3); + } elsif ($cmd_list[$cmd][2] eq "2ByteU"){ + $value = VCONTROL_2ByteUParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 3); + } elsif ($cmd_list[$cmd][2] eq "2BytePercent"){ + $value = VCONTROL_2BytePercentParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 1); + } elsif ($cmd_list[$cmd][2] eq "4Byte"){ + $value = VCONTROL_4ByteParse($hexline,$cmd_list[$cmd][3]) if (length($hexline) > 7); + } elsif ($cmd_list[$cmd][2] eq "mode"){ + $value = VCONTROL_ModeParse($hexline) if (length($hexline) > 1); + } elsif ($cmd_list[$cmd][2] eq "timer"){ + $value = VCONTROL_timerParse($hexline) if (length($hexline) > 7); + } elsif ($cmd_list[$cmd][2] eq "date"){ + $value = VCONTROL_DateParse($hexline) if (length($hexline) > 7); + } + + #this will be the name of the Reading + $valuename = "$cmd_list[$cmd][4]"; + Log3 $pn, 5,"VCONTROL: receive '$valuename : $value'"; + + return $pn if ($value eq ""); + + if ( $cmd_list[$cmd][2] + && $cmd_list[$cmd][2] ne "mode" + && $cmd_list[$cmd][2] ne "timer" + && $cmd_list[$cmd][3] ne "state" + && $cmd_list[$cmd][3] > 99){ + $value = sprintf("%.2f", $value); + } + + #TODO config Min and Max Values ???? + if ( substr($valuename,0,4) eq "Temp"){ + if ( $value < -30 || $value > 199 ){ + $value = ReadingsVal($pn,"$valuename",0); + } + } + + #get systemtime + my ($sec,$min,$hour,$mday,$mon,$year) = localtime; + $year+=1900; + $mon = $mon+1; + my $plotmonth = $mon; + my $plotmday = $mday; + my $plothour = $hour; + my $plotmin = $min; + my $plotsec = $sec; + if ($mon < 10) {$plotmonth = "0$mon"}; + if ($mday < 10) {$plotmday = "0$mday"}; + if ($hour < 10) {$plothour = "0$hour"}; + if ($min < 10) {$plotmin = "0$min"}; + if ($sec < 10) {$plotsec = "0$sec"}; + my $systime="$year-$plotmonth-$plotmday"."_"."$plothour:$plotmin:$plotsec"; + + #Start Update Readings + readingsBeginUpdate ($hash); + readingsBulkUpdate ($hash, "$valuename", $value); + + #calculate Kumulation Readings and Day Readings + + if ("$cmd_list[$cmd][5]" eq "day" ){ + my $start_of_the_day; + if ( $value < 0 ){ + $value = ReadingsVal($pn,"$valuename",0); + } + + $value = sprintf("%.2f", $value); + $start_of_the_day = ReadingsVal($pn,"$valuename"."DayStart",$value); + my $kumul_day = $value - $start_of_the_day; + $kumul_day = sprintf("%.2f", $kumul_day); + readingsBulkUpdate ($hash, "$valuename"."Today", $kumul_day); + + #Next Day for this value is reached + my $debug_day= $DayHash{$valuename}; + Log3 $pn, 5, "VCONTROL: DEBUG nextday $mday <-> $debug_day"; + if ($mday != $DayHash{$valuename}){ + $start_of_the_day = $value; + $start_of_the_day = sprintf("%.2f", $start_of_the_day); + readingsBulkUpdate ($hash, "$valuename"."LastDay" , $kumul_day); + $kumul_day = 0; + $DayHash{$valuename} = $mday; + } + readingsBulkUpdate ($hash, "$valuename"."DayStart" , $start_of_the_day); + } + + #if all polling commands are send, update Reading UpdateTime + my $all_cmd = @cmd_list -1; + if ( $cmd == $all_cmd){ + readingsBulkUpdate ($hash, "UpdateTime", $systime ); + } + #End Update Reading + readingsEndUpdate ($hash, 1); + + } + else #answer on set request + { + #Start Poll to refresh readings if send of set request was answered with 00 + # and no additional send has to be done + if (substr($hexline, 0, 2) == "00") + { + # it may be configured that another command has to be send + my $next_send = NO_SEND; + foreach(@write_cmd_list) { + if ($$_[0] eq "SET" && $$_[1] eq $write_cmd_list[$send_now][4]){ + $next_send=$$_[5]; + } + } + + if ($next_send == NO_SEND){ + #activate timer get list if questioned + if ($get_timer_now == GET_TIMER_ACTIVE ){ + @cmd_list = @get_timer_cmd_list; + $get_timer_now = GET_TIMER_PAUSED; + } + VCONTROL_Poll($hash) if (substr($hexline, 0, 2) == "00"); + } + $send_now = $next_send; + } + } + + return $pn; + +} + + +##################################### +sub +VCONTROL_Ready($) +{ + my ($hash) = @_; + my $dev = $hash->{DeviceName}; + my $name = $hash->{NAME}; + + my $po; + + ###USB + if (index($dev, ':') == -1) { + $po=$hash->{USBDev}; + if(!$po) { # Looking for the device + if ($^O=~/Win/) { + $po = new Win32::SerialPort ($dev); + } else { + $po = new Device::SerialPort ($dev); + } + return undef if(!$po); + + Log3 $name, 3, "VCONTROL: USB device $dev reappeared"; + $hash->{USBDev} = $po; + if( $^O !~ /Win/ ) { + $hash->{FD} = $po->FILENO; + delete($readyfnlist{"$name.$dev"}); + $selectlist{"$name.$dev"} = $hash; + } else { + $readyfnlist{"$name.$dev"} = $hash; + } + $hash->{PARTIAL} = ""; + VCONTROL_DoInit($hash, $po); + DoTrigger($name, "CONNECTED"); + return undef; + } + } else { + $hash->{PARTIAL} = ""; + DevIo_OpenDev($hash, 1, undef); + return undef if(!exists($hash->{FD})); + return undef if(!defined($_[0]->{TCPDev})); + VCONTROL_DoInit($hash, undef); + DoTrigger($name, "CONNECTED"); + return undef; + } + + + # This is relevant for windows only + if (index($dev, ':') == -1) { + return undef if !$po; + my ($BlockingFlags, $InBytes, $OutBytes, $ErrorFlags)=$po->status; + return ($InBytes>0); + } +} + +sub +VCONTROL_Set($@) +{ + my ($hash, @a) = @_; + my $pn = $hash->{NAME}; + my $arg = $a[1]; + my $value = (defined $a[2]) ? $a[2] : ""; + + my $setList = AttrVal($pn, "setList", " "); + + #return "Unknown argument ?, choose one of HWW ABSCHALT SPAR-ON SPAR-OFF PARTY-ON PARTY-OFF" if( $arg eq "?"); + return "Unknown argument ?, choose one of $setList" if( $arg eq "?"); + + #needed if cmd in config_file is just a prefix, e.g. set of an timer value + $send_additonal_param=""; + + #set write commands to send + foreach(@write_cmd_list) { + my $debug_info0=$$_[0]; + my $debug_info1=$$_[1]; + Log3 $pn, 5, "VCONTROL: DEBUG SET <-> $debug_info0 / $arg <-> $debug_info1"; + if ($$_[0] eq "SET" && $$_[1] eq $arg){ + $send_now=$$_[5]; + + if ($$_[3] eq "1ByteU"){ + $send_additonal_param=VCONTROL_1ByteUConv($value); + } + elsif ($$_[3] eq "1ByteS"){ + $send_additonal_param=VCONTROL_1ByteSConv($value); + } + elsif ($$_[3] eq "2ByteU"){ + $send_additonal_param=VCONTROL_2ByteUConv($value); + } + elsif ($$_[3] eq "2ByteS"){ + $send_additonal_param=VCONTROL_2ByteSConv($value); + } + elsif ($$_[3] eq "date"){ + my $strtemp = VCONTROL_DateConv($value); + Log3 $pn, 5, "VCONTROL: DEBUG Timestr: $strtemp"; + $send_additonal_param=$strtemp; + } + elsif ($$_[3] eq "timer"){ + my $tempday = $$_[4]; + $send_additonal_param=VCONTROL_TimerConv($tempday,$value); + @get_timer_cmd_list = @timer_cmd_list; + $get_timer_now = GET_TIMER_ACTIVE; + } + + return ""; + } + } + + # possible to correct DayStart Values + if(index($arg,"DayStart") >= 0){ + if ( $value ne "" ) + { + readingsBeginUpdate ($hash); + readingsBulkUpdate ($hash, $arg, $value); + readingsEndUpdate ($hash, 1); + } + + } + + #else { + # print "not data_ready: $arg \n"; + #} + return ""; +} + +sub VCONTROL_Get($@) { + my ($hash, @a) = @_; + return "no get value specified" if(@a < 2); + + my $pn = $hash->{NAME}; + my $arg = $a[1]; + my $value = (defined $a[2]) ? $a[2] : ""; + + return "Unknown argument ?, choose one of TIMER CONFIG" if( $arg eq "?"); + + if ($arg eq "TIMER" ) + { + @get_timer_cmd_list = @timer_cmd_list; + } + elsif ($arg eq "CONFIG" ) + { + if ($poll_now == POLL_PAUSED ){ + VCONTROL_CmdConfig($command_config_file); + @cmd_list = @poll_cmd_list; + } + else { $get_config_now = GET_CONFIG_ACTIVE; } + return ""; + } + + if ($poll_now == POLL_PAUSED ){ + @cmd_list = @get_timer_cmd_list; + VCONTROL_Poll($hash); + } + else { $get_timer_now = GET_TIMER_ACTIVE; } + + + return ""; +} + +##################################### +##################################### +## Load Config +##################################### +##################################### +sub VCONTROL_CmdConfig($) +{ + + my $cmd_config_file = shift; + + my ($sec,$min,$hour,$mday,$mon,$year) = localtime; + my $write_idx=0; + Log3 undef, 3, "VCONTROL: open DATEI '$cmd_config_file'"; + open(CMDDATEI,"<$cmd_config_file") || die "problem opening $cmd_config_file\n" ; + + undef @poll_cmd_list; + undef @write_cmd_list; + undef @timer_cmd_list; +# undef @timer_ww_cmd_list; + + while(){ + my $zeile=trim($_); + Log3 undef, 5, "VCONTROL: CmdConfig-Zeile $zeile"; + if ( length($zeile) > 0 && substr($zeile,0,1) ne "#") + { + my @cfgarray = split(",",$zeile); + + foreach(@cfgarray) { + $_ = trim($_); + } + + #TODO: CHECK IF CONFIG PARAMS are allowed!!! + if ($cfgarray[0] eq "POLL"){ + if ( $cfgarray[2] ne "1ByteU" + && $cfgarray[2] ne "1ByteS" + && $cfgarray[2] ne "2ByteS" + && $cfgarray[2] ne "2ByteU" + && $cfgarray[2] ne "2BytePercent" + && $cfgarray[2] ne "4Byte" + && $cfgarray[2] ne "mode" + && $cfgarray[2] ne "date" + && $cfgarray[2] ne "timer" + ){ + Log3 undef, 3, "VCONTROL: unknown parse method '$cfgarray[2]' in '$cmd_config_file'"; + } + elsif( index($cfgarray[1],"01F7") == -1 || length($cfgarray[1]) < 10 ){ + Log3 undef, 3, "VCONTROL: wrong Address '$cfgarray[1]' in '$cmd_config_file'"; + } + else { + if ($cfgarray[2] eq "timer") + { + my @timercmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$cfgarray[5]); + push(@timer_cmd_list,\@timercmd); + } + else { + my @pollcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$cfgarray[5]); + push(@poll_cmd_list,\@pollcmd); + if ("$cfgarray[5]" eq "day"){ + $DayHash{$cfgarray[4]} = $mday; + } + } + } + } + elsif ($cfgarray[0] eq "SET"){ + if ($cfgarray[3] eq "timer") + { + if ( $cfgarray[4] ne "MO" + && $cfgarray[4] ne "DI" + && $cfgarray[4] ne "MI" + && $cfgarray[4] ne "DO" + && $cfgarray[4] ne "FR" + && $cfgarray[4] ne "SA" + && $cfgarray[4] ne "SO" + ) + { Log3 undef, 1, "VCONTROL: wrong Day '$cfgarray[4]' in '$cmd_config_file'"; + } + else { + my @setcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$write_idx); + push(@write_cmd_list,\@setcmd); + $write_idx++; + } + } + else { + my @setcmd = ($cfgarray[0],$cfgarray[1],$cfgarray[2],$cfgarray[3],$cfgarray[4],$write_idx); + push(@write_cmd_list,\@setcmd); + $write_idx++; + } + } + else{ + Log3 undef, 3, "VCONTROL: unknown command '$cfgarray[0]' in '$cmd_config_file'"; + } + } + }; + +close (CMDDATEI); +Log3 undef, 3, "VCONTROL: DATEI '$cmd_config_file' refreshed"; +} + +########################################################################### +########################################################################### +### PARSE ROUTINES +########################################################################### +########################################################################### +sub VCONTROL_1ByteUParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + my $retstr=""; + + if (!$divisor || length($divisor) == 0 || $divisor eq "state"){ + $retstr = ($hexvalue eq "00") ? "off" : "on"; + } + else{ + #check if divisor is numeric and not 0 + if ( $divisor =~ /^\d+$/ && $divisor != 0){ + $retstr = hex($hexvalue)/$divisor; + } + else { + Log3 undef, 3, "VCONTROL: divisor not numeric '$divisor' or 0, it will be ignored"; + $retstr = hex($hexvalue) + } + } + return $retstr; +} +##################################### +sub VCONTROL_1ByteSParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + + return unpack('c', pack('C',hex(substr($hexvalue,0,2))))/$divisor; +} +##################################### +sub VCONTROL_2ByteUParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + + return hex(substr($hexvalue,2,2).substr($hexvalue,0,2))/$divisor; +} +##################################### +sub VCONTROL_2ByteSParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + + return unpack('s', pack('S',hex(substr($hexvalue,2,2).substr($hexvalue,0,2))))/$divisor; +} +##################################### +sub VCONTROL_2BytePercentParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + + return hex(substr($hexvalue,2,2))/$divisor; +} +##################################### +sub VCONTROL_4ByteParse($$) +{ + my $hexvalue = shift; + my $divisor = shift; + + return hex(substr($hexvalue,6,2).substr($hexvalue,4,2).substr($hexvalue,2,2).substr($hexvalue,0,2))/$divisor; + +} +##################################### +sub VCONTROL_ModeParse($) +{ + my $index = hex(shift); + return "$mode[$index]" if ($mode[$index]); + + return ""; +} +##################################### +sub VCONTROL_timerParse($) +{ + my $binvalue = shift; + $binvalue = pack('H*', "$binvalue"); + + my ($h1,$h2,$h3,$h4,$h5,$h6,$h7,$h8) = unpack ("CCCCCCCC",$binvalue); + my @bytes = ($h1,$h2,$h3,$h4,$h5,$h6,$h7,$h8); + my $timer_str; + + for ( $a = 0; $a < 8; $a = $a+1){ + my $delim = "-"; + if ( $a % 2 ){ + $delim = "/"; + } + + my $byte = $bytes[$a]; + if ($byte == 0xff){ + $timer_str = $timer_str."--$delim"; + } + else{ + my $hour = ($byte & 0xF8)>>3; + my $min = ($byte & 7)*10; + + $hour = "0$hour" if ( $hour < 10 ); + $min = "0$min" if ( $min < 10 ); + + $timer_str = $timer_str."$hour:$min$delim"; + } + } + + return "$timer_str"; + +} +##################################### +sub VCONTROL_DateParse($){ + + my $hexvalue = shift; + my $vcday; + + #0011223344556677 + #01 23 45 67 89 01 23 45 + $vcday = "So" if ( substr($hexvalue,8,2) eq "00" ); + $vcday = "Mo" if ( substr($hexvalue,8,2) eq "01" ); + $vcday = "Di" if ( substr($hexvalue,8,2) eq "02" ); + $vcday = "Mi" if ( substr($hexvalue,8,2) eq "03" ); + $vcday = "Do" if ( substr($hexvalue,8,2) eq "04" ); + $vcday = "Fr" if ( substr($hexvalue,8,2) eq "05" ); + $vcday = "Sa" if ( substr($hexvalue,8,2) eq "06" ); + $vcday = "So" if ( substr($hexvalue,8,2) eq "07" ); + + return $vcday.",".substr($hexvalue,6,2).".".substr($hexvalue,4,2).".".substr($hexvalue,0,4)." ".substr($hexvalue,10,2).":".substr($hexvalue,12,2).":".substr($hexvalue,14,2); + +} + +########################################################################### +########################################################################### +## CONV ROUTINES +########################################################################### +########################################################################### +sub VCONTROL_1ByteUConv($) +{ + my $convvalue = shift; + return (sprintf "%X", $convvalue); +} +##################################### +sub VCONTROL_1ByteSConv($) +{ + my $convvalue = shift; + my $cnvstrvalue = (sprintf "%02X", $convvalue); + if ($convvalue <0){ + return substr($cnvstrvalue,6,2); + } + else { + return $cnvstrvalue; + } +} +##################################### +sub VCONTROL_2ByteUConv($) +{ + my $convvalue = shift; + my $hexstr = (sprintf "%04X", $convvalue); + return substr($hexstr,2,2).substr($hexstr,0,2); +} +##################################### +sub VCONTROL_2ByteSConv($) +{ + my $convvalue = shift; + my $cnvstrvalue = (sprintf "%04X", $convvalue); + if ($convvalue <0){ + return substr($cnvstrvalue,6,2).substr($cnvstrvalue,4,2); + } + else { + return substr($cnvstrvalue,2,2).substr($cnvstrvalue,0,2); + } +} +##################################### +sub VCONTROL_DateConv($){ + #Eingabe + #dd.mm.yyyy_hh:mm:ss + #Ziel + #yyyymmddwwhhmmss + + #dd.mm.yyyy + my $date = shift; + my $vcday = substr($date,0,2); + my $vcmonth = substr($date,3,2); + my $vcyear = substr($date,6,4); + #hh:mm:ss + my $vchour = substr($date,11,2); + my $vcmin = substr($date,14,2); + my $vcsec = substr($date,17,2); + my $wday; + my $tmp; + my $hlptime = timelocal($vcsec, $vcmin, $vchour, $vcday, $vcmonth -1 , $vcyear - 1900); + ($tmp, $tmp, $tmp, $tmp, $tmp, $tmp, $wday) = localtime $hlptime; + + my @Wochentage = ("00","01","02","03","04","05","06"); + $wday = $Wochentage[$wday]; + + #0011223344556677 + #01 23 45 67 89 01 23 45 + return $vcyear.$vcmonth.$vcday.$wday.$vchour.$vcmin.$vcsec; + +} +##################################### +sub VCONTROL_TimerConv($$){ + + my $timer_day = shift; + my $value = shift; + my @timerarray = split(",",$value); + + return "" if (@timerarray != 8); + + my @hextimerdata; + foreach(@timerarray) { + if ($_ eq "--"){ + push(@hextimerdata,"FF"); + } + else{ + my ($timerhour, $timermin) = split(":",$_,2); + if (length($timerhour) != 2 || length($timermin) != 2 ){ + {return "";} + } + + if ( $timerhour < "00" || $timerhour > "23" ){ + {return "";} + } + + if ( $timermin ne "00" && $timermin ne "10" && $timermin ne "20" && $timermin ne "30" && $timermin ne "40" && $timermin ne "50"){ + {return "";} + } + + my $helpvalue = (($timerhour <<3) + ($timermin/10)) & 0xff; + push(@hextimerdata, (sprintf "%X", $helpvalue)); + } + } + + my $suffix=""; + foreach (@hextimerdata){ + $suffix = "$suffix"."$_"; + } + + return $suffix; +} +1; + +=pod +=begin html + + +

VCONTROL

+
    + VCONTROL is the fhem-Modul to control and read information from a VIESSMANN heating via Optolink-adapter.

    + + An Optolink-Adapter is necessary (USB or LAN), you will find information here:
    + http://openv.wikispaces.com/

    + + Additionaly you need to know Memory-Adresses for the div. heating types (e.g. V200KW1, VScotHO1, VPlusHO1 ....),
    + that will be read by the module to get the measurements or to set the actual state.
    + Additional information you will fin in the forum http://openv.wikispaces.com/ and on the following wiki page http://openv.wikispaces.com/


    + + Define +
      + define <name> VCONTROL <serial-device/LAN-Device:port> <configfile> [<intervall>]
      +
      +
    • <serial-device/LAN-Device:port>
      + USB Port (e.g. com4, /dev/ttyUSB3) or TCPIP:portnumber
      +
    • + +
    • <intervall>
      + Poll Intervall in seconds (default 180)
      +
    • + +
    • <configfile>
      + path to the configuration file, containing the memory addresses
      +
    • +
      + Example:

      + + serial device com4, every 3 minutes will be polled, configuration file name is 99_VCONTROL.cfg, existing in the fhem root directory

      + + Windows:
      + define Heizung VCONTROL com4 99_VCONTROL.cfg 180

      + + Linux:
      + define Heizung VCONTROL /dev/ttyUSB3 99_VCONTROL.cfg 180
      + +
    +

    + + Set +
      + These commands will be configured in the configuartion file. +
    +

    + Get +
      + get <name> CONFIG

      + reload the module specific configfile

      + + More commands will be configured in the configuartion file. +
    +

    + + configfile +
      + You will find Examples for the configuration file for the heating types V200KW1, VScotHO1, VPlusHO1 on the wiki page http://openv.wikispaces.com/.

      + + The lines of the configuration file can have the following structure:

      + +
    • lines beginning with "#" are comments!
    • +
    • Polling Commands (POLL) to read values.
    • +
    • Set Commandos (SET) to set values.
    • +
      + Polling Commands have the following structure:

      + + POLL, ADDRESSE, PARSEMETHODE, DIVISOR, READING-NAME, KUMULATION

      + +
        +
      • POLL
        + is fix POLL
        +
      • +
        +
      • ADDRESSE
        + Memory Address leading to the value, the will be read in the memory on the heating.
        + It is subdivided in 3 parts:
        +
          +
        • Beginning is fix 01F7 (defines a reading command)
        • +
        • followed by actuak address
        • +
        • followed by number of Bytes to be read.
        • +
        +
      • +
        +
      • PARSEMETHODE
        + Method how to parse the read bytes.
        + methods so far:
        +
          +
        • 1ByteU :
          Read value is 1 Byte without algebraic sign (if column Divisor set to state -> only 0 / 1 or off / on)
        • +
        • 1ByteS :
          Read value is 1 Byte with algebraic sign (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)
        • +
        • 2ByteS :
          Read value is 2 Byte with algebraic sign
        • +
        • 2ByteU :
          Read value is 2 Byte without algebraic sign
        • +
        • 2BytePercent :
          Read value is 2 Byte in percent
        • +
        • 4Byte :
          Read value is 4 Byte
        • +
        • mode :
          Read value is the actual operating status
        • +
        • timer :
          Read value is an 8 Byte timer value
        • +
        • date :
          Read value is an 8 Byte timestamp
        • + POLL Commands unsing the method timer will not be polled permanent, they have to be read by a GET Commando explicitly.
          + GET <devicename> TIMER
          +
        +
      • +
        +
      • DIVISOR
        + If the parsed value is multiplied by a factor, you can configure a divisor.
        + Additionally for values, that just deliver 0 or 1, you can configure state in this column.
        + This will force the reading to off and on, instead of 0 and 1.
        +
      • +
        +
      • READING-NAME
        + The read and parsed value will be stored in a reading with this name in the device. +
      • +
        +
      • KUMULATION
        + Accumulated Day values will be automatically stored for polling commands with the value day in the column KUMULATION.
        + Futhermore there will be stored the values of the last day in additional readings after 00:00.
        + So you have the chance to plot daily values.
        + The reading names will be supplemented by DayStart, Today and LastDay!
        +
      • + +
        + Examples:

        + POLL, 01F7080402, 2ByteS, 10 , Temp-WarmWater-Actual , -
        + POLL, 01F7088A02, 2ByteU, 1 , BurnerStarts , day
        +
      + +

      + Set Commands have the following structure:

      + + SET,SETCMD, ADRESSE, CONVMETHODE, NEXT_CMD or DAY for timer

      + +
        +
      • SET
        + is fix SET
        +
      • +
        + +
      • SETCMD
        + SETCMD are commands that will be used in FHEM to set a value of a device
        + set <devicename> <setcmd>
        + e.g. SET <devicename> WW to set the actual operational status to Warm Water processing
        +
      • +
        + +
      • ADDRESSE
        + Memory Address where the value has to be written in the memory of the heating.
        + It is subdivided in 4 parts:
        +
          +
        • Beginning is fix 01F4 (defines a writing command)
        • +
        • followed by actual address
        • +
        • followed by number of data-bytes to be written
        • +
        • followed by the data-bytes themselves
        • +
        +
        + There are two Address versions:
        +
      • Version 1: Value to be set is fix, e.g. Spar Mode on is fix 01
      • +
      • Version 2: Value has to be passed, e.g. warm water temperature
      • + +
        +
      • CONVMETHODE
        + Method how to convert the value with Version 2 in Bytes.
        + For Version 1 you can use - here.
        + Methods so far:
        +
          +
        • 1ByteU :
          Value to be written in 1 Byte without algebraic sign
          with Version 2 it has to be a number
        • +
        • 1ByteS :
          Value to be written in 1 Byte with algebraic sign
          with Version 2 it has to be a number
        • +
        • 2ByteS :
          Value to be written in 2 Byte with algebraic sign
          with Version 2 it has to be a number
        • +
        • 2ByteU :
          Value to be written in 2 Byte without algebraic sign
          with Version 2 it has to be a number
        • +
        • timer :
          Value to be written is an 8 Byte Timer value
          with Version 2 it has to be a string with this structure:
          + 8 times of day comma separeted. (ON1,OFF1,ON2,OFF2,ON3,OFF3,ON4,OFF4)
          + no time needed ha to be specified with -- .
          + Minutes of the times are just allowed to thi values: 00,10,20,30,40 or 50
          + Example: 06:10,12:00,16:00,23:00,--,--,--,--
        • +
        • date :
          Value to be written is an 8 Byte timestamp
          with Version 2 it has to be a string with this structure:
          + format specified is DD.MM.YYYY_HH:MM:SS
          + Example: 21.03.2014_21:35:00
        • +
        +
      • +
        + +
      • NEXT_CMD or DAY
        + This column has two functions: +
          +
        • If this columns is configured with a name of another SETCMD, it will be processed directly afterwards.
          + Example: after setting Spar Mode on (S-ON), you have to set Party Mode off (P-OFF)
        • +
        • Using timer as CONVMETHODE, so it has to be specified a week day in this columns.
          + possible values: MO DI MI DO FR SA SO
        • + +
          +
        + Examples:

        + SET, WW , 01F423010100, state , -
        + SET, S-ON , 01F423020101, state_spar , P-OFF
        + SET, WWTEMP , 01F4630001 , 1ByteU , -
        + SET, TIMER_2_MO, 01F4200008 , timer , MO
        +
      +
    +
    + Readings +
      The values read will be stored in readings, that will be configured as described above.
    +
+ +=end html +=begin html_DE + + +

VCONTROL

+
    + Das VCONTROL ist das fhem-Modul eine VIESSMANN Heizung via Optolink-Schnittstelle auszulesen und zu steuern.

    + + Notwendig ist dazu ein Optolink-Adapter (USB oder LAN), zu dem hier Informationen zu finden sind:
    + http://openv.wikispaces.com/

    + + Zusätzlich müssen für die verschiedenen Heizungstypen (z.B. V200KW1, VScotHO1, VPlusHO1 ....) Speicher-Adressen bekannt sein,
    + unter denen die Messwerte abgefragt oder aber auch Stati gesetzt werden können.
    + Informationen hierzu findet man im Forum http://openv.wikispaces.com/ und auf der wiki Seite http://openv.wikispaces.com/


    + + Define +
      + define <name> VCONTROL <serial-device/LAN-Device:port> <configfile> [<intervall>]
      +
      +
    • <serial-device/LAN-Device:port>
      + USB Port (z.B. com4, /dev/ttyUSB3) oder aber TCPIP:portnummer
      +
    • + +
    • <intervall>
      + Anzahl Sekunden wie oft die Heizung ausgelesen werden soll (default 180)
      +
    • + +
    • <configfile>
      + Pfad wo die Konfigurationsdatei für das Modul zu finden ist, die die Adressen beinhaltet
      +
    • +
      + Beispiel:

      + + serielle Schnittstelle über com4, alle 3 Minuten wird gepollt, configfile heisst 99_VCONTROL.cfg und liegt im fhem root Verzeichnis

      + + Windows:
      + define Heizung VCONTROL com4 99_VCONTROL.cfg 180

      + + Linux:
      + define Heizung VCONTROL /dev/ttyUSB3 99_VCONTROL.cfg 180
      + +
    +

    + + Set +
      + Diese müssen über das configfile konfiguriert werden. +
    +

    + Get +
      + get <name> CONFIG

      + Mit diesem Befehl wird das Modul spezifische configfile nachgeladen.

      + + Diese anderen Befehler müssen über das configfile konfiguriert werden. +
    +

    + + configfile +
      + Im configfile hat man nun die folgenden Konfigurations Möglichkeiten.

      + + Beispieldateien f¨r die Geräte-Typen V200KW1, VScotHO1, VPlusHO1 sind auf der wiki Seite http://openv.wikispaces.com/ zu finden.

      + +
    • Zeilen die mit "#" beginnen sind Kommentar!
    • +
    • Polling Commandos (POLL) zum Lesen von Werten können konfiguriert werden.
    • +
    • Set Commandos (SET) zum setzen von Werten können konfiguriert werden.
    • +
      + Polling Commandos haben den folgenden Aufbau:

      + + POLL, ADDRESSE, PARSEMETHODE, DIVISOR, READING-NAME, KUMULATION

      + +
        +
      • POLL
        + muss fest auf POLL stehen
        +
      • +
        +
      • ADDRESSE
        + Adresse, an der der auszulesende Wert im Speicher zu finden ist.
        + Sie besteht aus 3 Teilen:
        +
          +
        • beginnt immer mit 01F7 (Kommando zum Lesen)
        • +
        • danach folgt die eigentliche Addresse
        • +
        • danach muss die Anzahl der zu lesenden Bytes noch an die Adresse angehängt werden.
        • +
        +
      • +
        +
      • PARSEMETHODE
        + Methode wie die gelesenen Bytes interpretiert werden müssen.
        + Bisher mögliche Parsemethoden:
        +
          +
        • 1ByteU :
          Empfangener Wert in 1 Byte ohne Vorzeichen (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)
        • +
        • 1ByteS :
          Empfangener Wert in 1 Byte mit Vorzeichen (wenn Spalte Divisor state ist -> nur 0 / 1 also off / on)
        • +
        • 2ByteS :
          Empfangener Wert in 2 Byte mit Vorzeichen
        • +
        • 2ByteU :
          Empfangener Wert in 2 Byte ohne Vorzeichen
        • +
        • 2BytePercent :
          Empfangener Wert in 2 Byte als Prozent Wert
        • +
        • 4Byte :
          Empfangener Wert in 4 Byte
        • +
        • mode :
          Empfangener Wert ist der Betriebsstatus
        • +
        • timer :
          Empfangener Wert ist ein 8 Byte Timer Werte
        • +
        • date :
          Empfangener Wert ist ein 8 Byte Zeitstempel
        • + POLL Commandos die die Parsemethode timer enthalten werden nicht ständig gelesen, sondern müssen mit einem GET Commando geholt werden.
          + GET <devicename> TIMER
          +
        +
      • +
        +
      • DIVISOR
        + Wenn der interpretierte Wert noch um einen Faktor zu hoch ist, kann hier ein Divisor angegeben werden.
        + Zusätzlich hat man hier bei Werten, die nur 0 oder 1 liefern die möglich state einzutragen.
        + Dies führt dazu, dass das Reading mit off (0) und on (1) belegt wird, statt mit dem Wert.
        +
      • +
        +
      • READING-NAME
        + Der gelesene und interpretierte Wert wird unter diesem Reading abgelegt. +
      • +
        +
      • KUMULATION
        + Bei den Polling Commandos mit dem Wert day bei der Spalte KUMULATION werden Tageswerte Kumuliert.
        + Es werden dann jeweils nach 00:00 Uhr die Werte des letzten Tages ebenfalls als Readings im Device eingetragen,
        + so dass man die Werte pro Tag auch plotten oder auswerten kann.
        + Beim Readingnamen wird dann jeweils: DayStart,Today und LastDay angehangen!
        +
      • + +
        + Beispiel:

        + POLL, 01F7080402, 2ByteS, 10 , Temp-WarmWasser-Ist , -
        + POLL, 01F7088A02, 2ByteU, 1 , BrennerStarts , day
        +
      + +

      + Set Commandos haben den folgenden Aufbau:

      + + SET,SETCMD, ADRESSE, CONVMETHODE, NEXT_CMD or DAY for timer

      + +
        +
      • SET
        + muss fest auf SET stehen
        +
      • +
        + +
      • SETCMD
        + Die SETCMD sind die Commandos die man in FHEM zum setzen angeben muss
        + set <devicename> <setcmd>
        + z.B. SET <devicename> WW zum setzen auf den Status nur Warm Wasser Aufbereitung
        +
      • +
        + +
      • ADDRESSE
        + Adresse, an der der zu setzende Wert im Speicher zu schreiben ist.
        + Sie besteht aus 4 Teilen:
        +
          +
        • beginnt immer mit 01F4 (Kommando zum Lesen)
        • +
        • danach folgt die eigentliche Addresse
        • +
        • danach folgt die Anzahl der zu schreibenden Daten-Bytes
        • +
        • danach müssen die Daten-Bytes selber noch an die Adresse angehängt werden.
        • +
        +
        + Es gibt zwei Varianten bei den Adressen:
        +
      • Variante 1: Wert steht bereits fest, z.B. Spar Modus einschalten ist fix 01
      • +
      • Variante 2: Wert muss übergeben werden, z.B. Warm Wasser Temperatur
      • + +
        +
      • CONVMETHODE
        + Methode wie der zu schreibende Wert bei Variante 2 in Bytes konvertiert werden muss.
        + Bei Variante 1 kann man - eintragen.
        + Bisher mögliche Convmethoden:
        +
          +
        • 1ByteU :
          Zu sendender Wert in 1 Byte ohne Vorzeichen
          bei Variante 2 muss eine Zahl übergeben werden
        • +
        • 1ByteS :
          Zu sendender Wert in 1 Byte mit Vorzeichen
          bei Variante 2 muss eine Zahl übergeben werden
        • +
        • 2ByteS :
          Zu sendender Wert in 2 Byte mit Vorzeichen
          bei Variante 2 muss eine Zahl übergeben werden
        • +
        • 2ByteU :
          Zu sendender Wert in 2 Byte ohne Vorzeichen
          bei Variante 2 muss eine Zahl übergeben werden
        • +
        • timer :
          Zu sendender Wert ist ein 8 Byte Timer Werte
          bei Variante 2 muss folgender String uebergeben werden:
          + 8 Uhrzeiten mit Komma getrennt. (AN1,AUS1,AN2,AUS2,AN3,AUS3,AN4,AUS4)
          + Keine Uhrzeit muss als -- angegeben werden.
          + Minuten der Uhrzeiten dürfen nur 00,10,20,30,40 oder 50 sein
          + Beispiel: 06:10,12:00,16:00,23:00,--,--,--,--
        • +
        • date :
          Zu sendender Wert ist ein 8 Byte Zeitstempel
          bei Variante 2 muss folgender String uebergeben werden:
          + es muss das Format DD.MM.YYYY_HH:MM:SS eingehalten werden
          + Beispiel: 21.03.2014_21:35:00
        • +
        +
      • +
        + +
      • NEXT_CMD or DAY
        + Diese Spalte erfüllt zwei Funktionen: +
          +
        • Gibt man in dieser Spalte ein anderes konfiguriertes SETCMD an, so wird dies anschließend ausgeführt.
          + Beispiel: nach dem Spar Modus (S-ON) gesetzt wurde, muss der Party Modus (P-OFF) ausgeschaltet werden
        • +
        • Ist als CONVMETHODE timer angegeben, so muss man in dieser Spalte den Wochentag angeben, für den der Timer gilt.
          + Mögliche Werte: MO DI MI DO FR SA SO
        • + +
          +
        + Beispiele:

        + SET, WW , 01F423010100, state , -
        + SET, S-ON , 01F423020101, state_spar , P-OFF
        + SET, WWTEMP , 01F4630001 , 1ByteU , -
        + SET, TIMER_2_MO, 01F4200008 , timer , MO
        +
      +
    +
    + Readings +
      Die eingelesenen Werte werden wie oben beschrieben in selbst konfigurierten Readings abgelegt.
    +
+=end html_DE +=cut