diff --git a/fhem/FHEM/32_TechemHKV.pm b/fhem/FHEM/32_TechemHKV.pm new file mode 100644 index 000000000..be1c0c840 --- /dev/null +++ b/fhem/FHEM/32_TechemHKV.pm @@ -0,0 +1,360 @@ +############################################################################### +# $Id$ +# +# this module is part of fhem under the same license +# copyright 2015, joerg herrmann +# +# history +# initial checkin +# +############################################################################### +package main; + +use strict; +use warnings; + +sub +TechemHKV_Initialize(@) { + my ($hash) = @_; + + # require "Broker.pm"; + + # TECHEM HKV + $hash->{Match} = "^b..446850[\d]{8}6980....A0.*"; + + $hash->{DefFn} = "TechemHKV_Define"; + $hash->{UndefFn} = "TechemHKV_Undef"; + $hash->{SetFn} = "TechemHKV_Set"; + $hash->{GetFn} = "TechemHKV_Get"; + $hash->{NotifyFn} = "TechemHKV_Notify"; + $hash->{ParseFn} = "TechemHKV_Parse"; + + $hash->{AttrList} = "".$readingFnAttributes; + + return undef; +} + +sub +TechemHKV_Define(@) { + my ($hash, $def) = @_; + my ($name, $t, $id); + ($name, $t, $id, $def) = split(/ /, $def,4); + + return "ID must have 4 or 8 digits" if ($id !~ /^\d{4}(?:\d{4})?$/); + + my $lid = (length($id) == 8)?$id:undef; + $id = (length($id) == 8)?substr($id,-4):$id; + + $modules{TechemHKV}{defptr}{$id} = $hash; + $hash->{friendly} = $def if (defined($def)); + $hash->{lid} = $id if (length($id) == 8); + + # subscribe broadcast channels + # TechemHKV_subscribe($hash, 'foo'); + TechemHKV_Run($hash) if $init_done; + return undef; +} + +sub +TechemHKV_Undef(@) { + my ($hash) = @_; + return undef; +} + +sub +TechemHKV_Set(@) { + my ($hash, $name, $cmd, @args) = @_; + my $cnt = @args; + + return undef; +} + +sub +TechemHKV_Get(@) { + my ($hash) = @_; + + return undef; +} + +sub +TechemHKV_Notify (@) { + my ($hash, $ntfyDev) = @_; + return unless (($ntfyDev->{TYPE} eq 'CUL') || ($ntfyDev->{TYPE} eq 'Global')); + foreach my $event (@{$ntfyDev->{CHANGED}}) { + my @e = split(' ', $event); + TechemHKV_Run($hash) if ($e[0] eq 'INITIALIZED'); + # patch CUL.pm + TechemHKV_IOPatch($hash, $e[1]) if (($e[0] eq 'ATTR') && ($e[2] eq 'rfmode') && ($e[3] eq 'WMBus_T')); + # disable receiver + if (($e[0] eq 'ATTR') && ($e[2] eq 'rfmode') && ($e[3] ne 'WMBus_T')) { + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "state", "standby (IO missing)", 1); + readingsBulkUpdate($hash, "temp1", "--.--"); + readingsBulkUpdate($hash, "temp2", "--.--"); + readingsEndUpdate($hash, 1); + } + } + return undef; +} + +sub +TechemHKV_Receive(@) { + my ($hash, $msg) = @_; + + $hash->{longID} = $msg->{long} unless defined($hash->{longID}); + # TODO log collision if any ... + + my @t = localtime(time); + my ($ats, $ts); + readingsBeginUpdate($hash); + readingsBulkUpdate($hash, "temp1", $msg->{temp1}); + readingsBulkUpdate($hash, "temp2", $msg->{temp2}); + + # day period changed + $ats = ReadingsTimestamp($hash->{NAME},"current_period", "0"); + $ts = "".($t[5]+1900)."-".$msg->{actual}->{month}."-".$msg->{actual}->{day}." 00:00:00"; + if ($ats ne $ts) { + $hash->{".updateTimestamp"} = $ts; + readingsBulkUpdate($hash, "current_period", $msg->{actualVal}); + } + + # billing period changed + $ats = ReadingsTimestamp($hash->{NAME},"previous_period", "0"); + $ts = "20".$msg->{last}->{year}."-".$msg->{last}->{month}."-".$msg->{last}->{day}." 00:00:00"; + if ($ats ne $ts) { + $hash->{".updateTimestamp"} = $ts; + readingsBulkUpdate($hash, "previous_period", $msg->{lastVal}); + } + + readingsEndUpdate($hash, 1); + return undef; +} + +sub +TechemHKV_Run(@) { + my ($hash) = @_; + # find a CUL + foreach my $d (keys %defs) { + # live patch CUL.pm + TechemHKV_IOPatch($hash, $d) if ($defs{$d}{TYPE} eq "CUL"); + } + return undef; +} + +# live patch CUL.pm, aka THE HACK +sub +TechemHKV_IOPatch(@) { + my ($hash, $iodev) = @_; + return undef unless (AttrVal($iodev, "rfmode", undef) eq "WMBus_T"); + # see if already patched + readingsSingleUpdate($hash, "state", "listening", 1); + return undef if ($defs{$iodev}{Clients} =~ /TechemHKV/ ); + $defs{$iodev}{Clients} = ":TechemHKV".$defs{$iodev}{Clients}; + $defs{$iodev}{'.clientArray'} = undef; + return undef; +} + +sub +TechemHKV_Parse(@) { + + my ($iohash, $msg) = @_; + my ($message, $rssi); + ($msg, $rssi) = split (/::/, $msg); + my @m = ((substr $msg,1) =~ m/../g); + + # parse + ($message->{long}, $message->{short}) = TechemHKV_ParseID(@m); + $message->{lastVal} = TechemHKV_ParseLastPeriod(@m); + $message->{actualVal} = TechemHKV_ParseActualPeriod(@m); + $message->{temp1} = TechemHKV_ParseT1(@m); + $message->{temp2} = TechemHKV_ParseT2(@m); + ($message->{actual}->{month}, $message->{actual}->{day}) = TechemHKV_ParseActualDate(@m); + ($message->{last}->{year}, $message->{last}->{month}, $message->{last}->{day}) = TechemHKV_ParseLastDate(@m); + + # dispatch + if (exists($modules{TechemHKV}{defptr}{$message->{short}})) { + my $deviceHash = $modules{TechemHKV}{defptr}{$message->{short}}; + TechemHKV_Receive($deviceHash, $message); + return ($deviceHash->{NAME}); + } + # broadcast + + return ($iohash->{NAME}); +} + +sub +TechemHKV_ParseID(@) { + my @m = @_; + return ("$m[7]$m[6]$m[5]$m[4]", "$m[5]$m[4]"); +} + +sub +TechemHKV_ParseLastPeriod(@) { + my @m = @_; + return hex("$m[17]$m[16]"); +} + +sub +TechemHKV_ParseActualPeriod(@) { + my @m = @_; + return hex("$m[21]$m[20]"); +} + +sub +TechemHKV_ParseT1(@) { + my @m = @_; + return sprintf "%.2f", (hex("$m[23]$m[22]") / 100); +} + +sub +TechemHKV_ParseT2(@) { + my @m = @_; + return sprintf "%.2f", (hex("$m[25]$m[24]") / 100); +} + +sub +TechemHKV_ParseActualDate(@) { + my @m = @_; + my $b = hex("$m[19]$m[18]"); + my $d = ($b >> 4) & 0x1F; + my $m = ($b >> 9) & 0x0F; + return ($m, $d); +} + +sub +TechemHKV_ParseLastDate(@) { + my @m = @_; + my $b = hex("$m[15]$m[14]"); + my $d = ($b >> 0) & 0x1F; + my $m = ($b >> 5) & 0x0F; + my $y = ($b >> 9) & 0x3F; + return ($y, $m, $d); +} + +# message bus ahead +# sub +#TechemHKV_subscribe(@) { +# my ($hash, $topic) = @_; +# broker::subscribe ($topic, $hash->{NAME}, \&TechemHKV_rcvBCST); +# return undef; +#} + +#sub +#TechemHKV_sendBCST(@) { +# my ($hash, $topic, $msg) = @_; +# broker::publish ($topic, $hash->{NAME}, $msg); +# return undef; +#} + +#sub +#TechemHKV_rcvBCST(@) { +# my ($name, $topic, $sender, $msg) = @_; +# my $hash = $defs{$name}; +# return undef; +#} + +1; + +=pod +=begin html + + +

TechemHKV

+ +=end html + +=begin html_DE + + +

TechemHKV

+ + +=end html_DE +=cut +