From fc6db342182bf692b95af8fbf10d5e8f3bd0f6ba Mon Sep 17 00:00:00 2001 From: pahenning <> Date: Sun, 27 Mar 2016 09:14:38 +0000 Subject: [PATCH] =?UTF-8?q?OWAD.pm:=20Neue=20Version=206.0,=20eingerichtet?= =?UTF-8?q?=20f=C3=BCr=20asynchrones=20OWX=20OWCOUNT.pm:=20Neue=20Version?= =?UTF-8?q?=206.0,=20eingerichtet=20f=C3=BCr=20asynchrones=20OWX=20OWID.pm?= =?UTF-8?q?:=20Neue=20Version=206.0,=20eingerichtet=20f=C3=BCr=20asynchron?= =?UTF-8?q?es=20OWX=20OWLCD.pm:=20Neue=20Version=206.0,=20eingerichtet=20f?= =?UTF-8?q?=C3=BCr=20asynchrones=20OWX=20OWMULTI.pm:=20Neue=20Version=206.?= =?UTF-8?q?0,=20eingerichtet=20f=C3=BCr=20asynchrones=20OWX=20OWSWITCH.pm:?= =?UTF-8?q?=20Neue=20Version=206.0,=20eingerichtet=20f=C3=BCr=20asynchrone?= =?UTF-8?q?s=20OWX=20OWTHERM.pm:=20Neue=20Version=206.0,=20eingerichtet=20?= =?UTF-8?q?f=C3=BCr=20asynchrones=20OWX?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://svn.fhem.de/fhem/trunk@11130 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/21_OWAD.pm | 348 ++++----- fhem/FHEM/21_OWCOUNT.pm | 706 +++++++++--------- fhem/FHEM/21_OWID.pm | 15 +- fhem/FHEM/21_OWLCD.pm | 1479 +++++++++++++++++++++----------------- fhem/FHEM/21_OWMULTI.pm | 578 +++++++++------ fhem/FHEM/21_OWSWITCH.pm | 543 ++++++++------ fhem/FHEM/21_OWTHERM.pm | 231 +++--- 7 files changed, 2270 insertions(+), 1630 deletions(-) diff --git a/fhem/FHEM/21_OWAD.pm b/fhem/FHEM/21_OWAD.pm index 28b62e413..2c221a264 100644 --- a/fhem/FHEM/21_OWAD.pm +++ b/fhem/FHEM/21_OWAD.pm @@ -36,20 +36,16 @@ # # attr stateAL0 "" = character string for denoting low normal condition, default is empty # attr stateAH0 "" = character string for denoting high normal condition, default is empty -# attr stateAL1 "" = character string for denoting low alarm condition, default is down triangle -# attr stateAH1 "" = character string for denoting high alarm condition, default is up triangle +# attr stateAL1 "" = character string for denoting low alarm condition, default is ↓ +# attr stateAH1 "" = character string for denoting high alarm condition, default is ↑ # attr Name [|] = name for the channel [|name used in state reading] -# attr Unit [|] = unit of measurement for this channel [|unit used in state reading] -# -# ATTENTION: Usage of Offset/Factor is deprecated, replace by Function attribute -# attr Offset = offset added to the reading in this channel -# attr Factor = factor multiplied to (reading+offset) in this channel +# attr Unit = unit of measurement for this channel used in state reading (default V, none for empty) # attr Function = arbitrary functional expression involving the values V=VA,VB,VC,VD # VA is replaced by the measured voltage in channel A, etc. # # attr Alarm = alarm setting in this channel, either both, low, high or none (default) -# attr Low = measurement value (on the scale determined by offset and factor) for low alarm -# attr High = measurement value (on the scale determined by offset and factor) for high alarm +# attr Low = measurement value (on the scale determined by function) for low alarm +# attr High = measurement value (on the scale determined by function) for high alarm # ######################################################################################## # @@ -88,9 +84,9 @@ BEGIN { use ProtoThreads; no warnings 'deprecated'; -sub Log($$); +sub Log3($$$); -my $owx_version="5.20"; +my $owx_version="6.0"; #-- fixed raw channel name, flexible channel name my @owg_fixed = ("A","B","C","D"); my @owg_channel = ("A","B","C","D"); @@ -161,15 +157,13 @@ sub OWAD_Initialize ($) { $hash->{InitFn} = "OWAD_Init"; $hash->{AttrFn} = "OWAD_Attr"; - my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2450 verbose:0,1,2,3,4,5 ". + my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2450 ". "stateAL0 stateAL1 stateAH0 stateAH1 ". "interval ". $readingFnAttributes; for( my $i=0;$i{NOTIFYDEV} = "global"; @@ -391,11 +385,11 @@ sub OWAD_ChannelNames($) { my $name = $hash->{NAME}; my $state = $hash->{READINGS}{"state"}{VAL}; - my ($cname,@cnama,$unit,@unarr); + my ($cname,@cnama,$unit); for (my $i=0;$i{READINGS}{$owg_channel[$i]}{ABBR} = $cnama[1]; - $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unarr[0]; - $hash->{READINGS}{$owg_channel[$i]}{UNITABBR} = $unarr[1]; + $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unit; } } @@ -429,7 +423,7 @@ sub OWAD_FormatValues($) { my $name = $hash->{NAME}; my $interface = $hash->{IODev}->{TYPE}; - my ($offset,$factor,$vval,$vlow,$vhigh,$vfunc,$ret); + my ($vval,$vlow,$vhigh,$vfunc,$ret); my $vfuncall = ""; my $svalue = ""; @@ -445,8 +439,8 @@ sub OWAD_FormatValues($) { $hash->{ALARM} = 0; #-- alarm signatures - my $stateal1 = defined($attr{$name}{stateAL1}) ? $attr{$name}{stateAL1} : "▾"; - my $stateah1 = defined($attr{$name}{stateAH1}) ? $attr{$name}{stateAH1} : "▴"; + my $stateal1 = defined($attr{$name}{stateAL1}) ? $attr{$name}{stateAL1} : "↓"; + my $stateah1 = defined($attr{$name}{stateAH1}) ? $attr{$name}{stateAH1} : "↑"; my $stateal0 = defined($attr{$name}{stateAL0}) ? $attr{$name}{stateAL0} : ""; my $stateah0 = defined($attr{$name}{stateAH0}) ? $attr{$name}{stateAH0} : ""; @@ -463,13 +457,7 @@ sub OWAD_FormatValues($) { #-- formats for output for (my $i=0;$i{READINGS}{$owg_channel[$i]}{ABBR}, $vval,$hash->{READINGS}{$owg_channel[$i]}{UNITABBR}); + $svalue .= sprintf( "%s: %5.3f%s", $hash->{READINGS}{$owg_channel[$i]}{ABBR}, $vval,$hash->{READINGS}{$owg_channel[$i]}{UNIT}); #-- Test for alarm condition $alarm = "none"; @@ -542,6 +530,7 @@ sub OWAD_FormatValues($) { } #-- put into READINGS + $vval = sprintf( "%5.3f", $vval); readingsBulkUpdate($hash,"$owg_channel[$i]",$vval); #-- insert space if( $i{IODev}->{TYPE}; my ($value,$value2,$value3) = (undef,undef,undef); my $ret = ""; - my $offset; - my $factor; #-- check syntax return "OWAD: Get argument is missing @a" @@ -642,17 +629,20 @@ sub OWAD_Get($@) { return "OWAD: Get with wrong IODev type $interface"; } - #-- process results - if( defined($ret) ){ - $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; - if( $hash->{ERRCOUNT} > 5 ){ - $hash->{INTERVAL} = 9999; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWAD: $name getting reading, please wait for completion"; + }else{ + if( defined($ret) ){ + $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; + if( $hash->{ERRCOUNT} > 5 ){ + $hash->{INTERVAL} = 9999; + } + return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; } - return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; + return "OWAD: $name.reading => ".$hash->{READINGS}{"state"}{VAL}; } - return "OWAD: $name.reading => ".$hash->{READINGS}{"state"}{VAL}; } - #-- get alarm values according to interface type if($a[1] eq "alarm") { #-- OWX interface @@ -671,23 +661,27 @@ sub OWAD_Get($@) { return "OWAD: Get with wrong IODev type $interface"; } - #-- process results - if( defined($ret) ){ - $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; - if( $hash->{ERRCOUNT} > 5 ){ - $hash->{INTERVAL} = 9999; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWAD: $name getting alarm values, please wait for completion"; + }else{ + if( defined($ret) ){ + $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; + if( $hash->{ERRCOUNT} > 5 ){ + $hash->{INTERVAL} = 9999; + } + return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; } - return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; - } - #-- assemble ouput string - $value = ""; - for (my $i=0;$i $value"; } - return "OWAD: $name.alarm => $value"; } #-- get status values according to interface type @@ -708,47 +702,51 @@ sub OWAD_Get($@) { return "OWAD: Get with wrong IODev type $interface"; } - #-- process results - if( defined($ret) ){ - $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; - if( $hash->{ERRCOUNT} > 5 ){ - $hash->{INTERVAL} = 9999; - } - return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; - } + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWAD: $name getting status, please wait for completion"; + }else{ + if( defined($ret) ){ + $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1; + if( $hash->{ERRCOUNT} > 5 ){ + $hash->{INTERVAL} = 9999; + } + return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret"; + } - #-- assemble output string - $value = "\n"; - for (my $i=0;$i{owg_slow}->[$i]) { - $value .= "low alarm undefined, "; - } elsif( $hash->{owg_slow}->[$i]==0 ) { - $value .= "low alarm disabled, "; - } elsif( $hash->{owg_slow}->[$i]==1 ) { - $value .= "low alarm enabled, "; - } elsif( $hash->{owg_slow}->[$i]==2 ) { - $value .= "alarmed low, "; - } - if (!defined $hash->{owg_shigh}) { - $value .= "high alarm undefined"; - } elsif( $hash->{owg_shigh}->[$i]==0 ) { - $value .= "high alarm disabled"; - } elsif( $hash->{owg_shigh}->[$i]==1 ) { - $value .= "high alarm enabled"; - } elsif( $hash->{owg_shigh}->[$i]==2 ) { - $value .= "alarmed high"; - } - #-- insert space - if( $i{owg_slow}->[$i]) { + $value .= "low alarm undefined, "; + } elsif( $hash->{owg_slow}->[$i]==0 ) { + $value .= "low alarm disabled, "; + } elsif( $hash->{owg_slow}->[$i]==1 ) { + $value .= "low alarm enabled, "; + } elsif( $hash->{owg_slow}->[$i]==2 ) { + $value .= "alarmed low, "; + } + if (!defined $hash->{owg_shigh}) { + $value .= "high alarm undefined"; + } elsif( $hash->{owg_shigh}->[$i]==0 ) { + $value .= "high alarm disabled"; + } elsif( $hash->{owg_shigh}->[$i]==1 ) { + $value .= "high alarm enabled"; + } elsif( $hash->{owg_shigh}->[$i]==2 ) { + $value .= "alarmed high"; + } + #-- insert space + if( $i ".$value; } - return "OWAD: $name.status => ".$value; } } @@ -939,8 +937,6 @@ sub OWAD_Set($@) { my $ret = undef; my $channon = undef; my $channo = undef; - my $factor; - my $offset; my $condx; my $name = $hash->{NAME}; @@ -1024,7 +1020,7 @@ sub OWAD_Set($@) { #-- set alarm values (alarm voltages) }elsif( $key =~ m/(.*)(Low|High)/ ) { - #-- find upper and lower boundaries for given offset/factor + #-- find upper and lower boundaries my $mmin = 0.0; my $mmax = $owg_range[$channo]/1000; @@ -1313,37 +1309,61 @@ sub OWFSAD_SetPage($$) { # ######################################################################################## # -# OWXAD_BinValues - Binary readings into clear values +# OWXAD_BinValues - Process reading from one device - translate binary into raw # # Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string +# # ######################################################################################## -sub OWXAD_BinValues($$$$$$$$) { - my ($hash, $context, $success, $reset, $owx_dev, $command, $numread, $res) = @_; +sub OWXAD_BinValues($$$$$$$) { + my ($hash, $context, $proc, $owx_dev, $crcpart, $numread, $res) = @_; - #-- always check for success, unused are reset - return unless ($success and $context); - #Log 1,"OWXAD_BinValues context = $context"; - my $final = ($context =~ /\.final$/ ); - - my ($i,$j,$k,@data,$ow_thn,$ow_tln); + #-- hash of the busmaster + my $master = $hash->{IODev}; + my $name = $hash->{NAME}; + my @data=[]; + my $value; + my $msg; + OWX_WDBG($name,"OWXAD_BinValues called for device $name in context $context with ",$res) + if( $main::owx_debug>2 ); + + my $final = ($context =~ /\.final$/ ); + my ($ow_thn,$ow_tln); #-- process results @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 10 bytes" - if (@data != 10); - return "invalid CRC" - if (OWX_CRC16($command.substr($res,0,8),$data[8],$data[9])==0); - + if (@data != 10){ + $msg="$name returns invalid data length, ".int(@data)." instead of 10 bytes "; + }elsif (OWX_CRC16($crcpart.substr($res,0,8),$data[8],$data[9])==0){ + $msg="$name returns invalid CRC " + }else{ + $msg="No error "; + } + OWX_WDBG($name,"OWXAD_BinValues: ".$msg,$crcpart) + if( $main::owx_debug>2 ); + #=============== get the voltage reading =============================== if( $context =~ /^ds2450.getreading/ ){ - for( $i=0;$i{owg_val}->[$i]= (ord($data[2*$i])+256*ord($data[1+2*$i]) )/(1<<$owg_resoln[$i]) * $owg_range[$i]/1000; } #=============== get the alarm reading =============================== } elsif ( $context =~ /^ds2450.getalarm/ ){ - for( $i=0;$i{owg_vlow}->[$i] = int(ord($data[2*$i])/256 * $owg_range[$i]+0.5)/1000; $hash->{owg_vhigh}->[$i] = int(ord($data[1+2*$i])/256 * $owg_range[$i]+0.5)/1000; } @@ -1406,7 +1426,6 @@ sub OWXAD_BinValues($$$$$$$$) { $hash->{PRESENT} = 1; if( $final ){ my $value = OWAD_FormatValues($hash); - Log 5, $value; } return undef } @@ -1465,16 +1484,25 @@ sub OWXAD_GetPage($$$@) { return "wrong memory page requested from $owx_dev"; } my $context = "ds2450.get".$page.($final ? ".final" : ""); - #-- reset the bus - OWX_Reset($master); - #-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes - $res=OWX_Complex($master,$owx_dev,$select,10); - return "$owx_dev not accessible in reading page $page" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=22); - #-- for processing we also need the 3 command bytes - return OWXAD_BinValues($hash,$context,1,undef,$owx_dev,$select,10,substr($res,12,10)); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + #-- reset the bus + OWX_Reset($master); + #-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes + $res=OWX_Complex($master,$owx_dev,$select,10); + return "$owx_dev not accessible in reading page $page" + if( $res eq 0 ); + return "$owx_dev has returned invalid data" + if( length($res)!=22); + #-- for processing we also need the 3 command bytes + return OWXAD_BinValues($hash,$context,1,undef,$owx_dev,$select,substr($res,12,10)); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 1 additional reset after last action + OWX_Qomplex($master, $hash, $context, 1, $owx_dev, $select, $select, 10, 12, \&OWXAD_BinValues, 0); + return undef; + } } ######################################################################################## @@ -1542,11 +1570,18 @@ sub OWXAD_SetPage($$) { } else { return "wrong memory page write attempt"; } - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - if( $res eq 0 ){ - return "device $owx_dev not accessible for writing"; - } + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + if( $res eq 0 ){ + return "device $owx_dev not accessible for writing"; + } + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, undef, 0, $owx_dev, $select, 0, 0, 0, undef, 0); + } return undef; } @@ -1613,7 +1648,7 @@ sub OWXAD_PT_GetPage($$$) { PT_WAIT_THREAD($thread->{pt_execute}); die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); my $response = $thread->{pt_execute}->PT_RETVAL(); - my $res = OWXAD_BinValues($hash,"ds2450.get".$page.($final ? ".final" : ""),1,1,$owx_dev,$thread->{'select'},10,$response); + my $res = OWXAD_BinValues($hash,"ds2450.get".$page.($final ? ".final" : ""),1,$owx_dev,$thread->{'select'},10,$response); if ($res) { die $res; } @@ -1716,16 +1751,14 @@ sub OWXAD_PT_SetPage($$) {
attr OWX_AD DAlarm high
- attr OWX_AD DFactor 31.907097 + attr OWX_AD DName humidity +
+ attr OWX_AD DUnit % +
+ attr OWX_AD DFunction VD*31.907097-0.8088
attr OWX_AD DHigh 50.0
- attr OWX_AD DName RelHumidity|humidity -
- attr OWX_AD DOffset -0.8088 -
- attr OWX_AD DUnit percent|% -


Define

@@ -1792,46 +1825,31 @@ sub OWXAD_PT_SetPage($$) {
  • attr <name> stateAH0 <string>
    character string for denoting high normal condition, default is empty
  • attr <name> stateAL1 <string> -
    character string for denoting low alarm condition, default is down triangle, - e.g. the code &#x25BE; leading to the sign ▾
  • +
    character string for denoting low alarm condition, default is ↓
  • attr <name> stateAH1 <string> -
    character string for denoting high alarm condition, default is upward - triangle, e.g. the code &#x25B4; leading to the sign ▴
  • +
    character string for denoting high alarm condition, default is ↑ For each of the following attributes, the channel identification A,B,C,D may be used. =end html diff --git a/fhem/FHEM/21_OWCOUNT.pm b/fhem/FHEM/21_OWCOUNT.pm index f6905d65f..34154d1a6 100644 --- a/fhem/FHEM/21_OWCOUNT.pm +++ b/fhem/FHEM/21_OWCOUNT.pm @@ -44,9 +44,9 @@ # attr LogM = device name (not file name) of monthly log file # attr LogY = device name (not file name) of yearly log file # attr nomemory = 1|0 (when set to 1, disables use of internal memory) -# attr Name [|] = name for the channel [|name used in state reading] -# attr Unit [|] = unit of measurement for this channel [|unit used in state reading] -# attr Rate [|] = name for the channel rate [|name used in state reading] +# attr Name [|] = name for the channel [|short name used in state reading] +# attr Unit = unit of measurement used in state reading (default cts, none for empty) +# attr Rate [|] = name for the channel rate [|short name used in state reading] # attr Offset = offset added to the reading in this channel # attr Factor = factor multiplied to (reading+offset) in this channel # attr Mode = counting mode = normal(default) or daily @@ -99,11 +99,13 @@ no warnings 'deprecated'; sub Log3($$$); -my $owx_version="5.33"; +my $owx_version="6.0"; #-- fixed raw channel name, flexible channel name my @owg_fixed = ("A","B"); my @owg_channel = ("A","B"); my @owg_rate = ("A_rate","B_rate"); +#-- initially assume that both memory types (low, high) are present +my @owg_memory = (1,1,0); my %gets = ( "id" => "", @@ -229,13 +231,16 @@ sub OWCOUNT_Define ($$) { if( $model eq "DS2423" ){ $fam = "1D"; CommandAttr (undef,"$name model DS2423"); + @owg_memory = (1,1,0); }elsif( $model eq "DS2423enew" ){ $fam = "1D"; + @owg_memory = (1,1,0); CommandAttr (undef,"$name model DS2423enew"); }elsif( $model eq "DS2423eold" ){ $fam = "1D"; CommandAttr (undef,"$name model DS2423eold"); CommandAttr (undef,"$name nomemory 1"); + @owg_memory = (0,0,0); }else{ return "OWCOUNT: Wrong 1-Wire device model $model"; } @@ -264,7 +269,7 @@ sub OWCOUNT_Define ($$) { $modules{OWCOUNT}{defptr}{$id} = $hash; #-- readingsSingleUpdate($hash,"state","defined",1); - Log3 $name, 3, "OWCOUNT: Device $name defined."; + Log3 $name, 3, "OWCOUNT: Device $name defined."; $hash->{NOTIFYDEV} = "global"; @@ -301,12 +306,61 @@ sub OWCOUNT_Notify ($$) { sub OWCOUNT_Init ($) { my ($hash)=@_; + #-- Start timer for updates RemoveInternalTimer($hash); InternalTimer(gettimeofday()+10, "OWCOUNT_GetValues", $hash, 0); return undef; } +######################################################################################## +# +# OWCOUNT_InitializeDevice - delayed setting of initial readings and channel names +# +# Parameter hash = hash of device addressed +# +######################################################################################## + +sub OWCOUNT_InitializeDevice($) { + my ($hash) = @_; + + my $name = $hash->{NAME}; + #-- get memory page/counter according to interface type + my $master= $hash->{IODev}; + my $interface= $hash->{IODev}->{TYPE}; + + my $olddata = ""; + my ($olddata1,$olddata2); + my $newdata = "OWCOUNT ".$owx_version; + my $ret; + + #-- initial values + for( my $i=0;$i{owg_val}->[$i] = ""; + $hash->{owg_midnight}->[$i] = ""; + $hash->{owg_str}->[$i] = ""; + } + + #-- Check memory string + my $memory; + if( ($owg_memory[0]==1) && ($owg_memory[1]==1) ){ + $memory="page 0..13 and midnight"; + }elsif( ($owg_memory[0]==0) && ($owg_memory[1]==1) ){ + $memory="midnight only"; + }elsif( ($owg_memory[0]==1) && ($owg_memory[1]==0) ){ + $memory="page 0..13 only"; + }else{ + $memory="no pages, no midnight"; + } + readingsSingleUpdate($hash,"memory","$memory",0); + + #-- Set state to initialized + readingsSingleUpdate($hash,"state","initialized",1); + + return undef; +} + ####################################################################################### # # OWCOUNT_Attr - Set one attribute value for device @@ -369,56 +423,56 @@ sub OWCOUNT_ChannelNames($) { for (my $i=0;$i{READINGS}{$owg_channel[$i]}{ABBR} = $cnama[1]; - $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unarr[0]; - $hash->{READINGS}{$owg_channel[$i]}{UNITABBR} = $unarr[1]; + $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unit; $period = defined($attr{$name}{$owg_fixed[$i]."Period"}) ? $attr{$name}{$owg_fixed[$i]."Period"} : "hour"; #-- put into readings $hash->{READINGS}{$owg_channel[$i]}{PERIOD} = $period; #-- rate - $cname = defined($attr{$name}{$owg_fixed[$i]."Rate"}) ? $attr{$name}{$owg_fixed[$i]."Rate"} : $cnama[0]."_rate|".$cnama[1]."_rate"; + $cname = defined($attr{$name}{$owg_fixed[$i]."Rate"}) ? $attr{$name}{$owg_fixed[$i]."Rate"} : + (defined($attr{$name}{$owg_fixed[$i]."Name"}) ? "$cnama[0]_rate|$cnama[1]_r" : "$owg_fixed[$i]_rate|$owg_fixed[$i]_r"); @cnama = split(/\|/,$cname); if( int(@cnama)!=2){ push(@cnama,$cnama[0]); } #-- rate unit - my $runit = ""; - if( $period eq "hour" ){ - $runit = "/h"; - }elsif( $period eq "minute" ){ - $runit = "/min"; - } else { - $runit = "/s"; + if( $unit ne " " ){ + if( $period eq "hour" ){ + $unit .= "/h"; + }elsif( $period eq "minute" ){ + $unit .= "/min"; + } else { + $unit .= "/s"; + } } + + #-- some special cases + # Energy/Power + $unit = " kW" + if ($unit eq " kWh/h" ); + #-- put into readings $owg_rate[$i]=$cnama[0]; $hash->{READINGS}{$owg_rate[$i]}{ABBR} = $cnama[1]; - $hash->{READINGS}{$owg_rate[$i]}{UNIT} = $unarr[0].$runit; - $hash->{READINGS}{$owg_rate[$i]}{UNITABBR} = $unarr[1].$runit; - - #-- some special cases - # Energy/Power - $hash->{READINGS}{$owg_rate[$i]}{UNIT} = "kW" - if ($unarr[0].$runit eq "kWh/h" ); - $hash->{READINGS}{$owg_rate[$i]}{UNITABBR} = "kW" - if ($unarr[1].$runit eq "kWh/h" ); + $hash->{READINGS}{$owg_rate[$i]}{UNIT} = $unit; } } @@ -467,9 +521,34 @@ sub OWCOUNT_FormatValues($) { } } - #-- put into READINGS + #-- put into READING readingsBeginUpdate($hash); + #-- Check memory string + if( $owg_memory[2]==1 ){ + my $memory; + my $model = $hash->{OW_MODEL}; + my $nomemory; + + if( ($owg_memory[0]==1) && ($owg_memory[1]==1) ){ + $memory = "page 0..13 and midnight"; + $model = "DS2423"; + $nomemory = 0; + }elsif( ($owg_memory[0]==0) && ($owg_memory[1]==1) ){ + $memory="midnight only"; + $model = "DS2423enew"; + $nomemory = 0; + }else{ + $memory="no pages, no midnight"; + $model = "DS2423eold"; + $nomemory = 1; + } + CommandAttr (undef,"$name model ".$model); + CommandAttr (undef,"$name nomemory ".$nomemory); + readingsBulkUpdate($hash,"memory","$memory"); + $owg_memory[2]=0; + } + #-- formats for output for (my $i=0;$i{READINGS}{$owg_channel[$i]}{OFFSET} = $offset; $hash->{READINGS}{$owg_channel[$i]}{FACTOR} = $factor; - $unit = $hash->{READINGS}{$owg_channel[$i]}{UNITABBR}; + $unit = $hash->{READINGS}{$owg_channel[$i]}{UNIT}; $period = $hash->{READINGS}{$owg_channel[$i]}{PERIOD}; - $runit = $hash->{READINGS}{$owg_rate[$i]}{UNITABBR}; + $runit = $hash->{READINGS}{$owg_rate[$i]}{UNIT}; #-- skip some things if undefined if( $hash->{owg_val}->[$i] eq ""){ - $svalue .= $owg_channel[$i].": ???"; + $svalue .= $owg_channel[$i]." ???"; }else{ #-- only if attribute value mode=daily, take the midnight value from memory if( $daily == 1){ @@ -555,6 +634,7 @@ sub OWCOUNT_FormatValues($) { my $msg = sprintf("%4d-%02d-%02d midnight %7.2f", $year+1900,$month+1,$day,$dval2); OWCOUNT_SetPage($hash,14+$i,$msg); + Log3 $name,5,"OWCOUNT: measured value $vval (midnight ".$hash->{owg_midnight}->[$i].") => new extrapolated midnight $dval2"; #-- string buildup for monthly and yearly logging $dvalue .= sprintf( " %s: %5.2f %s %sM: %%5.2f %s", $owg_channel[$i],$dval,$unit,$owg_channel[$i],$unit); @@ -563,7 +643,7 @@ sub OWCOUNT_FormatValues($) { #-- string buildup for return value and STATE #-- 1 or 3 decimals - my $fs = ( $factor == 1.0 )? "%s: %5.2f %s %s: %5.2f %s":"%s: %5.3f %s %s: %5.3f %s"; + my $fs = ( $factor == 1.0 )? "%s: %5.2f %s %s: %5.2f %s" : "%s: %5.3f %s %s: %5.3f %s"; $svalue .= sprintf( $fs, $hash->{READINGS}{$owg_channel[$i]}{ABBR}, $vval,$unit,$hash->{READINGS}{$owg_rate[$i]}{ABBR},$vrate,$runit); #-- 3 decimals } @@ -585,7 +665,7 @@ sub OWCOUNT_FormatValues($) { #-- put in monthly and yearly sums if( int(@monthv) == 2 ){ $total0 = $monthv[0]->[1]; - $total1 = $monthv[1]->[1]; + $total1 = ($day==1)?$total0:$monthv[1]->[1]; $dvalue = sprintf("D%02d ",$day).$dvalue; $dvalue = sprintf($dvalue,$total0,$total1); readingsBulkUpdate($hash,"day",$dvalue); @@ -597,7 +677,7 @@ sub OWCOUNT_FormatValues($) { if( int(@yearv) == 2 ){ $total2 = $yearv[0]->[1]; - $total3 = $yearv[1]->[1]; + $total3 = ($month==0)?$total2: $yearv[1]->[1]; if ( $monthbreak == 1){ $mvalue = sprintf("M%02d ",$month+1).$mvalue; $mvalue = sprintf($mvalue,$total0,$total2,$total1,$total3); @@ -631,6 +711,7 @@ sub OWCOUNT_Get($@) { my $reading = $a[1]; my $name = $hash->{NAME}; my $model = $hash->{OW_MODEL}; + my $master = $hash->{IODev}; my $value = undef; my $ret = ""; my $page; @@ -655,18 +736,20 @@ sub OWCOUNT_Get($@) { if($a[1] eq "present") { #-- hash of the busmaster my $master = $hash->{IODev}; - #-- asynchronous mode - if( $hash->{ASYNC} ){ + + #-- normal OWX + if( !$hash->{ASYNC} ){ + $value = OWX_Verify($master,$hash->{ROM_ID}); + $hash->{PRESENT} = $value; + return "$name.present => $value"; + #-- old asynchronous mode + }else{ eval { OWX_ASYNC_RunToCompletion($hash,OWX_ASYNC_PT_Verify($hash)); }; return GP_Catch($@) if $@; return "$name.present => ".ReadingsVal($name,"present","unknown"); - } else { - $value = OWX_Verify($master,$hash->{ROM_ID}); } - $hash->{PRESENT} = $value; - return "$name.present => $value"; } #-- get interval @@ -733,7 +816,7 @@ sub OWCOUNT_Get($@) { $value .= $owg_channel[$i]."Y: ".$year2[$i]->[1]." ".$unit. " (yearly sum until now, average ".$year2[$i]->[2]." ".$unit."/d)\n"; }else{ - $value .= $owg_channel[$i]."Y: ".$year2[$i]->[1]." ".$unit." (last month)\n"; + $value .= $owg_channel[$i]."Y: ".$year2[$i]->[1]." ".$unit."\n"; } } return $value; @@ -754,11 +837,16 @@ sub OWCOUNT_Get($@) { return "OWCOUNT: Wrong memory page requested"; } $ret = OWCOUNT_GetPage($hash,$page,1,1); - #-- when we have a return code, we have an error - if( $ret ){ - return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWCOUNT: $name getting memory $page, please wait for completion"; }else{ - return "OWCOUNT: $name.$reading [$page] =>".$hash->{owg_str}->[$page]; + #-- when we have a return code, we have an error + if( $ret ){ + return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + }else{ + return "OWCOUNT: $name.$reading [$page] =>".$hash->{owg_str}->[$page]; + } } } if( $reading eq "midnight" ){ @@ -773,11 +861,16 @@ sub OWCOUNT_Get($@) { return "OWCOUNT: Invalid midnight counter address, must be A, B or defined channel name" } $ret = OWCOUNT_GetPage($hash,$page,1,1); - #-- when we have a return code, we have an error - if( $ret ){ - return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWCOUNT: $name getting midnight value $page and counter, please wait for completion"; }else{ - return "OWCOUNT: $name.$reading [$page] =>".$hash->{owg_midnight}->[$page-14]; + #-- when we have a return code, we have an error + if( $ret ){ + return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + }else{ + return "OWCOUNT: $name.$reading [$page] =>".$hash->{owg_midnight}->[$page-14]; + } } } @@ -794,30 +887,37 @@ sub OWCOUNT_Get($@) { return "OWCOUNT: Invalid counter address, must be A, B or defined channel name" } $ret = OWCOUNT_GetPage($hash,$page,1,1); - #-- when we have a return code, we have an error - if( $ret ){ - return "OWCOUNT: Could not get values from device $name, reason: ".$ret; - } - #-- only one counter will be returned - return "OWCOUNT: $name.raw $a[2] => ".$hash->{owg_val}->[$page-14]; - + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWCOUNT: $name getting page $page and counter, please wait for completion"; + }else{ + #-- when we have a return code, we have an error + if( $ret ){ + return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + } + #-- only one counter will be returned + return "OWCOUNT: $name.raw $a[2] => ".$hash->{owg_val}->[$page-14]; + } #-- check syntax for getting counters }elsif( $reading eq "counters" ){ return "OWCOUNT: Get needs no parameter when reading counters" if( int(@a)==1 ); $ret1 = OWCOUNT_GetPage($hash,14,0,1); $ret2 = OWCOUNT_GetPage($hash,15,1,1); - - #-- process results - $ret .= $ret1 - if( defined($ret1) ); - $ret .= $ret2 - if( defined($ret2) ); - if( defined($ret1) || defined($ret2) ){ - return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWCOUNT: $name getting counters, please wait for completion"; + }else{ + $ret .= $ret1 + if( defined($ret1) ); + $ret .= $ret2 + if( defined($ret2) ); + if( defined($ret1) || defined($ret2) ){ + return "OWCOUNT: Could not get values from device $name, reason: ".$ret; + } + #-- both counters will be returned + return "OWCOUNT: $name.counters => ".$hash->{READINGS}{"state"}{VAL}; } - #-- both counters will be returned - return "OWCOUNT: $name.counters => ".$hash->{READINGS}{"state"}{VAL}; } } @@ -926,7 +1026,7 @@ sub OWCOUNT_GetMonth($) { @linarr = split(' ',$line); if( int(@linarr)==4+6*int(@owg_fixed) ){ $day = $linarr[3]; - $day =~ s/D_0+//; + $day =~ s/D_+0+//; @mchannel = (); for (my $i=0;$i0); }; - - #-- add data from current day also for non-summed mode - $total = int($total*100)/100; - $total2 = int(100*($total+$month2[$i]->[1]))/100; + $total = int($total*100)/100; + #-- data from this month is + $total2 = int(100*($month2[$i]->[1]))/100; + #-- add data from this month and previous months in daily mode + $total2+=$total + if( $daily==1 ); #-- number of days so far, including the present day my $deltim = $cyday+($chour+$cmin/60.0 + $csec/3600.0)/24.0; my $av = $deltim>0 ? int(100*$total2/$deltim)/100 : -1; @@ -1094,7 +1194,7 @@ sub OWCOUNT_GetValues($) { #-- check if device needs to be initialized OWCOUNT_InitializeDevice($hash) if( $hash->{READINGS}{"state"}{VAL} eq "defined"); - + #-- restart timer for updates RemoveInternalTimer($hash); InternalTimer(time()+$hash->{INTERVAL}, "OWCOUNT_GetValues", $hash, 0); @@ -1111,106 +1211,6 @@ sub OWCOUNT_GetValues($) { if( $ret ne "" ){ return "OWCOUNT: Could not get values from device $name, reason: ".$ret; } - - return undef; -} - -######################################################################################## -# -# OWCOUNT_InitializeDevice - delayed setting of initial readings and channel names -# -# Parameter hash = hash of device addressed -# -######################################################################################## - -sub OWCOUNT_InitializeDevice($) { - my ($hash) = @_; - - my $name = $hash->{NAME}; - #-- get memory page/counter according to interface type - my $master= $hash->{IODev}; - my $interface= $hash->{IODev}->{TYPE}; - - my $olddata = ""; - my $newdata = "OWCOUNT ".$owx_version; - my $ret; - - #-- initial values - for( my $i=0;$i{owg_val}->[$i] = ""; - $hash->{owg_midnight}->[$i] = ""; - $hash->{owg_str}->[$i] = ""; - } - - #-- testing if it is the emulator - #-- The model may be DS2423, DS2423enew or DS2423eold. Some weird people are violating 1-Wire integrity by using the - # the same family ID although the DS2423emu does not fully support the DS2423 commands. - # Model attribute will be modified now after checking for memory - #-- OWX interface - if( $interface eq "OWX" ){ - $ret = OWXCOUNT_GetPage($hash,14,0); - $olddata = $hash->{owg_str}->[14]; - $ret = OWXCOUNT_SetPage($hash,14,$newdata); - $ret = OWXCOUNT_GetPage($hash,14,0); - $ret = OWXCOUNT_SetPage($hash,14,$olddata); - }elsif( $interface eq "OWX_ASYNC" ){ - eval { - $ret = OWX_ASYNC_RunToCompletion($hash,OWXCOUNT_PT_InitializeDevicePage($hash,14,$newdata)); - }; - $ret = GP_Catch($@) if $@; - #-- OWFS interface - }elsif( $interface eq "OWServer" ){ - $ret = OWFSCOUNT_GetPage($hash,14,0); - $olddata = $hash->{owg_str}->[14]; - $ret = OWFSCOUNT_SetPage($hash,14,$newdata); - $ret = OWFSCOUNT_GetPage($hash,14,0); - $ret = OWFSCOUNT_SetPage($hash,14,$olddata); - #-- Unknown interface - }else{ - return "OWCOUNT: InitializeDevice with wrong IODev type $interface"; - } - #Log 1,"FIRST CHECK: written $newdata, read ".substr($hash->{owg_str}->[14],0,length($newdata)); - my $nomid = ( substr($hash->{owg_str}->[14],0,length($newdata)) ne $newdata ); - #-- OWX interface - if( $interface eq "OWX" ){ - $ret = OWXCOUNT_GetPage($hash,0,0); - $olddata = $hash->{owg_str}->[0]; - $ret = OWXCOUNT_SetPage($hash,0,$newdata); - $ret = OWXCOUNT_GetPage($hash,0,0); - $ret = OWXCOUNT_SetPage($hash,0,$olddata); - }elsif( $interface eq "OWX_ASYNC" ){ - eval { - $ret = OWX_ASYNC_RunToCompletion($hash,OWXCOUNT_PT_InitializeDevicePage($hash,0,$newdata)); - }; - $ret = GP_Catch($@) if $@; - #-- OWFS interface - }elsif( $interface eq "OWServer" ){ - $ret = OWFSCOUNT_GetPage($hash,0,0); - $olddata = $hash->{owg_str}->[0]; - $ret = OWFSCOUNT_SetPage($hash,0,$newdata); - $ret = OWFSCOUNT_GetPage($hash,0,0); - $ret = OWFSCOUNT_SetPage($hash,0,$olddata); - #-- Unknown interface - }else{ - return "OWCOUNT: InitializeDevice with wrong IODev type $interface"; - } - #Log 1,"SECOND CHECK: written $newdata, read ".substr($hash->{owg_str}->[0],0,length($newdata)); - my $nomem = ( substr($hash->{owg_str}->[0],0,length($newdata)) ne $newdata ); - #-- Here we test if writing the memory is ok. - if( !$nomid && $nomem ){ - Log3 $name,1,"OWCOUNT: model attribute of $name set to DS2423enew"; - CommandAttr (undef,"$name model DS2423enew"); - CommandAttr (undef,"$name nomemory 0"); - } elsif( $nomid && $nomem ){ - Log3 $name,1,"OWCOUNT: model attribute of $name set to DS2423eold because no memory found"; - CommandAttr (undef,"$name model DS2423eold"); - CommandAttr (undef,"$name nomemory 1"); - } - - #-- Set state to initialized - readingsSingleUpdate($hash,"state","initialized",1); - return undef; } @@ -1315,7 +1315,7 @@ sub OWCOUNT_Set($@) { $data.=" ".$a[$i]; } if( length($data) > 32 ){ - Log3 $name,1,"OWXCOUNT: Memory data truncated to 32 characters"; + Log3 $name,3,"OWCOUNT: Memory data truncated to 32 characters"; $data=substr($data,0,32); }elsif( length($data) < 32 ){ for(my $i=length($data)-1;$i<32;$i++){ @@ -1360,7 +1360,7 @@ sub OWCOUNT_Set($@) { $hash->{READINGS}{$owg_channel[$page-14]}{FACTOR} - $a[3]; $data = sprintf("%4d-%02d-%02d midnight %7.2f", $year+1900,$month+1,$day,$midnew); - #Log 1,"OLD MIDNIGHT ".$hash->{owg_midnight}->[$page-14]." NEW $midnew"; + Log3 $name,5,"OWCOUNT: old midnight vakue ".$hash->{owg_midnight}->[$page-14].", replaced by $midnew"; $ret = OWCOUNT_SetPage($hash,$page,$data); } } @@ -1447,12 +1447,12 @@ sub OWCOUNT_store($$$) { } else { Log3 $name,1,"OWCOUNT_store: Cannot open $filename for writing!"; } - return undef; + return $ret; } ######################################################################################## # -# Recall daily start value from a file +# OWCOUNT_recall Recall daily start value from a file # # Parameter hash,filename # @@ -1470,8 +1470,18 @@ sub OWCOUNT_recall($$) { close(OWXFILE); return $line; } - Log3 $name,1, "OWCOUNT_recall: Cannot open $filename for reading!"; - return undef;; + Log3 $name,1, "OWCOUNT_recall: Cannot open $filename for reading, 2nd attempt"; + $ret = OWCOUNT_store($hash,$filename,0); + if (!$ret){ + $ret = open(OWXFILE, "< $mp/FHEM/$filename" ); + if( $ret ){ + my $line = readline OWXFILE; + close(OWXFILE); + return $line; + } + Log3 $name,1, "OWCOUNT_recall: Cannot open $filename for reading - tried twice"; + return "error"; + } } ######################################################################################## @@ -1494,6 +1504,8 @@ sub OWCOUNT_Undef ($) { # The following subroutines in alphabetical order are only for a 1-Wire bus connected # via OWFS # +# TODO: So far no automatic recognition of DS2423 / Emulator +# # Prefix = OWFSCOUNT # ######################################################################################## @@ -1603,76 +1615,125 @@ sub OWFSCOUNT_SetPage($$$) { # OWXCOUNT_BinValues - Process reading from one device - translate binary into raw # # Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string # -######################################################################################## +# +####################################################################################### -sub OWXCOUNT_BinValues($$$$$) { - my ($hash, $context, $owx_dev, $select, $res) = @_; +sub OWXCOUNT_BinValues($$$$$$$) { + my ($hash, $context, $proc, $owx_dev, $crcpart, $numread, $res) = @_; - #-- unused are success, reset, data - - return undef unless (defined $context and $context =~ /^(get|set)page\.([\d]+)(\.final|)$/); + #-- hash of the busmaster + my $master = $hash->{IODev}; + my $name = $hash->{NAME}; + my @data=[]; + my $value; + my $msg; + OWX_WDBG($name,"OWCOUNT_BinValues called for device $name in context $context with ",$res) + if( $main::owx_debug>2 ); + return undef unless (defined $context and $context =~ /^(get|set|check)page\.([\d]+)(\.final|)$/); my $cmd = $1; my $page = $2; my $final = $3; - my $name = $hash->{NAME}; - - Log3 ($name,5,"OWXCount_BinValues context: $context, $cmd page: $page, final: ".(defined $final ? $final : "undef")); - + #=============== get memory + counter =============================== if ($cmd eq "get") { - my ($i,$j,$k,@data,@writedata,$strval,$value); + my (@data,$strval,$value); my $change = 0; + @data=split(//,$res); #-- process results - @data=split(//,$res); - @writedata = split(//,$select); - return "invalid data length, ".int(@data)." instead of 42 bytes in three steps" - if( int(@data) < 42); - #return "invalid data" - # if (ord($data[17])<=0); - return "invalid CRC, ".ord($data[40])." ".ord($data[41]) - if (OWX_CRC16($select.substr($res,0,40),$data[40],$data[41]) == 0); - - #-- first 3 command, next 32 are memory - #my $res2 = "OWCOUNT FIRST 10 BYTES for device $owx_dev ARE "; - #for($i=0;$i<10;$i++){ - # $j=int(ord(substr($res,$i,1))/16); - # $k=ord(substr($res,$i,1))%16; - # $res2.=sprintf "0x%1x%1x ",$j,$k; - #} - #main::Log(1, $res2); + if(ord($data[17])<=0){ + #-- invalid data: do not die, but change memory flags + if( $page > 13 ){ + $owg_memory[1]=0; + }else{ + $owg_memory[0]=0; + } + $owg_memory[2]=1; + $msg="memory data could not be read"; + }else{ + if( $page > 13 ){ + $owg_memory[1]=1; + }else{ + $owg_memory[0]=1; + } + $owg_memory[2]=1; + } + + if( int(@data) < 42){ + $msg="$name returns invalid data length, ".int(@data)." instead of 42 bytes"; + }elsif (OWX_CRC16($crcpart.substr($res,0,40),$data[40],$data[41]) == 0){ + $msg="$name returns invalid CRC, ".ord($data[40])." ".ord($data[41]); + } + OWX_WDBG($name,"OWXCOUNT_BinValues: ".$msg,"") + if( $main::owx_debug>2 ); #-- my $nomemory = defined($attr{$name}{"nomemory"}) ? $attr{$name}{"nomemory"} : 0; if( $nomemory==0 ){ #-- memory part, treated as string $strval=substr($res,0,32); - #Log 1," retrieved on device $owx_dev for page $page STRING $strval"; + #Log3 $name,5,"OWCOUNT: retrieved from memory for page $page ==> $strval"; } else { $strval = OWCOUNT_recall($hash,"OWCOUNT_".$hash->{NAME}."_".$page.".dat"); + #Log3 $name,5,"OWCOUNT: retrieved from disk for page $page ==> $strval"; } $hash->{owg_str}->[$page]= defined $strval ? $strval : ""; #-- counter part if( ($page == 14) || ($page == 15) ){ @data=split(//,substr($res,32)); if ( ($data[4] | $data[5] | $data[6] | $data[7]) ne "\x00" ){ - #Log 1, "device $owx_dev returns invalid data ".ord($data[4])." ".ord($data[5])." ".ord($data[6])." ".ord($data[7]); - return "device $owx_dev returns invalid data"; + OWX_WDBG($name, "device $name returns invalid data ".ord($data[4])." ".ord($data[5])." ".ord($data[6])." ".ord($data[7])," "); } #-- counter value $value = (ord($data[3])<<24) + (ord($data[2])<<16) +(ord($data[1])<<8) + ord($data[0]); $hash->{owg_val}->[$page-14] = $value; #-- midnight value - Log3 $name,5, "OWCOUNT_BinValues ParseMidnight: ".(defined $strval ? $strval : "undef"); + #Log3 $name,1, "OWCOUNT_BinValues ParseMidnight: ".(defined $strval ? $strval : "undef"); OWCOUNT_ParseMidnight($hash,$strval,$page); } #-- and now from raw to formatted values $hash->{PRESENT} = 1; if( $final ) { my $value = OWCOUNT_FormatValues($hash); - Log3 $name,5, "OWCOUNT_BinValues->FormatValues returns: ".(defined $value ? $value : "undef"); } + #=============== set memory =============================== + #-- for setting a page we need a second step where the scratchpad is copied into memory + }elsif (($cmd eq "set") && !$final ) { + my $select="\x5A".substr($res,0,3); + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 inserts at top of queue + OWX_Qomplex($master, $hash, "setpage.$page.final", 16, $owx_dev, $select, 0, 6, 10, \&OWXCOUNT_BinValues, 0); + #-- and a third step where this is finalized + }elsif (($cmd eq "set") && $final ) { + if( substr($res,4,1) ne "\xAA" ){ + if( $page > 13 ){ + $owg_memory[1]=0; + }else{ + $owg_memory[0]=0; + } + }else{ + if( $page > 13){ + $owg_memory[1]=1; + }else{ + $owg_memory[0]=1; + } + } + #-- change applied + $owg_memory[2]=1; } return undef; } @@ -1699,8 +1760,6 @@ sub OWXCOUNT_GetPage($$$) { #-- reset presence $hash->{PRESENT} = 0; - my ($i,$j,$k); - #=============== wrong value requested =============================== if( ($page<0) || ($page>15) ){ return "wrong memory page requested"; @@ -1713,33 +1772,45 @@ sub OWXCOUNT_GetPage($$$) { $select=sprintf("\xA5%c%c",$ta1,$ta2); my $context = "getpage.".$page.($final ? ".final" : ""); - #-- reset the bus - OWX_Reset($master); - #-- reading 9 + 3 + 40 data bytes (32 byte memory, 4 byte counter + 4 byte zeroes) and 2 CRC bytes = 54 bytes - $res=OWX_Complex($master,$owx_dev,$select,42); - if( $res eq 0 ){ - return "device $owx_dev not accessible in reading page $page"; - } - #-- process results - if( length($res) < 54 ) { - #Log 1, "OWXCOUNT: warning, have received ".length($res)." bytes in first step"; - #-- read the data in a second step - $res.=OWX_Complex($master,"","",0); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + #-- reset the bus + OWX_Reset($master); + #-- reading 9 + 3 + 40 data bytes (32 byte memory, 4 byte counter + 4 byte zeroes) and 2 CRC bytes = 54 bytes + $res=OWX_Complex($master,$owx_dev,$select,42); + if( $res eq 0 ){ + return "device $owx_dev not accessible in reading page $page"; + } #-- process results if( length($res) < 54 ) { - #Log 1, "OWXCOUNT: warning, have received ".length($res)." bytes in second step"; - #-- read the data in a third step + #Log 1, "OWXCOUNT: warning, have received ".length($res)." bytes in first step"; + #-- read the data in a second step $res.=OWX_Complex($master,"","",0); - } - } - #-- reset the bus (needed to stop receiving data ?) - OWX_Reset($master); - #-- for processing we need 45 bytes - return "$owx_dev not accessible in reading" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=54); - return OWXCOUNT_BinValues($hash,$context,$owx_dev,$select,substr($res,12)); + #-- process results + if( length($res) < 54 ) { + #Log 1, "OWXCOUNT: warning, have received ".length($res)." bytes in second step"; + #-- read the data in a third step + $res.=OWX_Complex($master,"","",0); + } + } + #-- reset the bus (needed to stop receiving data ?) + OWX_Reset($master); + #-- for processing we need 45 bytes + return "$owx_dev not accessible in reading" + if( $res eq 0 ); + return "$owx_dev has returned invalid data" + if( length($res)!=54); + eval { + OWXCOUNT_BinValues($hash,$context,0,$owx_dev,$select,45,substr($res,12)); + }; + return $@ ? $@ : undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 1 additional reset after last action + OWX_Qomplex($master, $hash, $context, 1, $owx_dev, $select, $select, 45, 12, \&OWXCOUNT_BinValues, 0); + return undef; + } } ######################################################################################## @@ -1747,7 +1818,8 @@ sub OWXCOUNT_GetPage($$$) { # OWXCOUNT_SetPage - Set one memory page of device # # Parameter hash = hash of device addressed -# page = "alarm" or "status" +# page = 0..15 +# data = string to set into memory # ######################################################################################## @@ -1757,8 +1829,6 @@ sub OWXCOUNT_SetPage($$$) { my ($select, $res, $res2, $res3); - my ($i,$j,$k); - #-- ID of the device, hash of the busmaster my $owx_dev = $hash->{ROM_ID}; my $master = $hash->{IODev}; @@ -1778,64 +1848,59 @@ sub OWXCOUNT_SetPage($$$) { my $ta1 = ($page*32) & 255; #Log 1, "OWXCOUNT: setting page Nr. $ta2 $ta1 $data"; $select=sprintf("\x0F%c%c",$ta1,$ta2).$data; - - #-- first command, next 2 are address, then data - #$res2 = "OWCOUNT SET PAGE 1 device $owx_dev "; - #for($i=0;$i<10;$i++){ - # $j=int(ord(substr($select,$i,1))/16); - # $k=ord(substr($select,$i,1))%16; - # $res2.=sprintf "0x%1x%1x ",$j,$k; - #} - #main::Log(1, $res2); - - #-- reset the bus - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - if( $res eq 0 ){ - return "device $owx_dev not accessible in writing scratchpad"; - } - - #-- issue the match ROM command \x55 and the read scratchpad command - # \xAA, receiving 2 address bytes, 1 status byte and scratchpad content - $select = "\xAA"; - #-- reset the bus - OWX_Reset($master); - #-- reading 9 + 3 + up to 32 bytes - # TODO: sometimes much less than 28 - $res=OWX_Complex($master,$owx_dev,$select,28); - if( length($res) < 13 ){ - return "device $owx_dev not accessible in reading scratchpad"; - } - - #-- first 1 command, next 2 are address, then data - #$res3 = substr($res,9,10); - #$res2 = "OWCOUNT SET PAGE 2 device $owx_dev "; - #for($i=0;$i<10;$i++){ - # $j=int(ord(substr($res3,$i,1))/16); - # $k=ord(substr($res3,$i,1))%16; - # $res2.=sprintf "0x%1x%1x ",$j,$k; - #} - #main::Log(1, $res2); - #-- issue the match ROM command \x55 and the copy scratchpad command - # \x5A followed by 3 byte authentication code obtained in previous read - $select="\x5A".substr($res,10,3); - #-- first command, next 2 are address, then data - #$res2 = "OWCOUNT SET PAGE 3 device $owx_dev "; - #for($i=0;$i<10;$i++){ - # $j=int(ord(substr($select,$i,1))/16); - # $k=ord(substr($select,$i,1))%16; - # $res2.=sprintf "0x%1x%1x ",$j,$k; - #} - #main::Log(1, $res2); - - #-- reset the bus - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,6); - - #-- process results - if( $res eq 0 ){ - return "device $owx_dev not accessible for copying scratchpad"; - } + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + #-- reset the bus + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + if( $res eq 0 ){ + return "OWCOUNT: device $owx_dev not accessible in writing scratchpad"; + } + #-- issue the match ROM command \x55 and the read scratchpad command + # \xAA, receiving 2 address bytes, 1 status byte and scratchpad content + $select = "\xAA"; + #-- reset the bus + OWX_Reset($master); + #-- reading 9 + 3 + up to 32 bytes + # TODO: sometimes much less than 28 + $res=OWX_Complex($master,$owx_dev,$select,28); + if( length($res) < 13 ){ + return "OWCOUNT: device $owx_dev not accessible in reading scratchpad"; + } + #-- issue the match ROM command \x55 and the copy scratchpad command + # \x5A followed by 3 byte authentication code obtained in previous read + $select="\x5A".substr($res,10,3); + #-- reset the bus + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,6); + #-- process results + if( $res eq 0 ){ + return "OWCOUNT: device $owx_dev not accessible for copying scratchpad"; + } + if( substr($res,13,1) ne "\xAA" ){ + if( $page > 13){ + $owg_memory[1]=0; + }else{ + $owg_memory[0]=0; + } + }else{ + if( $page > 13){ + $owg_memory[1]=1; + }else{ + $owg_memory[0]=1; + } + } + $owg_memory[2]=1; + return undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 8 prevents from filling up with 0xFF + OWX_Qomplex($master, $hash, undef, 8, $owx_dev, $select, $select, 35, 10, undef, 0); + #-- The third step of copying the scratchpad into memory can be scheduled only when the authorization code has been received + # will be done in the callback of the following line + OWX_Qomplex($master, $hash, "setpage.".$page, 0, $owx_dev, "\xAA", 0, 37, 10, \&OWXCOUNT_BinValues, 0); + } return undef; } @@ -1885,7 +1950,7 @@ sub OWXCOUNT_PT_GetPage($$$) { PT_WAIT_THREAD($thread->{pt_execute}); die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - if (my $ret = OWXCOUNT_BinValues($hash,"getpage.".$page.($final ? ".final" : ""),$owx_dev,$thread->{'select'},$thread->{response})) { + if (my $ret = OWXCOUNT_BinValues($hash,"getpage.".$page.($final ? ".final" : ""),0,$owx_dev,$thread->{'select'},0,$thread->{response})) { die $ret; } PT_END; @@ -2026,13 +2091,13 @@ sub OWXCOUNT_PT_InitializeDevicePage($$$) {

    Example


    define OWC OWCOUNT 1D.CE780F000000 60
    - attr OWC AName Energie|energy + attr OWC AName energy|W
    - attr OWC AUnit kWh|kWh + attr OWC AUnit kWh
    attr OWC APeriod hour
    - attr OWC ARate Leistung|power + attr OWC ARate power|P
    attr OWX_AMode daily
    @@ -2138,13 +2203,13 @@ sub OWXCOUNT_PT_InitializeDevicePage($$$) { =end html diff --git a/fhem/FHEM/21_OWID.pm b/fhem/FHEM/21_OWID.pm index 3795c2c82..d3728513b 100644 --- a/fhem/FHEM/21_OWID.pm +++ b/fhem/FHEM/21_OWID.pm @@ -66,9 +66,9 @@ BEGIN { use GPUtils qw(:all); use ProtoThreads; no warnings 'deprecated'; -sub Log($$); +sub Log3($$$); -my $owx_version="5.15"; +my $owx_version="6.0beta6"; #-- declare variables my %gets = ( "present" => "", @@ -107,8 +107,7 @@ sub OWID_Initialize ($) { $hash->{AttrFn} = "OWID_Attr"; $hash->{NotifyFn} = "OWID_Notify"; $hash->{InitFn} = "OWID_Init"; - $hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model loglevel:0,1,2,3,4,5 ". - "interval ". + $hash->{AttrList} = "IODev do_not_notify:0,1 showtime:0,1 model interval". $readingFnAttributes; #--make sure OWX is loaded so OWX_CRC is available if running with OWServer @@ -212,7 +211,7 @@ sub OWID_Define ($$) { $modules{OWID}{defptr}{$id} = $hash; #-- readingsSingleUpdate($hash,"state","Defined",1); - Log 3, "OWID: Device $name defined."; + Log3 $name,1, "OWID: Device $name defined."; $hash->{NOTIFYDEV} = "global"; @@ -240,7 +239,7 @@ sub OWID_Notify ($$) { ######################################################################################### # -# OWID_Define - Implements InitFn function +# OWID_Init - Implements InitFn function # # Parameter hash = hash of device addressed # @@ -531,6 +530,10 @@ sub OWID_Undef ($) {
    Returns 1 if this 1-Wire device is present, otherwise 0. +

    Attributes

    + =end html =cut diff --git a/fhem/FHEM/21_OWLCD.pm b/fhem/FHEM/21_OWLCD.pm index 1392e6242..82f6a904e 100644 --- a/fhem/FHEM/21_OWLCD.pm +++ b/fhem/FHEM/21_OWLCD.pm @@ -36,6 +36,8 @@ # set reset => reset the display # set test => display a test content # +# attr lcdgeometry => LCD geometry values are 0-32-64-96 or 0-64-20-84 +# # Careful: Not ASCII ! strange Codepage ######################################################################################## # @@ -77,15 +79,15 @@ no warnings 'deprecated'; sub Log3($$$); -my $owx_version="5.3"; +my $owx_version="6.0beta6"; #-- controller may be HD44780 or KS0073 # these values have to be changed for different display # geometries or memory maps my $lcdcontroller = "KS0073"; my $lcdlines = 4; my $lcdchars = 20; -my @lcdpage = (0,32,64,96); -#my @lcdpage = (0,64,20,84); + +my @lcdpage = (0,32,64,96); #-- declare variables my %gets = ( @@ -137,7 +139,8 @@ sub OWLCD_Initialize ($) { $hash->{InitFn} = "OWLCD_Init"; $hash->{AttrFn} = "OWLCD_Attr"; my $attlist = "IODev do_not_notify:0,1 showtime:0,1 ". - ""; + "lcdgeometry:0-32-64-96,0-64-20-84 ". + $readingFnAttributes; $hash->{AttrList} = $attlist; #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer @@ -208,6 +211,14 @@ sub OWLCD_Define ($$) { return undef; } +######################################################################################## +# +# OWLCD_Notify - Implements Notify function +# +# Parameter hash = hash of device addressed +# +######################################################################################## + sub OWLCD_Notify ($$) { my ($hash,$dev) = @_; if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) { @@ -216,6 +227,14 @@ sub OWLCD_Notify ($$) { } } +######################################################################################## +# +# OWLCD_Init - Implements Init function +# +# Parameter hash = hash of device addressed +# +######################################################################################## + sub OWLCD_Init($) { my ($hash) = @_; #-- Initialization reading according to interface type @@ -275,6 +294,14 @@ sub OWLCD_Attr(@) { } last; }; + $key eq "lcdgeometry" and do { + if( $value eq "0-32-64-96" ){ + @lcdpage = (0,32,64,96); + }elsif( $value eq "0-64-20-84" ){ + @lcdpage = (0,64,20,84); + } + last; + }; }; #} elsif ( $do eq "del" ) { # ARGUMENT_HANDLER: { @@ -298,6 +325,7 @@ sub OWLCD_Get($@) { my $reading = $a[1]; my $name = $hash->{NAME}; my $model = $hash->{OW_MODEL}; + my $master = $hash->{IODev}; my $value = undef; my $ret = ""; my $offset; @@ -347,7 +375,12 @@ sub OWLCD_Get($@) { return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"gpio",""); } else { $value = OWXLCD_Get($hash,"gpio"); - return "$name.gpio => $value"; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWLCD: $name getting gpio, please wait for completion"; + }else{ + return "$name.gpio => $value"; + } } } @@ -362,7 +395,12 @@ sub OWLCD_Get($@) { return "$name.counter => ".main::ReadingsVal($hash->{NAME},"counter",""); } else { $value = OWXLCD_Get($hash,"counter"); - return "$name.counter => $value"; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWLCD: $name getting counter, please wait for completion"; + }else{ + return "$name.counter => $value"; + } } } @@ -377,14 +415,18 @@ sub OWLCD_Get($@) { return "$name.gpio => ".main::ReadingsVal($hash->{NAME},"version",""); } else { $value = OWXLCD_Get($hash,"version"); - return "$name.version => $owx_version (LCD firmware $value)"; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWLCD: $name getting version, please wait for completion"; + }else{ + return "$name.version => $owx_version (LCD firmware $value)"; + } } } #-- get EEPROM content if($a[1] eq "memory") { my $page = (defined $a[2] and $a[2] =~ m/\d/) ? int($a[2]) : 0; - Log3 $name,1,"Calling GetMemory with page $page"; if ($hash->{ASYNC}) { eval { $ret = OWX_ASYNC_RunToCompletion($hash,OWXLCD_PT_GetMemory($hash,$page)); @@ -394,7 +436,12 @@ sub OWLCD_Get($@) { return "$name $reading $page => ".main::ReadingsVal($hash->{NAME},"memory$page",""); } else { $value = OWXLCD_GetMemory($hash,$page); - return "$name $reading $page => $value"; + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWLCD: $name memory page $page, please wait for completion"; + }else{ + return "$name $reading $page => $value"; + } } } } @@ -660,8 +707,7 @@ sub OWLCD_Set($@) { if( (0 > $line) || ($line > 6) ); return "OWLCD: Wrong line length, must be <=16 " if( length($value) > 16 ); - #-- check value and write to device - Log3 $name,1,"Calling SetMemory with page $line"; + #-- write to device if ($hash->{ASYNC}) { eval { OWX_ASYNC_Schedule( $hash, OWXLCD_PT_SetMemory($hash, $line, $value) ); @@ -755,334 +801,6 @@ sub OWLCD_Undef ($) { return undef; } -######################################################################################## -# -# OWXLCD_Byte - write a single byte to the LCD device -# -# Parameter hash = hash of device addressed -# cmd = register or data -# byte = byte -# -######################################################################################## - -sub OWXLCD_Byte($$$) { - - my ($hash,$cmd,$byte) = @_; - - my ($select, $select2, $res, $res2, $res3, @data); - - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - my $owx_rnf = substr($owx_dev,3,12); - my $owx_f = substr($owx_dev,0,2); - - #-- hash of the busmaster - my $master = $hash->{IODev}; - - my ($i,$j,$k); - - #=============== write to LCD register =============================== - if ( $cmd eq "register" ) { - #-- issue the read LCD register command \x10 - $select = sprintf("\x10%c",$byte); - #=============== write to LCD data =============================== - }elsif ( $cmd eq "data" ) { - #-- issue the read LCD data command \x12 - $select = sprintf("\x12%c",$byte); - #=============== wrong value requested =============================== - } else { - return "OWXLCD: Wrong byte write attempt"; - } - - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for writing a byte"; - } - - return undef; -} - -######################################################################################## -# -# OWXLCD_PT_Byte - write a single byte to the LCD device async -# -# Parameter hash = hash of device addressed -# cmd = register or data -# byte = byte -# -######################################################################################## - -sub OWXLCD_PT_Byte($$$) { - - my ($hash,$cmd,$byte) = @_; - - return PT_THREAD(sub { - my ($thread) = @_; - my ($select); - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - #-- hash of the busmaster - my $master = $hash->{IODev}; - my ($i,$j,$k); - - PT_BEGIN($thread); - - #=============== write to LCD register =============================== - if ( $cmd eq "register" ) { - #-- issue the read LCD register command \x10 - $select = sprintf("\x10%c",$byte); - #=============== write to LCD data =============================== - }elsif ( $cmd eq "data" ) { - #-- issue the read LCD data command \x12 - $select = sprintf("\x12%c",$byte); - #=============== wrong value requested =============================== - } else { - die "OWXLCD: Wrong byte write attempt"; - } - - #"byte" - $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); - PT_WAIT_THREAD($thread->{pt_execute}); - die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - PT_END; - }); -} - -######################################################################################## -# -# OWXLCD_Get - get values from the LCD device -# -# Parameter hash = hash of device addressed -# cmd = command string -# -######################################################################################## - -sub OWXLCD_Get($$) { - - my ($hash,$cmd) = @_; - - my ($select, $select2, $len, $addr, $res, $res2); - - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - - #-- hash of the busmaster - my $master = $hash->{IODev}; - - my ($i,$j,$k); - - #=============== fill scratch with gpio ports =============================== - if ( $cmd eq "gpio" ) { - #-- issue the read GPIO command \x22 (1 byte) - $select = "\x22"; - $len = 1; - #=============== fill scratch with gpio counters =============================== - }elsif ( $cmd eq "counter" ) { - #-- issue the read counter command \x23 (8 bytes) - $select = "\x23"; - $len = 8; - #=============== fill scratch with version =============================== - }elsif ( $cmd eq "version" ) { - #-- issue the read version command \x41 - $select = "\x41"; - $len = 16; - } else { - return "OWXLCD: Wrong get attempt"; - } - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for reading"; - } - - #-- issue the read scratchpad command \xBE - $select2 = "\xBE"; - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select2,$len); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for reading in 2nd step"; - } - OWXLCD_BinValues($hash, "get.".$cmd, 1, 1, $owx_dev, $select2, $len, substr($res,10)); - - return main::ReadingsVal($hash->{NAME},$cmd,""); -} - -######################################################################################## -# -# OWXLCD_PT_Get - get values from the LCD device async -# -# Parameter hash = hash of device addressed -# cmd = command string -# -######################################################################################## - -sub OWXLCD_PT_Get($$) { - - my ($hash,$cmd) = @_; - - return PT_THREAD(sub { - - my ($thread) = @_; - my ($select); - - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - - #-- hash of the busmaster - my $master = $hash->{IODev}; - - my ($i,$j,$k); - - PT_BEGIN($thread); - #=============== fill scratch with gpio ports =============================== - if ( $cmd eq "gpio" ) { - #-- issue the read GPIO command \x22 (1 byte) - $select = "\x22"; - $thread->{len} = 1; - #=============== fill scratch with gpio counters =============================== - }elsif ( $cmd eq "counter" ) { - #-- issue the read counter command \x23 (8 bytes) - $select = "\x23"; - $thread->{len} = 8; - #=============== fill scratch with version =============================== - }elsif ( $cmd eq "version" ) { - #-- issue the read version command \x41 - $select = "\x41"; - $thread->{len} = 16; - } else { - die("OWXLCD: Wrong get attempt"); - } - #"get.prepare" - $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); - PT_WAIT_THREAD($thread->{pt_execute}); - die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - - #-- issue the read scratchpad command \xBE - $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE", $thread->{len}); - PT_WAIT_THREAD($thread->{pt_execute}); - die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - - OWXLCD_BinValues($hash, "get.".$cmd, 1, 1, $owx_dev, "\xBE", $thread->{len}, $thread->{pt_execute}->PT_RETVAL()); - - PT_END; - }); -} - -######################################################################################## -# -# OWXLCD_GetMemory - get memory page from LCD device (EXPERIMENTAL) -# -# Parameter hash = hash of device addressed -# page = memory page address -# -######################################################################################## - -sub OWXLCD_GetMemory($$) { - - my ($hash,$page) = @_; - - my ($select, $res, $res2, $res3); - - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - my $owx_rnf = substr($owx_dev,3,12); - my $owx_f = substr($owx_dev,0,2); - - #-- hash of the busmaster - my $master = $hash->{IODev}; - - my ($i,$j,$k); - - #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E - #Log 1," page read is ".$page; - $select = sprintf("\4E%c\x10\x37",$page); - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for reading"; - } - - #-- sleeping for some time - #select(undef,undef,undef,0.5); - - #-- issue the match ROM command \x55 and the read scratchpad command \xBE - $select = "\xBE"; - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,16); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for reading in 2nd step"; - } - OWXLCD_BinValues($hash, "get.memory.$page", 1, 1, $owx_dev, $select, 16, substr($res,11,16)); - #-- process results (10 bytes or more have been sent) - #$res2 = substr($res,11,16); - #return $res2; - return main::ReadingsVal($hash->{NAME},"memory$page",""); -} - -######################################################################################## -# -# OWXLCD_PT_GetMemory - get memory page from LCD device async (EXPERIMENTAL) -# -# Parameter hash = hash of device addressed -# page = memory page address -# -######################################################################################## - -sub OWXLCD_PT_GetMemory($$) { - - my ($hash,$page) = @_; - - return PT_THREAD(sub { - - my ($thread) = @_; - my ($select); - - #-- ID of the device - my $owx_dev = $hash->{ROM_ID}; - - #-- hash of the busmaster - my $master = $hash->{IODev}; - - PT_BEGIN($thread); - #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E - #Log 1," page read is ".$page; - $select = sprintf("\4E%c\x10\x37",$page); - #"prepare" - $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); - PT_WAIT_THREAD($thread->{pt_execute}); - die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - - #-- sleeping for some time - $thread->{ExecuteTime} = gettimeofday()+0.5; - PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime}); - delete $thread->{ExecuteTime}; - - #-- issue the match ROM command \x55 and the read scratchpad command \xBE - $thread->{'select'} = "\xBE"; - #"get.memory.$page" - $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},16); - PT_WAIT_THREAD($thread->{pt_execute}); - die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - - OWXLCD_BinValues($hash, "get.memory.$page", 1, 1, $owx_dev, $thread->{'select'}, 16, $thread->{pt_execute}->PT_RETVAL()); - #-- process results (10 bytes or more have been sent) - #$res2 = substr($res,11,16); - #return $res2; - PT_END; - }); -} - ######################################################################################## # # OWXLCD_InitializeDevice - initialize the display @@ -1144,9 +862,312 @@ sub OWXLCD_InitializeDevice($) { } else { return "OWXLCD: Wrong LCD controller type"; } - } +######################################################################################## +# +# OWXLCD_Byte - write a single byte to the LCD device +# +# Parameter hash = hash of device addressed +# cmd = register or data +# byte = byte +# +######################################################################################## + +sub OWXLCD_Byte($$$) { + + my ($hash,$cmd,$byte) = @_; + + my ($select, $select2, $res, $res2, $res3, @data); + + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + my $owx_rnf = substr($owx_dev,3,12); + my $owx_f = substr($owx_dev,0,2); + + #-- hash of the busmaster + my $master = $hash->{IODev}; + + my ($i,$j,$k); + + #=============== write to LCD register =============================== + if ( $cmd eq "register" ) { + #-- issue the read LCD register command \x10 + $select = sprintf("\x10%c",$byte); + #=============== write to LCD data =============================== + }elsif ( $cmd eq "data" ) { + #-- issue the read LCD data command \x12 + $select = sprintf("\x12%c",$byte); + #=============== wrong value requested =============================== + } else { + return "OWXLCD: Wrong byte write attempt"; + } + + #-- write to device + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for writing a byte"; + } + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "writebyte", 0, $owx_dev,$select, 0, 0, 0, undef, 0); + } + return undef; +} + +######################################################################################## +# +# OWXLCD_Get - get values from the LCD device +# +# Parameter hash = hash of device addressed +# cmd = command string +# +######################################################################################## + +sub OWXLCD_Get($$) { + + my ($hash,$cmd) = @_; + + my ($select, $select2, $len, $addr, $res, $res2); + + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + + #-- hash of the busmaster + my $master = $hash->{IODev}; + + my ($i,$j,$k); + + #=============== fill scratch with gpio ports =============================== + if ( $cmd eq "gpio" ) { + #-- issue the read GPIO command \x22 (1 byte) + $select = "\x22"; + $len = 1; + #=============== fill scratch with gpio counters =============================== + }elsif ( $cmd eq "counter" ) { + #-- issue the read counter command \x23 (8 bytes) + $select = "\x23"; + $len = 8; + #=============== fill scratch with version =============================== + }elsif ( $cmd eq "version" ) { + #-- issue the read version command \x41 + $select = "\x41"; + $len = 16; + } else { + return "OWXLCD: Wrong get attempt"; + } + #-- write to device + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for reading"; + } + + #-- issue the read scratchpad command \xBE + $select2 = "\xBE"; + #-- write to device + + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select2,$len); + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for reading in 2nd step"; + } + OWXLCD_BinValues($hash, "get.".$cmd, 1, $owx_dev, "\xBE", $len, substr($res,10)); + + return main::ReadingsVal($hash->{NAME},$cmd,""); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "get.prep.".$len, 0, $owx_dev, $select, $cmd, 1, 10, \&OWXLCD_BinValues, 0); + return undef; + } +} + +######################################################################################## +# +# OWXLCD_GetMemory - get memory page from LCD device (EXPERIMENTAL) +# +# Parameter hash = hash of device addressed +# page = memory page address +# +######################################################################################## + +sub OWXLCD_GetMemory($$) { + + my ($hash,$page) = @_; + + my ($select, $res, $res2, $res3); + + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + my $owx_rnf = substr($owx_dev,3,12); + my $owx_f = substr($owx_dev,0,2); + + #-- hash of the busmaster + my $master = $hash->{IODev}; + + my ($i,$j,$k); + + #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E + #Log 1," page read is ".$page; + $select = sprintf("\4E%c\x10\x37",$page); + #-- write to device + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for reading"; + } + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + $select = "\xBE"; + #-- write to device + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,16); + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for reading in 2nd step"; + } + OWXLCD_BinValues($hash, "get.memory.$page", 1, $owx_dev, $select, 16, substr($res,11,16)); + #-- process results (10 bytes or more have been sent) + #$res2 = substr($res,11,16); + #return $res2; + return main::ReadingsVal($hash->{NAME},"memory$page",""); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "get.prep.16", 0, $owx_dev, $select, "memory.$page", 1, 11, \&OWXLCD_BinValues, 0); + return undef; + } +} + +######################################################################################## +# +# OWXLCD_BinValues - Process reading from one device - translate binary into raw +# +# Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string +# +# +######################################################################################## + +sub OWXLCD_BinValues($$$$$$$) { + my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_; + + + my ($ret,@data,$select); + my $change = 0; + + my $master = $hash->{IODev}; + my $name = $hash->{NAME}; + + my $msg; + OWX_WDBG($name,"OWLCD: $name: BinValues called with ",$res) + if( $main::owx_debug>2 ); + + #-- process results + #die "OWVAR: $name not accessible in 2nd step" unless ( defined $res and $res ne 0 ); + + #=============== setline 2nd step =============================== + if( $context eq "setline" ) { + #-- issue the copy scratchpad to LCD command \x48 + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "", 16, $owx_dev,"\x48", 0, 0, 0, undef, 0); + #=============== seteeprom 2nd step =============================== + }elsif( $context eq "seteeprom" ) { + #-- issue the copy scratchpad to EEPROM command \x39 + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "", 16, $owx_dev,"\x39", 0, 0, 0, undef, 0); + #=============== eraseicon 2nd step =============================== + }elsif( $context eq "eraseicon.1" ) { + #-- SEGRAM addres to 0 = \x40, + $select = "\x10\x40"; + #-- write 16 zeros to scratchpad + $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "eraseicon.2", 16, $owx_dev, $select, 0, 0, 0, \&OWXLCD_BinValues, 0); + #=============== eraseicon 3rd step =============================== + }elsif( $context eq "eraseicon.2" ) { + #-- issue the copy scratchpad to LCD command \x48 + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "endicon", 16, $owx_dev,"\x48", 0, 1, 0, \&OWXLCD_BinValues, 0); + #=============== seticon 2nd step =============================== + }elsif( $context eq "seticon.1" ) { + #-- SEGRAM addres to 0 = \x40 + icon address + $select = substr($crcpart,0,2); + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "seticon.2", 16, $owx_dev, $select,$crcpart, 0, 0, \&OWXLCD_BinValues, 0); + #=============== seticon 2nd step =============================== + }elsif( $context eq "seticon.2" ) { + #-- data + $select = substr($crcpart,2); + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "endicon", 16, $owx_dev, $select, 0, 1, 0, \&OWXLCD_BinValues, 0); + #=============== endicon =============================== + }elsif( $context eq "endicon" ) { + #-- issue the return to normal state command + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 ensures entry at top of queue + OWX_Qomplex($master, $hash, "", 16, $owx_dev, "\x10\x20", 0, 0, 0, undef, 0); + #=============== prepare some get values =============================== + }elsif ( $context =~ /^get\.prep\.(\d+)/ ) { + my $len = $1; + #Log 1,"OWXLCD_BinValues: context get.$crcpart with length $len"; + #-- command hidden in crcpart, issueing read scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "get.".$crcpart, 0, $owx_dev, "\xBE", 0, $len, 10, \&OWXLCD_BinValues, 0); + #=============== gpio ports =============================== + }elsif ( $context eq "get.gpio" ) { + $ret = ord($res); + readingsSingleUpdate($hash,"gpio",$ret,1); + #=============== gpio counters =============================== + }elsif ( $context eq "get.counter" ) { + for( my $i=0; $i<4; $i++){ + $data[$i] = ord(substr($res,2*$i+1,1))*256+ord(substr($res,2*$i,1)); + } + $ret = join(" ",@data); + readingsSingleUpdate($hash,"counter",$ret,1); + #=============== version =============================== + }elsif ( $context eq "get.version" ) { + #TODO format version, raw value is unreadable + readingsSingleUpdate($hash,"version",$res,1); + #=============== memory =============================== + }elsif ( $context =~ /^get\.memory\.([\d]+)$/ ) { + readingsSingleUpdate($hash,"memory$1",unpack("H*",$res),1); + } + return undef; +} + ######################################################################################## # # OWXLCD_SetFunction - write state and values of the LCD device @@ -1199,15 +1220,482 @@ sub OWXLCD_SetFunction($$$) { return "OWXLCD: Wrong function selected"; } - #-- write to device - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - #-- process results - if( $res eq 0 ){ - return "OWLCD: Device $owx_dev not accessible for writing"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + #-- write to device + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + #-- process results + if( $res eq 0 ){ + return "OWLCD: Device $owx_dev not accessible for writing"; + } + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "setfunction", 0, $owx_dev, $select, 0, 0, 0, undef, 0); + } + return undef; +} + +######################################################################################## +# +# OWXLCD_SetIcon - set one of the icons +# +# Parameter hash = hash of device addressed +# icon = address of the icon used = 0,1 .. 16 (0 = all off) +# value = data value: 0 = off, 1 = on, 2 = blink +# for battery icon 16: 0 = off, 1 = empty ... 5 = full, 6 = empty blink +# +######################################################################################## + +sub OWXLCD_SetIcon($$$) { + my ($hash,$icon,$value) = @_; + + my ($i,$data,$select, $res); + + #-- ID of the device, hash of the busmaster + my $owx_dev = $hash->{ROM_ID}; + my $master = $hash->{IODev}; + + #-- only for KS0073 + if ( $lcdcontroller eq "KS0073"){ + + #-- write 16 zeros to erase all icons + if( $icon == 0){ + #-- 4 bit data size, RE => 1, blink Enable = \x26 + $select = "\x10\x26"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- SEGRAM addres to 0 = \x40, + $select = "\x10\x40"; + #-- write 16 zeros to scratchpad + $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- issue the copy scratchpad to LCD command \x48 + $select="\x48"; + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- return to normal state + $select = "\x10\x20"; + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "eraseicon.1", 0, $owx_dev, $select, 0, 0, 0, \&OWXLCD_BinValues, 0); + } + } else { + #-- determine data value + if( int($icon) != 16 ){ + if( $value == 0 ){ + $data = 0; + } elsif ( $value == 1) { + $data = 16; + } elsif ( $value == 2) { + $data = 80; + } else { + return "OWXLCD: Wrong data value $value for icon $icon"; + } + } else { + if( $value == 0 ){ + $data = 0; + } elsif ( $value == 1) { + $data = 16; + } elsif ( $value == 2) { + $data = 24; + } elsif ( $value == 3) { + $data = 28; + } elsif ( $value == 4) { + $data = 30; + } elsif ( $value == 5) { + $data = 31; + } elsif ( $value == 6) { + $data = 80; + } else { + return "OWXLCD: Wrong data value $value for icon $icon"; + } + } + #-- 4 bit data size, RE => 1, blink Enable = \x26 + $select = "\x10\x26"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- SEGRAM addres to 0 = \x40 + icon address + $select = sprintf("\x10%c",63+$icon); + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- data + $select = sprintf("\x12%c",$data); + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- return to normal state + $select = "\x10\x20"; + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "seticon.1", 0, $owx_dev, $select, sprintf("\x10%c",63+$icon).sprintf("\x12%c",$data), 0, 0, \&OWXLCD_BinValues, 0); + } + } + + #-- or else + } else { + return "OWXLCD: Wrong LCD controller type"; + } +} + +######################################################################################## +# +# OWXLCD_SetLine - set one of the display lines +# +# Parameter hash = hash of device addressed +# line = line number (0..3) +# msg = data string to be written +# +######################################################################################## + +sub OWXLCD_SetLine($$$) { + + my ($hash,$line,$msg) = @_; + + my ($select, $res, $res2, $res3, $i, $msgA, $msgB); + $res2 = ""; + $line = int($line); + $msg = defined($msg) ? $msg : ""; + + $msg = OWXLCD_Trans($msg); + + #-- ID of the device, hash of the busmaster + my $owx_dev = $hash->{ROM_ID}; + my $master = $hash->{IODev}; + + #-- split if longer than 16 bytes, fill each with blanks + # has already been checked to be <= $lcdchars + if( $lcdchars > 16 ){ + if( length($msg) > 16 ) { + $msgA = substr($msg,0,16); + $msgB = substr($msg,16,length($msg)-16); + for($i = 0;$i<$lcdchars-length($msg);$i++){ + $msgB .= "\x20"; + } + } else { + $msgA = $msg; + for($i = 0;$i<16-length($msg);$i++){ + $msgA .= "\x20"; + } + for($i = 0;$i<$lcdchars-16;$i++){ + $msgB .= "\x20"; + } + } + }else{ + $msgA = $msg; + for($i = 0;$i<$lcdchars-length($msg);$i++){ + $msgA .= "\x20"; + } + $msgB = undef; + } + + #-- issue the match ROM command \x55 and the write scratchpad command \x4E + # followed by LCD page address and the text + $select=sprintf("\x4E%c",$lcdpage[$line]).$msgA; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + + #-- issue the copy scratchpad to LCD command \x48 + $select="\x48"; + OWX_Reset($master); + $res3=OWX_Complex($master,$owx_dev,$select,0); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "setline", 0, $owx_dev, $select, 0, 0, 0, \&OWXLCD_BinValues, 0); + } + #-- if second string available: + if( defined($msgB) ) { + #select(undef,undef,undef,0.005); + #-- issue the match ROM command \x55 and the write scratchpad command \x4E + # followed by LCD page address and the text + $select=sprintf("\x4E%c",$lcdpage[$line]+16).$msgB; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res2=OWX_Complex($master,$owx_dev,$select,0); + + #-- issue the copy scratchpad to LCD command \x48 + $select="\x48"; + OWX_Reset($master); + $res3=OWX_Complex($master,$owx_dev,$select,0); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "setline", 0, $owx_dev, $select, 0, 0, 0, \&OWXLCD_BinValues, 0); + } } + #-- process results + if( !$master->{ASYNCHRONOUS} ){ + if( ($res eq 0) || ($res2 eq 0) || ($res3 eq 0) ){ + return "OWLCD: Device $owx_dev not accessible for writing"; + } + } return undef; + +} + +######################################################################################## +# +# OWXLCD_Trans - String translation helper +# +# Parameter msg = data string to be written +# +######################################################################################## + +sub OWXLCD_Trans($) { + + my ($msg) = @_; + + #-- replace umlaut chars for special codepage + $msg =~ s/ä/\x7B/g; + $msg =~ s/ö/\x7C/g; + $msg =~ s/ü/\x7E/g; + $msg =~ s/Ä/\x5B/g; + $msg =~ s/Ö/\x5C/g; + $msg =~ s/Ü/\x5E/g; + $msg =~ s/ß/\xBE/g; + #-- replace other special chars + $msg =~s/_/\xC4/g; + #--take out HTML degree sign + if( $msg =~ m/.*\°\;.*/ ) { + my @ma = split(/\°\;/,$msg); + $msg = $ma[0]."\x80".$ma[1]; + } + return $msg; +} + +######################################################################################## +# +# OWXLCD_SetMemory - set internal nonvolatile memory +# +# Parameter hash = hash of device addressed +# page = page number (0..14) +# msg = data string to be written +# +######################################################################################## + +sub OWXLCD_SetMemory($$$) { + + my ($hash,$page,$msg) = @_; + + my ($select, $res, $res2, $res3, $i, $msgA); + $page = int($page); + $msg = defined($msg) ? $msg : ""; + + #-- ID of the device, hash of the busmaster + my $owx_dev = $hash->{ROM_ID}; + my $master = $hash->{IODev}; + + #-- fillup with blanks + $msgA = $msg; + for($i = 0;$i<16-length($msg);$i++){ + $msgA .= "\x20"; + } + + #-- issue the match ROM command \x55 and the write scratchpad command \x4E + # followed by LCD page address and the text + #Log 1," page written is ".$page; + $select=sprintf("\x4E\%c",$page).$msgA; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,0); + #-- issue the copy scratchpad to EEPROM command \x39 + $select = "\x39"; + OWX_Reset($master); + $res2=OWX_Complex($master,$owx_dev,$select,0); + + #-- process results + if( ($res eq 0) || ($res2 eq 0) ){ + return "OWLCD: Device $owx_dev not accessible for writing"; + } + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "seteeprom", 0, $owx_dev, $select, 0, 0, 0, \&OWXLCD_BinValues, 0); + } + return undef; +} + +######################################################################################## +# +# OWXLCD_PT_Byte - write a single byte to the LCD device async +# +# Parameter hash = hash of device addressed +# cmd = register or data +# byte = byte +# +######################################################################################## + +sub OWXLCD_PT_Byte($$$) { + + my ($hash,$cmd,$byte) = @_; + + return PT_THREAD(sub { + my ($thread) = @_; + my ($select); + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + #-- hash of the busmaster + my $master = $hash->{IODev}; + my ($i,$j,$k); + + PT_BEGIN($thread); + + #=============== write to LCD register =============================== + if ( $cmd eq "register" ) { + #-- issue the read LCD register command \x10 + $select = sprintf("\x10%c",$byte); + #=============== write to LCD data =============================== + }elsif ( $cmd eq "data" ) { + #-- issue the read LCD data command \x12 + $select = sprintf("\x12%c",$byte); + #=============== wrong value requested =============================== + } else { + die "OWXLCD: Wrong byte write attempt"; + } + + #"byte" + $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); + PT_WAIT_THREAD($thread->{pt_execute}); + die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); + PT_END; + }); +} + +######################################################################################## +# +# OWXLCD_PT_Get - get values from the LCD device async +# +# Parameter hash = hash of device addressed +# cmd = command string +# +######################################################################################## + +sub OWXLCD_PT_Get($$) { + + my ($hash,$cmd) = @_; + + return PT_THREAD(sub { + + my ($thread) = @_; + my ($select); + + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + + #-- hash of the busmaster + my $master = $hash->{IODev}; + + my ($i,$j,$k); + + PT_BEGIN($thread); + #=============== fill scratch with gpio ports =============================== + if ( $cmd eq "gpio" ) { + #-- issue the read GPIO command \x22 (1 byte) + $select = "\x22"; + $thread->{len} = 1; + #=============== fill scratch with gpio counters =============================== + }elsif ( $cmd eq "counter" ) { + #-- issue the read counter command \x23 (8 bytes) + $select = "\x23"; + $thread->{len} = 8; + #=============== fill scratch with version =============================== + }elsif ( $cmd eq "version" ) { + #-- issue the read version command \x41 + $select = "\x41"; + $thread->{len} = 16; + } else { + die("OWXLCD: Wrong get attempt"); + } + #"get.prepare" + $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); + PT_WAIT_THREAD($thread->{pt_execute}); + die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); + + #-- issue the read scratchpad command \xBE + $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE", $thread->{len}); + PT_WAIT_THREAD($thread->{pt_execute}); + die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); + + OWXLCD_BinValues($hash, "get.".$cmd, 1, $owx_dev, "\xBE", $thread->{len}, $thread->{pt_execute}->PT_RETVAL()); + + PT_END; + }); +} + +######################################################################################## +# +# OWXLCD_PT_GetMemory - get memory page from LCD device async (EXPERIMENTAL) +# +# Parameter hash = hash of device addressed +# page = memory page address +# +######################################################################################## + +sub OWXLCD_PT_GetMemory($$) { + + my ($hash,$page) = @_; + + return PT_THREAD(sub { + + my ($thread) = @_; + my ($select); + + #-- ID of the device + my $owx_dev = $hash->{ROM_ID}; + + #-- hash of the busmaster + my $master = $hash->{IODev}; + + PT_BEGIN($thread); + #-- issue the match ROM command \x55 and the copy eeprom to scratchpad command \x4E + #Log 1," page read is ".$page; + $select = sprintf("\4E%c\x10\x37",$page); + #"prepare" + $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,0); + PT_WAIT_THREAD($thread->{pt_execute}); + die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); + + #-- sleeping for some time + $thread->{ExecuteTime} = gettimeofday()+0.5; + PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime}); + delete $thread->{ExecuteTime}; + + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + $thread->{'select'} = "\xBE"; + #"get.memory.$page" + $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},16); + PT_WAIT_THREAD($thread->{pt_execute}); + die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); + + OWXLCD_BinValues($hash, "get.memory.$page", 1, $owx_dev, $thread->{'select'}, 16, $thread->{pt_execute}->PT_RETVAL()); + #-- process results (10 bytes or more have been sent) + #$res2 = substr($res,11,16); + #return $res2; + PT_END; + }); } ######################################################################################## @@ -1275,104 +1763,6 @@ sub OWXLCD_PT_SetFunction($$$) { }); } -######################################################################################## -# -# OWXLCD_SetIcon - set one of the icons -# -# Parameter hash = hash of device addressed -# icon = address of the icon used = 0,1 .. 16 (0 = all off) -# value = data value: 0 = off, 1 = on, 2 = blink -# for battery icon 16: 0 = off, 1 = empty ... 5 = full, 6 = empty blink -# -######################################################################################## - -sub OWXLCD_SetIcon($$$) { - my ($hash,$icon,$value) = @_; - - my ($i,$data,$select, $res); - - #-- ID of the device, hash of the busmaster - my $owx_dev = $hash->{ROM_ID}; - my $master = $hash->{IODev}; - - #-- only for KS0073 - if ( $lcdcontroller eq "KS0073"){ - - #-- write 16 zeros to erase all icons - if( $icon == 0){ - #-- 4 bit data size, RE => 1, blink Enable = \x26 - $select = "\x10\x26"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- SEGRAM addres to 0 = \x40, - $select = "\x10\x40"; - #-- write 16 zeros to scratchpad - $select .= "\x4E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- issue the copy scratchpad to LCD command \x48 - $select="\x48"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - } else { - #-- determine data value - if( int($icon) != 16 ){ - if( $value == 0 ){ - $data = 0; - } elsif ( $value == 1) { - $data = 16; - } elsif ( $value == 2) { - $data = 80; - } else { - return "OWXLCD: Wrong data value $value for icon $icon"; - } - } else { - if( $value == 0 ){ - $data = 0; - } elsif ( $value == 1) { - $data = 16; - } elsif ( $value == 2) { - $data = 24; - } elsif ( $value == 3) { - $data = 28; - } elsif ( $value == 4) { - $data = 30; - } elsif ( $value == 5) { - $data = 31; - } elsif ( $value == 6) { - $data = 80; - } else { - return "OWXLCD: Wrong data value $value for icon $icon"; - } - } - #-- 4 bit data size, RE => 1, blink Enable = \x26 - $select = "\x10\x26"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- SEGRAM addres to 0 = \x40 + icon address - $select = sprintf("\x10%c",63+$icon); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- data - $select = sprintf("\x12%c",$data); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - } - - #-- return to normal state - $select = "\x10\x20"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - #-- or else - } else { - return "OWXLCD: Wrong LCD controller type"; - } -} - ######################################################################################## # # OWXLCD_PT_SetIcon - set one of the icons async @@ -1492,92 +1882,6 @@ sub OWXLCD_PT_SetIcon($$$) { }); } -######################################################################################## -# -# OWXLCD_SetLine - set one of the display lines -# -# Parameter hash = hash of device addressed -# line = line number (0..3) -# msg = data string to be written -# -######################################################################################## - -sub OWXLCD_SetLine($$$) { - - my ($hash,$line,$msg) = @_; - - my ($select, $res, $res2, $res3, $i, $msgA, $msgB); - $res2 = ""; - $line = int($line); - $msg = defined($msg) ? $msg : ""; - - $msg = OWXLCD_Trans($msg); - - #-- ID of the device, hash of the busmaster - my $owx_dev = $hash->{ROM_ID}; - my $master = $hash->{IODev}; - - #-- split if longer than 16 bytes, fill each with blanks - # has already been checked to be <= $lcdchars - if( $lcdchars > 16 ){ - if( length($msg) > 16 ) { - $msgA = substr($msg,0,16); - $msgB = substr($msg,16,length($msg)-16); - for($i = 0;$i<$lcdchars-length($msg);$i++){ - $msgB .= "\x20"; - } - } else { - $msgA = $msg; - for($i = 0;$i<16-length($msg);$i++){ - $msgA .= "\x20"; - } - for($i = 0;$i<$lcdchars-16;$i++){ - $msgB .= "\x20"; - } - } - }else{ - $msgA = $msg; - for($i = 0;$i<$lcdchars-length($msg);$i++){ - $msgA .= "\x20"; - } - $msgB = undef; - } - - #-- issue the match ROM command \x55 and the write scratchpad command \x4E - # followed by LCD page address and the text - $select=sprintf("\x4E%c",$lcdpage[$line]).$msgA; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- issue the copy scratchpad to LCD command \x48 - $select="\x48"; - OWX_Reset($master); - $res3=OWX_Complex($master,$owx_dev,$select,0); - - #-- if second string available: - if( defined($msgB) ) { - #select(undef,undef,undef,0.005); - #-- issue the match ROM command \x55 and the write scratchpad command \x4E - # followed by LCD page address and the text - $select=sprintf("\x4E%c",$lcdpage[$line]+16).$msgB; - OWX_Reset($master); - $res2=OWX_Complex($master,$owx_dev,$select,0); - - #-- issue the copy scratchpad to LCD command \x48 - $select="\x48"; - OWX_Reset($master); - $res3=OWX_Complex($master,$owx_dev,$select,0); - } - - #-- process results - if( ($res eq 0) || ($res2 eq 0) || ($res3 eq 0) ){ - return "OWLCD: Device $owx_dev not accessible for writing"; - } - - return undef; - -} - ######################################################################################## # # OWXLCD_PT_SetLine - set one of the display lines async @@ -1672,84 +1976,6 @@ sub OWXLCD_PT_SetLine($$$) { }); } -######################################################################################## -# -# OWXLCD_Trans - String translation helper -# -# Parameter msg = data string to be written -# -######################################################################################## - -sub OWXLCD_Trans($) { - - my ($msg) = @_; - - #-- replace umlaut chars for special codepage - $msg =~ s/ä/\x7B/g; - $msg =~ s/ö/\x7C/g; - $msg =~ s/ü/\x7E/g; - $msg =~ s/Ä/\x5B/g; - $msg =~ s/Ö/\x5C/g; - $msg =~ s/Ü/\x5E/g; - $msg =~ s/ß/\xBE/g; - #-- replace other special chars - $msg =~s/_/\xC4/g; - #--take out HTML degree sign - if( $msg =~ m/.*\°\;.*/ ) { - my @ma = split(/\°\;/,$msg); - $msg = $ma[0]."\x80".$ma[1]; - } - return $msg; -} - -######################################################################################## -# -# OWXLCD_SetMemory - set internal nonvolatile memory -# -# Parameter hash = hash of device addressed -# page = page number (0..14) -# msg = data string to be written -# -######################################################################################## - -sub OWXLCD_SetMemory($$$) { - - my ($hash,$page,$msg) = @_; - - my ($select, $res, $res2, $res3, $i, $msgA); - $page = int($page); - $msg = defined($msg) ? $msg : ""; - - #-- ID of the device, hash of the busmaster - my $owx_dev = $hash->{ROM_ID}; - my $master = $hash->{IODev}; - - #-- fillup with blanks - $msgA = $msg; - for($i = 0;$i<16-length($msg);$i++){ - $msgA .= "\x20"; - } - - #-- issue the match ROM command \x55 and the write scratchpad command \x4E - # followed by LCD page address and the text - #Log 1," page written is ".$page; - $select=sprintf("\x4E\%c",$page).$msgA; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,0); - - #-- issue the copy scratchpad to EEPROM command \x39 - $select = "\x39"; - OWX_Reset($master); - $res2=OWX_Complex($master,$owx_dev,$select,0); - - #-- process results - if( ($res eq 0) || ($res2 eq 0) ){ - return "OWLCD: Device $owx_dev not accessible for writing"; - } - - return undef; - -} ######################################################################################## # @@ -1804,34 +2030,6 @@ sub OWXLCD_PT_SetMemory($$$) { }); } -sub OWXLCD_BinValues($$$$$$$$) { - my ($hash, $cmd, $success, $reset, $owx_dev, $command, $numread, $res) = @_; - - my ($i,@data,$ret); - - #=============== gpio ports =============================== - if ( $cmd eq "get.gpio" ) { - $ret = ord($res); - readingsSingleUpdate($hash,"gpio",$ret,1); - return $ret; - #=============== gpio counters =============================== - }elsif ( $cmd eq "get.counter" ) { - for( $i=0; $i<4; $i++){ - $data[$i] = ord(substr($res,2*$i+1,1))*256+ord(substr($res,2*$i,1)); - } - $ret = join(" ",@data); - readingsSingleUpdate($hash,"counter",$ret,1); - #=============== version =============================== - }elsif ( $cmd eq "get.version" ) { - #TODO format version, raw value is unreadable - readingsSingleUpdate($hash,"version",$res,1); - return $res; - }elsif ( $cmd =~ /^get\.memory\.([\d]+)$/ ) { - readingsSingleUpdate($hash,"memory$1",unpack("H*",$res),1); - return $ret; - } -} - 1; =pod @@ -1912,7 +2110,7 @@ sub OWXLCD_BinValues($$$$$$$$) { get <name> gpio
    Obtain state of all four input channels (15 = all off, 0 = all on)
  • - get <name> gpio
    Obtain state of all four input + get <name> counter
    Obtain state of all four input counters (4 x 16 Bit)
  • get <name> version
    Obtain firmware version of the @@ -1922,9 +2120,10 @@ sub OWXLCD_BinValues($$$$$$$$) {

    Attributes

    =end html diff --git a/fhem/FHEM/21_OWMULTI.pm b/fhem/FHEM/21_OWMULTI.pm index b581373ae..ff4cb86f0 100644 --- a/fhem/FHEM/21_OWMULTI.pm +++ b/fhem/FHEM/21_OWMULTI.pm @@ -28,7 +28,7 @@ # get reading => measurement value obtained from VFunction # get temperature => temperature measurement # get VDD => supply voltage measurement -# get V|raw => raw external voltage measurement +# get V|I|raw => external voltage/external current/raw measurement # get version => OWX version number # # set interval => set period for measurement @@ -38,12 +38,17 @@ # # attr tempOffset = temperature offset in degree Celsius added to the raw temperature reading # attr tempUnit = unit of measurement, e.g. Celsius/Kelvin/Fahrenheit, default is Celsius -# attr VName [|] = name for the channel [|name used in state reading] -# attr VUnit [|] = unit of measurement for the channel [|unit used in state reading] -# attr Vfunction = arbitrary functional expression involving the values VDD, V, T +# attr VName [|] = name for the voltage channel [|short name used in state reading] +# attr VUnit = unit of measurement for the voltage channel (default V, none for empty) +# attr Vfunction = arbitrary functional expression involving the values VDD, V, W, T # VDD is replaced by the measured supply voltage in Volt, -# V by the measured external voltage (the channel) +# V by the measured external voltage channel +# W by the measured external sense channel # T by the measured and corrected temperature in its unit +# attr WName [|] = name for the sense channel [|short name used in state reading] +# attr WUnit [|] = unit of measurement for the sense channel (default 1/16384 V, none for empty) +# attr Wfunction = arbitrary functional expression involving the values VDD, V, W, T +# # ######################################################################################## # @@ -82,9 +87,9 @@ no warnings 'deprecated'; sub Log($$); -my $owx_version="5.23"; +my $owx_version="6.0"; #-- flexible channel name -my $owg_channel; +my ($owg_channel,$owg_schannel); my %gets = ( "id" => "", @@ -112,17 +117,14 @@ my %updates = ( # # Prefix = OWMULTI # -## -# Parameters: -# hash - hash of device addressed -# -# Called By: -# FHEM - Main Loop -# Gargelmargel - dunno where -# -#Calling: -# None -## +######################################################################################## +# +# OWMULTI_Initialize +# +# Parameter hash = hash of device addressed +# +######################################################################################## + sub OWMULTI_Initialize ($) { my ($hash) = @_; @@ -136,16 +138,17 @@ sub OWMULTI_Initialize ($) { #tempOffset = a temperature offset added to the temperature reading for correction #tempUnit = a unit of measure: C/F/K - $hash->{AttrList}= "IODev do_not_notify:0,1 showtime:0,1 model:DS2438 loglevel:0,1,2,3,4,5 ". + $hash->{AttrList}= "IODev do_not_notify:0,1 showtime:0,1 model:DS2438 verbose:0,1,2,3,4,5 ". "tempOffset tempUnit:Celsius,Fahrenheit,Kelvin ". - "VName VUnit VFunction ". + "VName VUnit VFunction WName WUnit WFunction ". "interval ". $readingFnAttributes; #-- temperature and voltage globals - always the raw values from the device $hash->{owg_val}->[0] = undef; - $hash->{owg_val}->[2] = undef; $hash->{owg_val}->[1] = undef; + $hash->{owg_val}->[2] = undef; + $hash->{owg_val}->[3] = undef; #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer main::LoadModule("OWX"); @@ -280,7 +283,7 @@ sub OWMULTI_Define ($$) { $main::modules{OWMULTI}{defptr}{$id} = $hash; #-- readingsSingleUpdate($hash,"state","defined",1); - Log 3, "OWMULTI: Device $name defined."; + Log 3, "OWMULTI: Device $name defined."; $hash->{NOTIFYDEV} = "global"; @@ -336,29 +339,48 @@ sub OWMULTI_ChannelNames($) { my $name = $hash->{NAME}; my $state = $hash->{READINGS}{"state"}{VAL}; - my ($cname,@cnama,$unit,@unarr); - my ($tunit,$toffset,$tfactor,$tabbr,$vfunc); + my ($cname,@cnama,$unit); + my ($tunit,$toffset,$tfactor,$tabbr,$vfunc,$wfunc); #-- Set channel name, channel unit for voltage channel - $cname = defined($attr{$name}{"VName"}) ? $attr{$name}{"VName"} : "voltage"; + $cname = defined($attr{$name}{"VName"}) ? $attr{$name}{"VName"} : "voltage|vad"; @cnama = split(/\|/,$cname); if( int(@cnama)!=2){ push(@cnama,$cnama[0]); } #-- unit - $unit = defined($attr{$name}{"VUnit"}) ? $attr{$name}{"VUnit"} : "Volt|V"; - @unarr= split(/\|/,$unit); - if( int(@unarr)!=2 ){ - push(@unarr,$unarr[0]); - } + $unit = defined($attr{$name}{"VUnit"}) ? $attr{$name}{"VUnit"} : "V"; + $unit = "" + if($unit eq "none"); #-- put into readings $owg_channel = $cnama[0]; $hash->{READINGS}{$owg_channel}{VAL} = " "; $hash->{READINGS}{$owg_channel}{ABBR} = $cnama[1]; - $hash->{READINGS}{$owg_channel}{UNIT} = $unarr[0]; - $hash->{READINGS}{$owg_channel}{UNITABBR} = $unarr[1]; + $hash->{READINGS}{$owg_channel}{UNIT} = " ".$unit; + + + #-- Set channel name, channel unit for sense channel + $cname = defined($attr{$name}{"WName"}) ? $attr{$name}{"WName"} : "sense|s"; + @cnama = split(/\|/,$cname); + if( int(@cnama)!=2){ + push(@cnama,$cnama[0]); + } + + #-- unit + $unit = defined($attr{$name}{"WUnit"}) ? $attr{$name}{"WUnit"} : "V"; + if($unit eq "none"){ + $unit = "" + }else{ + $unit = " ".$unit + } + + #-- put into readings + $owg_schannel = $cnama[0]; + $hash->{READINGS}{$owg_schannel}{VAL} = " "; + $hash->{READINGS}{$owg_schannel}{ABBR} = $cnama[1]; + $hash->{READINGS}{$owg_schannel}{UNIT} = $unit; #-- temperature scale $hash->{READINGS}{"temperature"}{UNIT} = defined($attr{$name}{"tempUnit"}) ? $attr{$name}{"tempUnit"} : "Celsius"; @@ -366,13 +388,15 @@ sub OWMULTI_ChannelNames($) { $toffset = defined($attr{$name}{"tempOffset"}) ? $attr{$name}{"tempOffset"} : 0.0 ; $tfactor = 1.0; - if( $tunit eq "Celsius" ){ - $tabbr = "°C"; + if( $tunit eq "none" ){ + $tabbr = ""; + }elsif( $tunit eq "Celsius" ){ + $tabbr = " °C"; } elsif ($tunit eq "Kelvin" ){ - $tabbr = "K"; + $tabbr = " K"; $toffset += "273.16" } elsif ($tunit eq "Fahrenheit" ){ - $tabbr = "°F"; + $tabbr = " °F"; $toffset = ($toffset+32)/1.8; $tfactor = 1.8; } else { @@ -382,8 +406,7 @@ sub OWMULTI_ChannelNames($) { #-- these values are rather complex to obtain, therefore save them in the hash $hash->{READINGS}{"temperature"}{ABBR} = "T"; - $hash->{READINGS}{"temperature"}{UNIT} = $tunit; - $hash->{READINGS}{"temperature"}{UNITABBR} = $tabbr; + $hash->{READINGS}{"temperature"}{UNIT} = $tabbr; $hash->{tempf}{offset} = $toffset; $hash->{tempf}{factor} = $tfactor; } @@ -400,11 +423,11 @@ sub OWMULTI_FormatValues($) { my ($hash) = @_; my $name = $hash->{NAME}; - my ($toffset,$tfactor,$tval,$vfunc,$vval); + my ($toffset,$tfactor,$tval,$vfunc,$wfunc,$vval,$wval); my $svalue = ""; #-- no change in any value if invalid reading - return if( ($hash->{owg_val}->[0] eq "") || ($hash->{owg_val}->[1] eq "") || ($hash->{owg_val}->[2] eq "") ); + return if( ($hash->{owg_val}->[0] eq "") || ($hash->{owg_val}->[1] eq "") || ($hash->{owg_val}->[2] eq "") || ($hash->{owg_val}->[3] eq "")); #-- obtain channel names OWMULTI_ChannelNames($hash); @@ -414,35 +437,53 @@ sub OWMULTI_FormatValues($) { $tfactor = $hash->{tempf}{factor}; $tval = int(10*($hash->{owg_val}->[0] + $toffset)*$tfactor+0.5)/10; - #-- attribute VFunction defined ? + #-- attribute V/WFunction defined ? $vfunc = defined($attr{$name}{"VFunction"}) ? $attr{$name}{"VFunction"} : "V"; + $wfunc = defined($attr{$name}{"WFunction"}) ? $attr{$name}{"WFunction"} : "W"; #-- replace by proper values $vfunc =~ s/VDD/\$hash->{owg_val}->[1]/g; $vfunc =~ s/V/\$hash->{owg_val}->[2]/g; + $vfunc =~ s/W/\$hash->{owg_val}->[3]/g; $vfunc =~ s/T/\$tval/g; + $wfunc =~ s/VDD/\$hash->{owg_val}->[1]/g; + $wfunc =~ s/V/\$hash->{owg_val}->[2]/g; + $wfunc =~ s/W/\$hash->{owg_val}->[3]/g; + $wfunc =~ s/T/\$tval/g; #-- determine the measured value from the function - $vfunc = "\$hash->{owg_val}->[1] = $hash->{owg_val}->[1]; \$hash->{owg_val}->[2] = $hash->{owg_val}->[2]; \$tval = $tval; ".$vfunc; + $vfunc = "\$hash->{owg_val}->[1] = $hash->{owg_val}->[1]; \$hash->{owg_val}->[2] = $hash->{owg_val}->[2]; \$hash->{owg_val}->[3] = $hash->{owg_val}->[3]; \$tval = $tval; ".$vfunc; #Log 1, "vfunc= ".$vfunc; $vfunc = eval($vfunc); if( !$vfunc ){ - $vval = ""; + $vval = 0.0; } elsif( $vfunc ne "" ){ - $vval = int( $vfunc*10+0.5)/10; + $vval = int( $vfunc*100+0.5)/100; } else { - #-- todo ? + $vval = "???"; + } + + $wfunc = "\$hash->{owg_val}->[1] = $hash->{owg_val}->[1]; \$hash->{owg_val}->[2] = $hash->{owg_val}->[2]; \$hash->{owg_val}->[3] = $hash->{owg_val}->[3]; \$tval = $tval; ".$wfunc; + #Log 1, "wfunc= ".$wfunc; + $wfunc = eval($wfunc); + if( !$wfunc ){ + $wval = 0.0; + } elsif( $wfunc ne "" ){ + $wval = int( $wfunc*100+0.5)/100; + } else { + $wval = "???"; } #-- string buildup for return value, STATE - $svalue .= sprintf( "%s: %5.1f %s (T: %5.1f %s)", - $hash->{READINGS}{$owg_channel}{ABBR}, $vval,$hash->{READINGS}{$owg_channel}{UNITABBR}, - $tval,$hash->{READINGS}{"temperature"}{UNITABBR}); + $svalue .= sprintf( "%s: %5.2f%s (T: %5.1f%s %s: %5.2f%s)", + $hash->{READINGS}{$owg_channel}{ABBR}, $vval,$hash->{READINGS}{$owg_channel}{UNIT}, + $tval,$hash->{READINGS}{"temperature"}{UNIT}, $hash->{READINGS}{$owg_schannel}{ABBR}, $wval,$hash->{READINGS}{$owg_schannel}{UNIT}); #-- put into READINGS readingsBeginUpdate($hash); readingsBulkUpdate($hash,$owg_channel,$vval); - readingsBulkUpdate($hash,"VDD",sprintf("%4.2f %s",$hash->{owg_val}->[1],"V")); + readingsBulkUpdate($hash,$owg_schannel,$wval); + readingsBulkUpdate($hash,"VDD",sprintf("%4.2f",$hash->{owg_val}->[1])); readingsBulkUpdate($hash,"temperature",$tval); #-- STATE @@ -466,6 +507,7 @@ sub OWMULTI_Get($@) { my $reading = $a[1]; my $name = $hash->{NAME}; my $model = $hash->{OW_MODEL}; + my $value = undef; my $ret = ""; @@ -538,27 +580,31 @@ sub OWMULTI_Get($@) { return "OWMULTI: Get with wrong IODev type $interface"; } - #-- process results - if( defined($ret) ){ - return "OWMULTI: Could not get values from device $name, reason $ret"; - } - - #-- return the special reading - if ($reading eq "reading") { - return "OWMULTI: $name.reading => ".$hash->{READINGS}{"state"}{VAL}; - } + #-- process result + if( $master->{ASYNCHRONOUS} ){ + return "OWSMULTI: $name getting readings, please wait for completion"; + }else{ + if( defined($ret) ){ + return "OWMULTI: Could not get values from device $name, reason $ret"; + } + + #-- return the special reading + if ($reading eq "reading") { + return "OWMULTI: $name.reading => ".$hash->{READINGS}{"state"}{VAL}; + } - if ($reading eq "temperature") { - return "OWMULTI: $name.temperature => ". - $hash->{READINGS}{"temperature"}{VAL}; - } - if ($reading eq "VDD") { - return "OWMULTI: $name.VDD => ". - $hash->{owg_val}->[1]; - } - if ( $reading eq "raw") { - return "OWMULTI: $name.raw => ". - $hash->{owg_val}->[2]; + if ($reading eq "temperature") { + return "OWMULTI: $name.temperature => ". + $hash->{READINGS}{"temperature"}{VAL}; + } + if ($reading eq "VDD") { + return "OWMULTI: $name.VDD => ". + $hash->{owg_val}->[1]; + } + if ( $reading eq "raw") { + return "OWMULTI: $name.raw => ". + $hash->{owg_val}->[2]." V ".$hash->{owg_val}->[3]." V"; + } } return undef; } @@ -630,8 +676,9 @@ sub OWMULTI_InitializeDevice($) { #-- Initial readings $hash->{owg_val}->[0] = ""; - $hash->{owg_val}->[2] = ""; - $hash->{owg_val}->[1] = ""; + $hash->{owg_val}->[1] = ""; + $hash->{owg_val}->[2] = ""; + $hash->{owg_val}->[3] = ""; #-- Set state to initialized readingsSingleUpdate($hash,"state","initialized",1); @@ -766,16 +813,16 @@ sub OWFSMULTI_GetValues($) { $hash->{owg_val}->[0] = OWServer_Read($master,"/$owx_add/temperature"); $hash->{owg_val}->[1] = OWServer_Read($master,"/$owx_add/VDD"); $hash->{owg_val}->[2] = OWServer_Read($master,"/$owx_add/VAD"); + $hash->{owg_val}->[3] = OWServer_Read($master,"/$owx_add/vis"); return "no return from OWServer" - if( (!defined($hash->{owg_val}->[0])) || (!defined($hash->{owg_val}->[1])) || (!defined($hash->{owg_val}->[2])) ); + if( (!defined($hash->{owg_val}->[0])) || (!defined($hash->{owg_val}->[1])) || (!defined($hash->{owg_val}->[2])) || (!defined($hash->{owg_val}->[3])) ); return "empty return from OWServer" - if( ($hash->{owg_val}->[0] eq "") || ($hash->{owg_val}->[1] eq "") || ($hash->{owg_val}->[2] eq "") ); + if( ($hash->{owg_val}->[0] eq "") || ($hash->{owg_val}->[1] eq "") || ($hash->{owg_val}->[2] eq "") || ($hash->{owg_val}->[3] eq "") ); #-- and now from raw to formatted values $hash->{PRESENT} = 1; my $value = OWMULTI_FormatValues($hash); - Log 5, $value; return undef; } @@ -802,40 +849,65 @@ sub OWFSMULTI_SetValues($@) { # ######################################################################################## # -# OWXMULTI_BinValues - Binary readings into clear values +# OWXMULTI_BinValues - Process reading from one device - translate binary into raw # # Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string +# # ######################################################################################## -sub OWXMULTI_BinValues($$$$$$$$) { - my ($hash, $context, $success, $reset, $owx_dev, $command, $numread, $res) = @_; +sub OWXMULTI_BinValues($$$$$$$) { + my ($hash, $context, $proc, $owx_dev, $crcpart, $numread, $res) = @_; + + #-- hash of the busmaster + my $master = $hash->{IODev}; + my $name = $hash->{NAME}; + my @data=[]; + my ($value,$lsb,$msb,$sign); + my $msg; + OWX_WDBG($name,"OWXMULTI_BinValues called for device $name in context $context with ",$res) + if( $main::owx_debug>2 ); #-- always check for success, unused are reset, numread - return unless ($success and $context =~ /^ds2438.getv[ad]d$/); + return unless ($context =~ /^ds2438.getv[ad]d$/); #Log 1,"OWXMULTI_BinValues context = $context"; #-- process results - my @data=split(//,$res); + @data=split(//,$res); if (@data != 9) { - return "invalid data length, ".int(@data)." instead of 9 bytes"; - } - if ((ord($data[0]) & 112)!=0) { - return "conversion not complete or data invalid"; - } - if (OWX_CRC8(substr($res,0,8),$data[8])==0) { - return "invalid CRC"; + $msg="$name returns invalid data length, ".int(@data)." instead of 9 bytes"; + }elsif ((ord($data[0]) & 112)!=0) { + $msg="$name: conversion not complete or data invalid"; + }elsif (OWX_CRC8(substr($res,0,8),$data[8])==0) { + $msg="$name returns invalid CRC"; + }else{ + $msg="No error"; } + OWX_WDBG($name,"OWXMULTI_BinValues: ".$msg,"") + if( $main::owx_debug>2 ); #-- this must be different for the different device types # family = 26 => DS2438 #-- transform binary rep of VDD - if( $context eq "ds2438.getvdd") { + if( $context eq "ds2438.getvdd") { #-- temperature - my $lsb = ord($data[1]); - my $msb = ord($data[2]) & 127; - my $sign = ord($data[2]) & 128; + $lsb = ord($data[1]); + $msb = ord($data[2]) & 127; + $sign = ord($data[2]) & 128; #-- test with -55 degrees #$lsb = 0; @@ -843,7 +915,7 @@ sub OWXMULTI_BinValues($$$$$$$$) { #$msb = 73; #-- 2's complement form = signed bytes - $hash->{owg_val}->[0] = $msb+ $lsb/256; + $hash->{owg_val}->[0] = $msb+ $lsb/256.; if( $sign !=0 ){ $hash->{owg_val}->[0] = -128+$hash->{owg_val}->[0]; } @@ -857,25 +929,31 @@ sub OWXMULTI_BinValues($$$$$$$$) { #$msb = 1; #-- supply voltage - $hash->{owg_val}->[1] = ($msb*256+ $lsb)/100; - }; + $hash->{owg_val}->[1] = ($msb*256+ $lsb)/100.; + #-- transform binary rep of VAD - if( $context eq "ds2438.getvad") { + }elsif( $context eq "ds2438.getvad") { #-- voltage - my $lsb = ord($data[3]); - my $msb = ord($data[4]) & 3; + $lsb = ord($data[3]); + $msb = ord($data[4]) & 3; #-- test with 7.2 V #$lsb = 208; #$msb = 2; #-- external voltage - $hash->{owg_val}->[2] = ($msb*256+ $lsb)/100; - - #-- and now from raw to formatted values + $hash->{owg_val}->[2] = ($msb*256+ $lsb)/100.; + + #-- current + $lsb = ord($data[5]); + $msb = ord($data[6]) & 3; + + #-- external current + $hash->{owg_val}->[3] = ($msb*256.+ $lsb)/4096; + + #-- and now from raw to formatted values $hash->{PRESENT} = 1; my $value = OWMULTI_FormatValues($hash); - Log 5, $value; }; return undef; } @@ -893,7 +971,7 @@ sub OWXMULTI_GetValues($) { my ($hash) = @_; - my ($i,$j,$k,$res,$ret); + my ($res,$ret); #-- ID of the device my $owx_dev = $hash->{ROM_ID}; @@ -905,101 +983,181 @@ sub OWXMULTI_GetValues($) { #------------------------------------------------------------------------------------ #-- switch the device to current measurement off, VDD only #-- issue the match ROM command \x55 and the write scratchpad command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x4E\x00\x08",0) eq 0 ){ - return "$owx_dev write status failed"; - } + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + #if( OWX_Complex($master,$owx_dev,"\x4E\x00\x08",0) eq 0 ){ + if( OWX_Complex($master,$owx_dev,"\x4E\x00\x09",0) eq 0 ){ + return "$owx_dev write status failed"; + } - #-- copy scratchpad to register - #-- issue the match ROM command \x55 and the copy scratchpad command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x48\x00",0) eq 0){ - return "$owx_dev copy scratchpad failed"; - } + #-- copy scratchpad to register + #-- issue the match ROM command \x55 and the copy scratchpad command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\x48\x00",0) eq 0){ + return "$owx_dev copy scratchpad failed"; + } - #-- initiate temperature conversion - #-- conversion needs some 12 ms ! - #-- issue the match ROM command \x55 and the start conversion command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x44",0) eq 0 ){ - return "$owx_dev temperature conversion failed"; - } - select(undef,undef,undef,0.012); + #-- initiate temperature conversion + #-- conversion needs some 12 ms ! + #-- issue the match ROM command \x55 and the start conversion command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\x44",0) eq 0 ){ + return "$owx_dev temperature conversion failed"; + } + select(undef,undef,undef,0.012); - #-- initiate voltage conversion - #-- conversion needs some 6 ms ! - #-- issue the match ROM command \x55 and the start conversion command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\xB4",0) eq 0 ){ - return "$owx_dev voltage conversion failed"; - } - select(undef,undef,undef,0.006); + #-- initiate voltage conversion + #-- conversion needs some 6 ms ! + #-- issue the match ROM command \x55 and the start conversion command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\xB4",0.01) eq 0 ){ + return "$owx_dev voltage conversion failed"; + } + select(undef,undef,undef,0.006); - #-- from memory to scratchpad - #-- copy needs some 12 ms ! - #-- issue the match ROM command \x55 and the recall memory command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\xB8\x00",0) eq 0 ){ - return "$owx_dev recall memory failed"; - } - select(undef,undef,undef,0.012); - #-- NOW ask the specific device - #-- issue the match ROM command \x55 and the read scratchpad command \xBE - #-- reading 9 + 2 + 9 data bytes = 20 bytes - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,"\xBE\x00",9); - #Log 1,"OWXMULTI: data length from reading device is ".length($res)." bytes"; - return "$owx_dev not accessible in 2nd step" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=20); - $ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",1,undef,$owx_dev,undef,undef,substr($res,11)); - return $ret if (defined $ret); - #------------------------------------------------------------------------------------ - #-- switch the device to current measurement off, V external only - #-- issue the match ROM command \x55 and the write scratchpad command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x4E\x00\x00",0) eq 0 ){ - return "$owx_dev write status failed"; - } - #-- copy scratchpad to register - #-- issue the match ROM command \x55 and the copy scratchpad command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x48\x00",0) eq 0){ - return "$owx_dev copy scratchpad failed"; - } - #-- initiate voltage conversion - #-- conversion needs some 6 ms ! - #-- issue the match ROM command \x55 and the start conversion command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\xB4",0) eq 0 ){ - return "$owx_dev voltage conversion failed"; - } - select(undef,undef,undef,0.006); + #-- from memory to scratchpad + #-- copy needs some 12 ms ! + #-- issue the match ROM command \x55 and the recall memory command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\xB8\x00",0.02) eq 0 ){ + return "$owx_dev recall memory failed"; + } + select(undef,undef,undef,0.012); + #-- NOW ask the specific device + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + #-- reading 9 + 2 + 9 data bytes = 20 bytes + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,"\xBE\x00",9); + #Log 1,"OWXMULTI: data length from reading device is ".length($res)." bytes"; + return "$owx_dev not accessible in 2nd step" + if( $res eq 0 ); + return "$owx_dev has returned invalid data" + if( length($res)!=20); + $ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",undef,$owx_dev,undef,undef,substr($res,11)); + return $ret if (defined $ret); + #------------------------------------------------------------------------------------ + #-- switch the device to current measurement off, V external only + #-- issue the match ROM command \x55 and the write scratchpad command + OWX_Reset($master); + #if( OWX_Complex($master,$owx_dev,"\x4E\x00\x00",0) eq 0 ){ + if( OWX_Complex($master,$owx_dev,"\x4E\x00\x01",0) eq 0 ){ + return "$owx_dev write status failed"; + } + #-- copy scratchpad to register + #-- issue the match ROM command \x55 and the copy scratchpad command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\x48\x00",0) eq 0){ + return "$owx_dev copy scratchpad failed"; + } + #-- initiate voltage conversion + #-- conversion needs some 6 ms ! + #-- issue the match ROM command \x55 and the start conversion command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\xB4",0.01) eq 0 ){ + return "$owx_dev voltage conversion failed"; + } + select(undef,undef,undef,0.006); - #-- from memory to scratchpad - #-- copy needs some 12 ms ! - #-- issue the match ROM command \x55 and the recall memory command - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\xB8\x00",0) eq 0 ){ - return "$owx_dev recall memory failed"; - } - select(undef,undef,undef,0.012); + #-- from memory to scratchpad + #-- copy needs some 12 ms ! + #-- issue the match ROM command \x55 and the recall memory command + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\xB8\x00",0.02) eq 0 ){ + return "$owx_dev recall memory failed"; + } + select(undef,undef,undef,0.012); - #-- NOW ask the specific device - #-- issue the match ROM command \x55 and the read scratchpad command \xBE - #-- reading 9 + 2 + 9 data bytes = 20 bytes - my $context = "ds2438.getvad"; - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,"\xBE\x00",9); - #-- process results - return "$owx_dev not accessible in 2nd step" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=20); - return OWXMULTI_BinValues($hash,$context,1,undef,$owx_dev,undef,undef,substr($res,11)); + #-- NOW ask the specific device + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + #-- reading 9 + 2 + 9 data bytes = 20 bytes + my $context = "ds2438.getvad"; + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,"\xBE\x00",9); + #-- process results + return "$owx_dev not accessible in 2nd step" + if( $res eq 0 ); + return "$owx_dev has returned invalid data" + if( length($res)!=20); + return OWXMULTI_BinValues($hash,$context,undef,$owx_dev,undef,undef,substr($res,11)); +#-- NEW OWX interface + }else{ + #-- switch the device to current measurement off, VDD only + #-- issue the match ROM command \x55 and the write scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + #OWX_Qomplex($master, $hash, "write SP", 0, $owx_dev, "\x4E\x00\x08", 0, 0, 0, undef, 0); + #-- switch the device to current measurement on, VDD only + #-- issue the match ROM command \x55 and the write scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "write SP", 0, $owx_dev, "\x4E\x00\x09", 0, 0, 0, undef, 0); + + #-- copy scratchpad to register + #-- issue the match ROM command \x55 and the copy scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "copy SP", 0, $owx_dev, "\x48\x00", 0, 0, 0, undef, 0); + + #-- initiate temperature conversion + #-- conversion needs some 12 ms ! + #-- issue the match ROM command \x55 and the start conversion command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "T conversion", 0, $owx_dev, "\x44", 0, 0, 0, undef, 0); + + #-- initiate voltage conversion + #-- conversion needs some 6 ms ! + #-- issue the match ROM command \x55 and the start conversion command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "V conversion", 0, $owx_dev, "\xB4", 0, 0, 0, undef, 0); + + #-- from memory to scratchpad + #-- copy needs some 12 ms ! + #-- issue the match ROM command \x55 and the recall memory command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "recall", 0, $owx_dev, "\xB8\x00", 0, 0, 0, undef, 0); + + #-- NOW ask the specific device + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + #-- reading 9 + 2 + 9 data bytes = 20 bytes + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 1 provides additional reset after last operattion + OWX_Qomplex($master, $hash, "ds2438.getvdd", 1, $owx_dev, "\xBE\x00\x08", 0, 9, 11, \&OWXMULTI_BinValues, 0); + + #-- switch the device to current measurement off, V external only + #-- issue the match ROM command \x55 and the write scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + #OWX_Qomplex($master, $hash, "write SP", 0, $owx_dev, "\x4E\x00\x00", 0, 0, 0, undef, 0); + #-- switch the device to current measurement on, V external only + #-- issue the match ROM command \x55 and the write scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "write SP", 0, $owx_dev, "\x4E\x00\x01", 0, 0, 0, undef, 0); + + + #-- copy scratchpad to register + #-- issue the match ROM command \x55 and the copy scratchpad command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "copy SP", 0, $owx_dev, "\x48\x00", 0, 0, 0, undef, 0); + + #-- initiate voltage conversion + #-- conversion needs some 6 ms ! + #-- issue the match ROM command \x55 and the start conversion command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "V conversion", 0, $owx_dev, "\xB4", 0, 0, 0, undef, 0); + + #-- from memory to scratchpad + #-- copy needs some 12 ms ! + #-- issue the match ROM command \x55 and the recall memory command + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "recall", 0, $owx_dev, "\xB8\x00", 0, 0, 0, undef, 0); + + #-- NOW ask the specific device + #-- issue the match ROM command \x55 and the read scratchpad command \xBE + #-- reading 9 + 2 + 9 data bytes = 20 bytes + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 1 provides additional reset after last operattion + OWX_Qomplex($master, $hash, "ds2438.getvad", 1, $owx_dev, "\xBE\x00", 0, 20, 11, \&OWXMULTI_BinValues, 0); + + return undef; + } } - ####################################################################################### # # OWXMULTI_SetValues - Set values in device @@ -1126,7 +1284,7 @@ sub OWXMULTI_PT_GetValues($) { unless (defined $res and length($res)==9) { PT_EXIT("$owx_dev has returned invalid data"); } - $ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",1,undef,$owx_dev,undef,undef,$res); + $ret = OWXMULTI_BinValues($hash,"ds2438.getvdd",undef,$owx_dev,undef,undef,$res); if ($ret) { die $ret; } @@ -1180,7 +1338,7 @@ sub OWXMULTI_PT_GetValues($) { unless (defined $res and length($res)==9) { PT_EXIT("$owx_dev has returned invalid data"); } - $ret = OWXMULTI_BinValues($hash,"ds2438.getvad",1,undef,$owx_dev,undef,undef,$res); + $ret = OWXMULTI_BinValues($hash,"ds2438.getvad",undef,$owx_dev,undef,undef,$res); if ($ret) { die $ret; } @@ -1250,9 +1408,9 @@ sub OWXMULTI_PT_SetValues($@) {

    define OWX_M OWMULTI 7C5034010000 45
    - attr OWX_M VName relHumidity|humidity + attr OWX_M VName humidity|rH
    - attr OWX_M VUnit percent|% + attr OWX_M VUnit %
    attr OWX_M VFunction (161.29 * V / VDD - 25.8065)/(1.0546 - 0.00216 * T)

    @@ -1305,34 +1463,43 @@ sub OWXMULTI_PT_SetValues($@) { seconds.
  • get <name> reading
    Obtain the measurement values
  • -
  • - get <name> VAD
    Obtain the measurement value from - VFunction.
  • get <name> temperature
    Obtain the temperature value.
  • get <name> VDD
    Obtain the current supply voltage.
  • get <name> V or get <name> - raw
    Obtain the raw external voltage measurement.
  • + raw
    Obtain the raw external voltage and external sense measurement.

    Attributes

    =end html diff --git a/fhem/FHEM/21_OWSWITCH.pm b/fhem/FHEM/21_OWSWITCH.pm index 5fbd9da81..53e60fdfd 100644 --- a/fhem/FHEM/21_OWSWITCH.pm +++ b/fhem/FHEM/21_OWSWITCH.pm @@ -16,7 +16,7 @@ # where may be replaced by any name string # # is a 1-Wire device type. If omitted, we assume this to be an -# DS2413. Allowed values are DS2413, DS2406 +# DS2413. Allowed values are DS2413, DS2406, DS2408 # is a 1-Wire family id, currently allowed values are 12, 29, 3A # is a 12 character (6 byte) 1-Wire ROM ID # without Family ID, e.g. A2D90D000800 @@ -45,10 +45,8 @@ # Additional attributes are defined in fhem.cfg, in some cases per channel, where =A,B # Note: attributes are read only during initialization procedure - later changes are not used. # -# attr stateS = character string denoting external shortening condition, default is (ext) -# overwritten by an attribute setting "red angled arrow downward" -# -# attr Name | = name for the channel [|name used in state reading] +# attr stateS = character string denoting external shortening condition, default is X +# attr Name | = name for the channel [|short name used in state reading] # attr Unit | = values to display in state variable for on|off condition # ######################################################################################## @@ -89,7 +87,7 @@ no warnings 'deprecated'; sub Log($$); -my $owx_version="5.24"; +my $owx_version="6.0"; #-- fixed raw channel name, flexible channel name my @owg_fixed = ("A","B","C","D","E","F","G","H"); my @owg_channel = ("A","B","C","D","E","F","G","H"); @@ -131,8 +129,6 @@ my %cnumber = ( # # OWSWITCH_Initialize # -# CalledBy: FHEM -# Calling: -- # Parameter: hash = hash of device addressed # ######################################################################################## @@ -148,7 +144,7 @@ sub OWSWITCH_Initialize ($) { $hash->{InitFn} = "OWSWITCH_Init"; $hash->{AttrFn} = "OWSWITCH_Attr"; - my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2413,DS2406,DS2408 loglevel:0,1,2,3,4,5 ". + my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2413,DS2406,DS2408 ". "stateS interval ". $readingFnAttributes; @@ -172,8 +168,6 @@ sub OWSWITCH_Initialize ($) { # # OWSWITCH_Define - Implements DefFn function # -# CalledBy: FHEM -# Calling: -- # Parameter: hash = hash of device addressed, def = definition string # ######################################################################################### @@ -280,8 +274,6 @@ sub OWSWITCH_Define ($$) { # # OWSWITCH_Notify - Implements Notify function # -# CalledBy: FHEM -# Calling: -- # Parameter: hash = hash of device addressed, def = definition string # ######################################################################################### @@ -298,8 +290,6 @@ sub OWSWITCH_Notify ($$) { # # OWSWITCH_Init - Implements Init function # -# CalledBy: FHEM -# Calling: -- # Parameter: hash = hash of device addressed, def = definition string # ######################################################################################### @@ -316,8 +306,6 @@ sub OWSWITCH_Init ($) { # # OWSWITCH_Attr - Set one attribute value for device # -# CalledBy: FHEM -# Calling: -- # Parameter: hash = hash of device addressed # a = argument array # @@ -362,8 +350,6 @@ sub OWSWITCH_Attr(@) { # # OWSWITCH_ChannelNames - find the real channel names # -# CalledBy: OWSWITCH_FormatValues, OWSWITCH_Get, OWSWITCH_Set -# Calling: -- # Parameter: hash = hash of device addressed # ######################################################################################## @@ -378,7 +364,7 @@ sub OWSWITCH_ChannelNames($) { for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){ #-- name - $cname = defined($attr{$name}{$owg_fixed[$i]."Name"}) ? $attr{$name}{$owg_fixed[$i]."Name"} : $owg_fixed[$i]; + $cname = defined($attr{$name}{$owg_fixed[$i]."Name"}) ? $attr{$name}{$owg_fixed[$i]."Name"} : "$owg_fixed[$i]"; @cnama = split(/\|/,$cname); if( int(@cnama)!=2){ push(@cnama,$cnama[0]); @@ -398,7 +384,6 @@ sub OWSWITCH_ChannelNames($) { #-- put into readings $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unit; - $hash->{READINGS}{$owg_channel[$i]}{UNITABBR} = $unit; } } @@ -406,8 +391,6 @@ sub OWSWITCH_ChannelNames($) { # # OWSWITCH_FormatValues - put together various format strings # -# CalledBy: OWSWITCH_Get, OWSWITCH_Set -# Calling: -- # Parameter; hash = hash of device addressed, fs = format string # ######################################################################################## @@ -420,7 +403,9 @@ sub OWSWITCH_FormatValues($) { my $svalue = ""; #-- external shortening signature - my $sname = defined($attr{$name}{"stateS"}) ? $attr{$name}{"stateS"} : "☇"; + my $sname = defined($attr{$name}{"stateS"}) ? $attr{$name}{"stateS"} : "X"; + $sname = "" + if($sname eq "none"); #-- obtain channel names OWSWITCH_ChannelNames($hash); @@ -466,10 +451,6 @@ sub OWSWITCH_FormatValues($) { # # OWSWITCH_Get - Implements GetFn function # -# CalledBy: FHEM -# Calling: OWSWITCH_ChannelNames,OWSWITCH_FormatValues, -# OWFSSWITCH_GetState,OWXSWITCH_GetState, -# OWX_Verify # Parameter: hash = hash of device addressed, a = argument array # ######################################################################################## @@ -480,6 +461,7 @@ sub OWSWITCH_Get($@) { my $reading = $a[1]; my $name = $hash->{NAME}; my $model = $hash->{OW_MODEL}; + my ($value,$value2,$value3) = (undef,undef,undef); my $ret = ""; my ($offset,$factor,$page,$cname,@cnama,@channel); @@ -550,7 +532,7 @@ sub OWSWITCH_Get($@) { #-- OWX interface if( $interface eq "OWX" ){ - $ret = OWXSWITCH_GetState($hash); + OWXSWITCH_GetModState($hash,undef,undef); }elsif( $interface eq "OWX_ASYNC") { eval { $ret = OWX_ASYNC_RunToCompletion($hash,OWXSWITCH_PT_GetState($hash)); @@ -563,8 +545,12 @@ sub OWSWITCH_Get($@) { }else{ return "OWSWITCH: Get with wrong IODev type $interface"; } - #-- process results - return $name.".".$a[2]." => ".$hash->{READINGS}{$owg_channel[$fnd]}{VAL}; + #-- process result + if( ($master->{ASYNCHRONOUS}) && ($interface ne "OWFS") ){ + return "OWSWITCH: $name getting input, please wait for completion"; + }else{ + return $name.".".$a[2]." => ".$hash->{READINGS}{$owg_channel[$fnd]}{VAL}; + } #-- get all states }elsif( $reading eq "gpio" ){ @@ -572,7 +558,7 @@ sub OWSWITCH_Get($@) { if( int(@a)==1 ); if( $interface eq "OWX" ){ - $ret = OWXSWITCH_GetState($hash); + $ret = OWXSWITCH_GetModState($hash,undef,undef); }elsif( $interface eq "OWX_ASYNC" ){ eval { $ret = OWX_ASYNC_RunToCompletion($hash,OWXSWITCH_PT_GetState($hash)); @@ -584,10 +570,14 @@ sub OWSWITCH_Get($@) { return "OWSWITCH: Get with wrong IODev type $interface"; } #-- process results - if( defined($ret) ){ - return "OWSWITCH: Could not get values from device $name, reason $ret"; + if( $master->{ASYNCHRONOUS} ){ + return "OWSWITCH: $name getting gpio, please wait for completion"; + }else{ + if( defined($ret) ){ + return "OWSWITCH: Could not get values from device $name, reason $ret"; + } + return "OWSWITCH: $name.$reading => ".$hash->{READINGS}{"state"}{VAL}; } - return "OWSWITCH: $name.$reading => ".$hash->{READINGS}{"state"}{VAL}; } } @@ -620,7 +610,7 @@ sub OWSWITCH_GetValues($) { if( $interface eq "OWX" ){ #-- max 3 tries for(my $try=0; $try<3; $try++){ - $ret = OWXSWITCH_GetState($hash); + $ret = OWXSWITCH_GetModState($hash,undef,undef); return if( !defined($ret) ); } }elsif( $interface eq "OWX_ASYNC" ){ @@ -652,6 +642,7 @@ sub OWSWITCH_GetValues($) { ######################################################################################## # # OWSWITCH_InitializeDevice - initial readings +# # Parameter hash = hash of device addressed # ######################################################################################## @@ -738,24 +729,24 @@ sub OWSWITCH_Set($@) { return "OWSWITCH: Set needs parameter when writing output: " if( int(@a)<2 ); #-- find out which channel we have - my $fnd=undef; + my $outfnd=undef; for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){ if( ($a[2] eq $owg_channel[$i]) || ($a[2] eq $owg_fixed[$i]) ){ - $fnd=$i; + $outfnd=$i; last; } } return "OWSWITCH: Invalid output address, must be A,B,... or defined channel name" - if( !defined($fnd) ); + if( !defined($outfnd) ); #-- prepare gpio value - my $nval; + my $outval; my $ntim; my $nstr=""; if( lc($a[3]) eq "on" ){ - $nval = 0; + $outval = 0; }elsif( lc($a[3]) eq "off" ){ - $nval = 1; + $outval = 1; }elsif( lc($a[3]) =~ m/for-timer/ ){ if( !($a[4] =~ m/\d\d\:\d\d\:\d\d/) ){ if( !($a[4] =~ m/\d{1,4}/ )){ @@ -767,10 +758,10 @@ sub OWSWITCH_Set($@) { $ntim= $a[4]; } if( lc($a[3]) eq "on-for-timer" ){ - $nval = 0; + $outval = 0; $nstr = "$a[0] $a[1] $a[2] off"; }elsif( lc($a[3]) eq "off-for-timer" ){ - $nval = 1; + $outval = 1; $nstr = "$a[0] $a[1] $a[2] on"; } }else{ @@ -778,36 +769,31 @@ sub OWSWITCH_Set($@) { } if ($nstr ne ""){ - fhem("define ".$a[0].".".$owg_fixed[$fnd]."Timer at +".$ntim." set ".$nstr); + fhem("define ".$a[0].".".$owg_fixed[$outfnd]."Timer at +".$ntim." set ".$nstr); } #-- OWX interface if( $interface eq "OWX" ){ - $ret1 = OWXSWITCH_GetState($hash); - $value = 0; - #-- vax or val ? - for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){ - $value += ($hash->{owg_vax}->[$i]<<$i) - if( $i != $fnd ); - $value += ($nval<<$i) - if( $i == $fnd ); - } - $ret2 = OWXSWITCH_SetState($hash,$value); + $ret1 = OWXSWITCH_GetModState($hash,$outfnd,$outval); }elsif( $interface eq "OWX_ASYNC"){ eval { - OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetOutput($hash,$fnd,$nval) ); + OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetOutput($hash,$outfnd,$outval) ); }; $ret2 = GP_Catch($@) if $@; #-- OWFS interface }elsif( $interface eq "OWServer" ){ $ret1 = OWFSSWITCH_GetState($hash); - $value = 0; - #-- vax or val ? + my $gpio = 0; + #-- for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){ - $value += ($hash->{owg_vax}->[$i]<<$i) - if( $i != $fnd ); - $value += ($nval<<$i) - if( $i == $fnd ); + if( $outval==0 ){ + $gpio += ($hash->{owg_vax}->[$i]<<$i) + if( $i != $outfnd ); + }else{ + $gpio += ($hash->{owg_vax}->[$i]<<$i); + $gpio += (1<<$i) + if( $i == $outfnd ); + } } $ret2 = OWFSSWITCH_SetState($hash,$value); #-- Unknown interface @@ -848,7 +834,7 @@ sub OWSWITCH_Set($@) { } #-- process results - we have to reread the device - OWSWITCH_GetValues($hash); + #OWSWITCH_GetValues($hash); Log 4, "OWSWITCH: Set $hash->{NAME} $key $value"; return undef; } @@ -1009,124 +995,216 @@ sub OWFSSWITCH_SetState($$) { # ######################################################################################## # -# OWXSWITCH_BinValues - Binary readings into clear values +# OWXSWITCH_BinValues - Process reading from one device - translate binary into raw # # Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string +# # ######################################################################################## -sub OWXSWITCH_BinValues($$$$$$$$) { - my ($hash, $context, $success, $reset, $owx_dev, $command, $numread, $res) = @_; - - #-- always check for success, unused are reset, numread - return unless ($success and $context); - #Log 1,"OWXSWITCH_BinValues context = $context"; +sub OWXSWITCH_BinValues($$$$$$$) { + my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_; - my @data=[]; - my $value; #-- hash of the busmaster my $master = $hash->{IODev}; + my $name = $hash->{NAME}; + my @data=[]; + my $value; + my $msg; + my $cmd; + my $chip; + my $outfnd; + my $outval; + OWX_WDBG($name,"OWXSWITCH_BinValues called for device $name in context $context with data ",$res) + if( $main::owx_debug>2 ); + #-- note: value 1 corresponds to OFF, 0 to ON normally # val = input value, vax = output value #-- Outer if - check get or set - if ( $context =~ /.*getstate.*/ ){ + if ( $context =~ /^(......)\.(get|mod)state\.?(\d)?\.?(\d)?/){ + $cmd = $2; + $chip = $1; + $outfnd = $3; + $outval = $4; #-- family = 12 => DS2406 ------------------------------------------------------- - if( ($context eq "getstate.ds2406") or ($context eq "ds2406.getstate") ) { + if( $chip eq "ds2406" ) { @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 4 bytes" - if (@data != 4); - return "invalid CRC" - if ( OWX_CRC16($command.substr($res,0,2),$data[2],$data[3]) == 0); - $hash->{owg_val}->[0] = (ord($data[0])>>2) & 1; - $hash->{owg_vax}->[0] = ord($data[0]) & 1; - $hash->{owg_val}->[1] = (ord($data[0])>>3) & 1; - $hash->{owg_vax}->[1] = (ord($data[0])>>1) & 1; - + if (@data != 4){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 4 bytes, "; + }elsif(OWX_CRC16($crcpart.substr($res,0,2),$data[2],$data[3]) == 0){ + $msg="Error - state could not be set for device $name, invalid CRC, "; + }else{ + $msg="No error, "; + $value=ord($data[0]); + $hash->{owg_val}->[0] = ($value>>2) & 1; + $hash->{owg_vax}->[0] = $value & 1; + $hash->{owg_val}->[1] = ($value>>3) & 1; + $hash->{owg_vax}->[1] = ($value>>1) & 1; + + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); + #-- family = 29 => DS2408 ------------------------------------------------------- - }elsif( ($context eq "getstate.ds2408") or ($context eq "ds2408.getstate") ) { + }elsif( $chip eq "ds2408" ) { @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 10 bytes" - if (@data != 10); - return "invalid data" - if (ord($data[6])!=255); - return "invalid CRC" - if( OWX_CRC16($command.substr($res,0,8),$data[8],$data[9]) == 0); - for(my $i=0;$i<8;$i++){ - $hash->{owg_val}->[$i] = (ord($data[0])>>$i) & 1; - $hash->{owg_vax}->[$i] = (ord($data[1])>>$i) & 1; - }; + if (@data != 10){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 10 bytes, "; + }elsif(ord($data[6])!=255){ + $msg="Error - $name returns invalid data, "; + }elsif(OWX_CRC16($crcpart.substr($res,0,8),$data[8],$data[9]) == 0){ + $msg="Error - state could not be set for device $name, invalid CRC, "; + }else{ + $msg="No error, "; + for(my $i=0;$i<8;$i++){ + $hash->{owg_val}->[$i] = (ord($data[0])>>$i) & 1; + $hash->{owg_vax}->[$i] = (ord($data[1])>>$i) & 1; + }; + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); #-- family = 3A => DS2413 ------------------------------------------------------- - }elsif( ($context eq "getstate.ds2413") or ($context eq "ds2413.getstate") ){ + }elsif( $chip eq "ds2413" ){ @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 2 bytes" - if (@data != 2); - return "invalid data" - if ( (15- (ord($data[0])>>4)) != (ord($data[0]) & 15) ); - $hash->{owg_val}->[0] = ord($data[0]) & 1; - $hash->{owg_vax}->[0] = (ord($data[0])>>1) & 1; - $hash->{owg_val}->[1] = (ord($data[0])>>2) & 1; - $hash->{owg_vax}->[1] = (ord($data[0])>>3) & 1; + if (@data != 2){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, "; + }elsif((15- (ord($data[0])>>4)) != (ord($data[0]) & 15)){ + $msg="Error - $name returns invalid data, "; + }else{ + $msg="No error, "; + $hash->{owg_val}->[0] = ord($data[0]) & 1; + $hash->{owg_vax}->[0] = (ord($data[0])>>1) & 1; + $hash->{owg_val}->[1] = (ord($data[0])>>2) & 1; + $hash->{owg_vax}->[1] = (ord($data[0])>>3) & 1; + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); + #-- }else{ - return "unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues getstate\n"; + die "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues getstate\n"; }; + #-- now only if data has to be overwritten + if( $cmd eq "mod" ){ + my $gpio = 0; + #-- + for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){ + if( $outval==0 ){ + $gpio += ($hash->{owg_vax}->[$i]<<$i) + if( $i != $outfnd ); + }else{ + $gpio += ($hash->{owg_vax}->[$i]<<$i); + $gpio += (1<<$i) + if( $i == $outfnd ); + } + } + #-- re-set the state + OWXSWITCH_SetState($hash,$gpio); + } #-- Now for context setstate - }elsif ( $context =~ /.*setstate.*/){ + }elsif ( $context =~ /^(......)\.setstate\.?(\d+)?\.?(\d+)?/){ + $chip = $1; + $value = $2; #-- family = 12 => DS2406 ------------------------------------------------------- - if( ($context =~ /setstate\.ds2406\..*/) or ($context =~ /ds2406\.setstate\..*/) ) { - $value = substr($context,-1); + if( $chip eq "ds2406" ) { @data=split(//,$res); - return "state could not be set for device $owx_dev" - if( int(@data) != 2); - return "invalid CRC" - if (OWX_CRC16($command,$data[0],$data[1]) == 0); - #-- put into local buffer]"; - $hash->{owg_val}->[0] = $value % 2; - $hash->{owg_vax}->[0] = $value % 2; - $hash->{owg_val}->[1] = int($value / 2); - $hash->{owg_vax}->[1] = int($value / 2); - + if (@data != 2){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, "; + }elsif(OWX_CRC16($crcpart,$data[0],$data[1]) == 0){ + $msg="Error - state could not be set for device $name, invalid CRC, "; + }else{ + $msg="No error, "; + $outval = $value % 2; + $hash->{owg_vax}->[0] = $outval; + $hash->{owg_val}->[0] = 0 + if( $outval ==0); + $outval = int($value / 2); + $hash->{owg_vax}->[1] = $outval; + $hash->{owg_val}->[1] = 0 + if( $outval ==0); + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); + #-- family = 29 => DS2408 ------------------------------------------------------- - }elsif( ($context eq "setstate.ds2408") or ($context eq "ds2408.setstate") ) { - @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 1 bytes" - if (@data != 1); - return "state could not be set for device $owx_dev" - if( $data[0] ne "\xAA"); + }elsif( $chip eq "ds2408" ) { + if (length($res)!=1){ + $msg="Error - $name returns invalid data length, ".length($res)." instead of 1 bytes, "; + }elsif($res ne "\xAA"){ + $msg="Error - state could not be set for device $name, "; + }else{ + $msg="No error, "; + for(my $i=0;$i<8;$i++){ + $outval = ($value >>$i) & 1; + $hash->{owg_vax}->[$i] = $outval; + $hash->{owg_val}->[$i] = 0 + if( $outval ==0); + }; + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); + #-- family = 3A => DS2413 ------------------------------------------------------- - }elsif( ($context eq "setstate.ds2413") or ($context eq "ds2413.setstate") ){ + }elsif( $chip eq "ds2413" ){ @data=split(//,$res); - return "invalid data length, ".int(@data)." instead of 1 bytes" - if (@data != 1); - return "state could not be set for device $owx_dev" - if( $data[0] ne "\xAA"); + if (@data != 2){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, "; + }elsif( $data[0] ne "\xAA"){ + $msg="Error - state could not be set for device $name, "; + }else{ + $msg="No error, "; + $outval = (ord($data[1])>>1) & 1; + $hash->{owg_vax}->[0] = $outval; + $hash->{owg_val}->[0] = 0 + if( $outval ==0); + $outval = (ord($data[1])>>3) & 1; + $hash->{owg_vax}->[1] = $outval; + $hash->{owg_val}->[1] = 0 + if( $outval ==0); + } + OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); #-- }else{ - return "unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues setstate\n"; + die "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues setstate\n"; }; + OWXSWITCH_GetModState($hash,undef,undef); }else{ - return "unknown context in OWXSWITCH_BinValues"; + die "OWSWITCH: unknown context $context in OWXSWITCH_BinValues"; } #-- and now from raw to formatted values $hash->{PRESENT} = 1; $value = OWSWITCH_FormatValues($hash); - Log 5, $value; return undef; } ######################################################################################## # -# OWXSWITCH_GetState - Get gpio ports from device +# OWXSWITCH_GetModState - Get gpio ports from device and overwrite # # Parameter hash = hash of device addressed +# mod = if 1, overwrite state with new data # ######################################################################################## -sub OWXSWITCH_GetState($@) { - my ($hash,$sync) = @_; +sub OWXSWITCH_GetModState($$$) { + my ($hash,$outfnd,$outval) = @_; my ($select, $res, @data); @@ -1137,12 +1215,24 @@ sub OWXSWITCH_GetState($@) { #-- hash of the busmaster my $master = $hash->{IODev}; + my $name = $hash->{NAME}; #-- reset presence $hash->{PRESENT} = 0; - my ($i,$j,$k); - + #-- what do we have to do + my $context; + my $proc; + if( !defined($outfnd) ){ + $context = "getstate"; + #-- take your time + $proc = 0; + }else{ + $context = "modstate.$outfnd.$outval"; + #-- faster ! + $proc = 16; + } + #-- family = 12 => DS2406 if( $hash->{OW_FAMILY} eq "12" ) { #=============== get gpio values =============================== @@ -1150,45 +1240,78 @@ sub OWXSWITCH_GetState($@) { # \xF5 plus the two byte channel control and the value #-- reading 9 + 3 + 2 data bytes + 2 CRC bytes = 16 bytes $select=sprintf("\xF5\xDD\xFF"); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,4); - return "$owx_dev not accessible in reading" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=16); - OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2406.getstate",1,undef,$owx_dev,substr($res,9,3),undef,substr($res,12)); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,4); + return "OWSWITCH: $name not accessible in reading" + if( $res eq 0 ); + return "OWSWITCH: $name has returned invalid data" + if( length($res)!=16); + #OWX_Reset($master); + eval { + OWXSWITCH_BinValues($hash,"ds2406.$context",undef,$owx_dev,$select,4,substr($res,12)); + }; + return $@ ? $@ : undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "ds2406.$context", $proc, $owx_dev, $select, $select, 4, 12, \&OWXSWITCH_BinValues, 0); + return undef; + } #-- family = 29 => DS2408 }elsif( $hash->{OW_FAMILY} eq "29" ) { #=============== get gpio values =============================== - #-- issue the match ROM command \x55 and the read PIO rtegisters command + #-- issue the match ROM command \x55 and the read PIO registers command # \xF5 plus the two byte channel target address #-- reading 9 + 3 + 8 data bytes + 2 CRC bytes = 22 bytes - $select=sprintf("\xF0\x88\x00"); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,10); - return "$owx_dev not accessible in reading" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=22); - OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2408.getstate",1,undef,$owx_dev,substr($res,9,3),undef,substr($res,12)); + $select=sprintf("\xF0\x88\x00"); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,10); + return "OWSWITCH: $name not accessible in reading" + if( $res eq 0 ); + return "OWSWITCH: $name has returned invalid data" + if( length($res)!=22); + #OWX_Reset($master); + eval { + OWXSWITCH_BinValues($hash,"ds2408.$context",0,$owx_dev,$select,4,substr($res,12)); + }; + return $@ ? $@ : undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "ds2408.$context", $proc, $owx_dev, $select, $select,10, 12, \&OWXSWITCH_BinValues, 0); + return undef; + } #-- family = 3A => DS2413 }elsif( $hash->{OW_FAMILY} eq "3A" ) { #=============== get gpio values =============================== #-- issue the match ROM command \x55 and the read gpio command # \xF5 plus 2 empty bytes #-- reading 9 + 1 + 2 data bytes = 12 bytes - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,"\xF5",2); - return "$owx_dev not accessible in reading" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=12); - #OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2413.getstate",1,undef,$owx_dev,substr($res,9,1),undef,substr($res,10)); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,"\xF5",2); + return "OWSWITCH: $name not accessible in reading" + if( $res eq 0 ); + return "OWSWITCH: $name has returned invalid data" + if( length($res)!=12); + #OWX_Reset($master); + eval { + OWXSWITCH_BinValues($hash,"ds2413.$context",0,$owx_dev,substr($res,9,1),2,substr($res,10)); + }; + return $@ ? $@ : undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, "ds2413.$context", $proc, $owx_dev, "\xF5", "\xF5", 2, 10, \&OWXSWITCH_BinValues, 0); + return undef; + } } else { - return "unknown device family $hash->{OW_FAMILY}\n"; + return "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY}\n"; } } @@ -1197,7 +1320,7 @@ sub OWXSWITCH_GetState($@) { # OWXSWITCH_SetState - Set gpio ports of device # # Parameter hash = hash of device addressed -# value = integer value for device outputs +# value = integer value for device gpio output # ######################################################################################## @@ -1205,7 +1328,6 @@ sub OWXSWITCH_SetState($$) { my ($hash,$value) = @_; - my ($select, $res, $res2, @data); #-- ID of the device @@ -1215,8 +1337,6 @@ sub OWXSWITCH_SetState($$) { #-- hash of the busmaster my $master = $hash->{IODev}; - - my ($i,$j,$k); #-- family = 12 => DS2406 if( $hash->{OW_FAMILY} eq "12" ) { @@ -1240,42 +1360,66 @@ sub OWXSWITCH_SetState($$) { # \x55 at address TA1 = \x07 TA2 = \x00 #-- reading 9 + 4 + 2 data bytes = 15 bytes $select=sprintf("\x55\x07\x00%c",$statneu); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,2); - if( $res eq 0 ){ - return "device $owx_dev not accessible in writing"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,2); + if( $res eq 0 ){ + return "device $owx_dev not accessible in writing"; + } + #OWX_Reset($master); + return OWXSWITCH_BinValues($hash,"ds2406.setstate.$value",0,$owx_dev,$select,2,substr($res,13)); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + # 16 pushes this to the top of the queue + OWX_Qomplex($master, $hash, "ds2406.setstate.$value", 16, $owx_dev, $select, $select, 2, 13, \&OWXSWITCH_BinValues, 0); + return undef; } - OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2406.setstate.$value",1,undef,$owx_dev,substr($res,9,4),undef,substr($res,13)); - return; #-- family = 29 => DS2408 } elsif( $hash->{OW_FAMILY} eq "29" ) { #=============== set gpio values =============================== #-- issue the match ROM command \x55 and the write gpio command # \x5A plus the value byte and its complement $select=sprintf("\x5A%c%c",$value,255-$value); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,1); - if( $res eq 0 ){ - return "device $owx_dev not accessible in writing"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,1); + if( $res eq 0 ){ + return "device $owx_dev not accessible in writing"; + } + OWX_Reset($master); + return OWXSWITCH_BinValues($hash,"ds2408.setstate.$value",0,$owx_dev,0,1,substr($res,12)); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay +# 16 pushes this to the top of the queue + OWX_Qomplex($master, $hash, "ds2408.setstate.$value", 16, $owx_dev, $select, 0, 1, 12, \&OWXSWITCH_BinValues, 0); + return undef; } - OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2408.setstate",1,undef,$owx_dev,undef,undef,substr($res,12)); - return; #-- family = 3A => DS2413 } elsif( $hash->{OW_FAMILY} eq "3A" ) { #=============== set gpio values =============================== #-- issue the match ROM command \x55 and the write gpio command # \x5A plus the value byte and its complement $select=sprintf("\x5A%c%c",252+$value,3-$value); - OWX_Reset($master); - $res=OWX_Complex($master,$owx_dev,$select,1); - if( $res eq 0 ){ - return "device $owx_dev not accessible in writing"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + $res=OWX_Complex($master,$owx_dev,$select,1); + if( $res eq 0 ){ + return "device $owx_dev not accessible in writing"; + } + OWX_Reset($master); + return OWXSWITCH_BinValues($hash,"ds2413.setstate",0,$owx_dev,0,2,substr($res,12)); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data cmd numread startread callback delay + # 16 pushes this to the top of the queue + OWX_Qomplex($master, $hash, "ds2413.setstate", 16, $owx_dev, $select, 0, 2, 12, \&OWXSWITCH_BinValues, 0); + return undef; } - OWX_Reset($master); - return OWXSWITCH_BinValues($hash,"ds2413.setstate",1,undef,$owx_dev,undef,undef,substr($res,12)); - return; }else { return "unknown device family $hash->{OW_FAMILY}\n"; } @@ -1322,7 +1466,7 @@ sub OWXSWITCH_PT_GetState($) { unless (length($response) == 4) { PT_EXIT("$owx_dev has returned invalid data"); } - $ret = OWXSWITCH_BinValues($hash,"ds2406.getstate",1,1,$owx_dev,$thread->{'select'},4,$response); + $ret = OWXSWITCH_BinValues($hash,"ds2406.getstate",1,$owx_dev,$thread->{'select'},4,$response); if (defined $ret) { PT_EXIT($ret); } @@ -1340,7 +1484,7 @@ sub OWXSWITCH_PT_GetState($) { unless (length($response) == 10) { PT_EXIT("$owx_dev has returned invalid data") }; - $ret = OWXSWITCH_BinValues($hash,"ds2408.getstate",1,1,$owx_dev,$thread->{'select'},10,$response); + $ret = OWXSWITCH_BinValues($hash,"ds2408.getstate",1,$owx_dev,$thread->{'select'},10,$response); if (defined $ret) { PT_EXIT($ret); } @@ -1358,7 +1502,7 @@ sub OWXSWITCH_PT_GetState($) { unless (length($response) == 2) { PT_EXIT("$owx_dev has returned invalid data"); } - $ret = OWXSWITCH_BinValues($hash,"ds2413.getstate",1,1,$owx_dev,$thread->{'select'},2,$response); + $ret = OWXSWITCH_BinValues($hash,"ds2413.getstate",1,$owx_dev,$thread->{'select'},2,$response); if (defined $ret) { PT_EXIT($ret); } @@ -1534,7 +1678,7 @@ sub OWXSWITCH_PT_SetOutput($$$) {

    define OWX_S OWSWITCH DS2413 B5D502000000 60
    - attr OWX_S AName Lampe|light + attr OWX_S AName light-a|la
    attr OWX_S AUnit AN|AUS

    @@ -1597,7 +1741,7 @@ sub OWXSWITCH_PT_SetOutput($$$) {
    Returns 1 if this 1-Wire device is present, otherwise 0.
  • - get <name> interval
    Returns measurement interval in + get <name> interval
    Measurement interval in seconds.
  • get <name> input <channel-name>
    state for @@ -1605,7 +1749,7 @@ sub OWXSWITCH_PT_SetOutput($$$) { not necessarily the one set as output state, because the output transistors are open collector switches. A measured state of 1 = OFF therefore corresponds to an output state of 1 = OFF, but a measured state of 0 = ON can also be due to an external - shortening of the output.
  • + shortening of the output, it will be signaled by appending the value of the attribute stateS to the reading.
  • get <name> gpio
    Obtain state of all channels
  • @@ -1613,19 +1757,14 @@ sub OWXSWITCH_PT_SetOutput($$$) {

    Attributes

    For each of the following attributes, the channel identification A,B,... may be used. =end html diff --git a/fhem/FHEM/21_OWTHERM.pm b/fhem/FHEM/21_OWTHERM.pm index c049db51e..34bd565d9 100644 --- a/fhem/FHEM/21_OWTHERM.pm +++ b/fhem/FHEM/21_OWTHERM.pm @@ -35,8 +35,8 @@ # # Additional attributes are defined in fhem.cfg # -# attr stateAL "" = character string for denoting low alarm condition, default is down triangle -# attr stateAH "" = character string for denoting high alarm condition, default is up triangle +# attr stateAL "" = character string for denoting low alarm condition, default is ↓ +# attr stateAH "" = character string for denoting high alarm condition, default is ↑ # attr tempOffset = temperature offset in degree Celsius added to the raw temperature reading # attr tempUnit = unit of measurement, e.g. Celsius/Kelvin/Fahrenheit, default is Celsius # attr tempConv onkick|onread = determines, whether a temperature measurement will happen when "kicked" @@ -86,7 +86,7 @@ no warnings 'deprecated'; sub Log3($$$); sub AttrVal($$$); -my $owx_version="5.28"; +my $owx_version="6.0"; my %gets = ( "id" => "", @@ -141,7 +141,7 @@ sub OWTHERM_Initialize ($) { $hash->{NotifyFn}= "OWTHERM_Notify"; $hash->{InitFn} = "OWTHERM_Init"; $hash->{AttrFn} = "OWTHERM_Attr"; - $hash->{AttrList}= "IODev model:DS1820,DS18B20,DS1822 loglevel:0,1,2,3,4,5 ". + $hash->{AttrList}= "IODev model:DS1820,DS18B20,DS1822 ". "stateAL stateAH ". "tempOffset tempUnit:Celsius,Fahrenheit,Kelvin ". "tempConv:onkick,onread tempLow tempHigh ". @@ -254,7 +254,7 @@ sub OWTHERM_Define ($$) { $modules{OWTHERM}{defptr}{$id} = $hash; #-- readingsSingleUpdate($hash,"state","defined",1); - Log3 $name, 3, "OWTHERM: Device $name defined."; + Log3 $name, 3, "OWTHERM: Device $name defined."; $hash->{NOTIFYDEV} = "global"; @@ -264,6 +264,16 @@ sub OWTHERM_Define ($$) { return undef; } +####################################################################################### +# +# OWTHERM_Notify - Implements the Notify function +# +# Parameter hash = hash of device addressed +# a = argument array +# +######################################################################################## + + sub OWTHERM_Notify ($$) { my ($hash,$dev) = @_; if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) { @@ -272,6 +282,16 @@ sub OWTHERM_Notify ($$) { } } +####################################################################################### +# +# OWTHERM_Init - Implements the Init function +# +# Parameter hash = hash of device addressed +# a = argument array +# +######################################################################################## + + sub OWTHERM_Init ($) { my ($hash)=@_; #-- Start timer for updates @@ -355,28 +375,29 @@ sub OWTHERM_FormatValues($) { my $svalue = ""; #-- attributes defined ? - $stateal = AttrVal($name,"stateAL","▾"); - $stateah = AttrVal($name,"stateAH","▴"); + $stateal = AttrVal($name,"stateAL","↓"); + $stateah = AttrVal($name,"stateAH","↑"); $unit = AttrVal($name,"tempUnit","Celsius"); $offset = AttrVal($name,"tempOffset",0.0); $factor = 1.0; - if( $unit eq "Celsius" ){ - $abbr = "°C"; + if( $unit eq "none" ){ + $abbr = ""; + }elsif( $unit eq "Celsius" ){ + $abbr = " °C"; } elsif ($unit eq "Kelvin" ){ - $abbr = "K"; + $abbr = " K"; $offset += "273.16" } elsif ($unit eq "Fahrenheit" ){ - $abbr = "°F"; + $abbr = " °F"; $offset = ($offset+32)/1.8; $factor = 1.8; } else { - $abbr="?"; + $abbr=" ?"; Log3 $name, 3, "OWTHERM_FormatValues: Unknown temperature unit $unit"; } #-- these values are rather complex to obtain, therefore save them in the hash - $hash->{READINGS}{"temperature"}{UNIT} = $unit; - $hash->{READINGS}{"temperature"}{UNITABBR} = $abbr; + $hash->{READINGS}{"temperature"}{UNIT} = $abbr; $hash->{tempf}{offset} = $offset; $hash->{tempf}{factor} = $factor; @@ -392,7 +413,7 @@ sub OWTHERM_FormatValues($) { $main::attr{$name}{"tempHigh"} = $vhigh; #-- formats for output - $statef = "T: %5.2f ".$abbr; + $statef = "T: %5.2f".$abbr; $svalue = sprintf($statef,$vval); #-- Test for alarm condition @@ -431,6 +452,7 @@ sub OWTHERM_Get($@) { my $reading = $a[1]; my $name = $hash->{NAME}; my $model = $hash->{OW_MODEL}; + my $value = undef; my $ret = ""; @@ -450,6 +472,7 @@ sub OWTHERM_Get($@) { #-- hash of the busmaster my $master = $hash->{IODev}; + #-- Get other values according to interface type my $interface= $hash->{IODev}->{TYPE}; @@ -503,19 +526,24 @@ sub OWTHERM_Get($@) { } #-- process results - if( defined($ret) ){ - return "OWTHERM: Could not get values from device $name, return was $ret"; + if( $master->{ASYNCHRONOUS} ){ + return "OWTHERM: $name getting values, please wait for completion"; + }else{ + #-- when we have a return code, we have an error + if( defined($ret) ){ + return "OWTHERM: Could not get values from device $name, return was $ret"; + } + #-- return the special reading + if ($reading eq "temperature") { + return "OWTHERM: $name.temperature => ". + $hash->{READINGS}{"temperature"}{VAL}; + } elsif ($reading eq "alarm") { + return "OWTHERM: $name.alarm => L ".$main::attr{$name}{"tempLow"}. + " H ".$main::attr{$name}{"tempHigh"}; + } else { + return undef; + } } - - #-- return the special reading - if ($reading eq "temperature") { - return "OWTHERM: $name.temperature => ". - $hash->{READINGS}{"temperature"}{VAL}; - } elsif ($reading eq "alarm") { - return "OWTHERM: $name.alarm => L ".$main::attr{$name}{"tempLow"}. - " H ".$main::attr{$name}{"tempHigh"}; - } - return undef; } ####################################################################################### @@ -615,9 +643,8 @@ sub OWTHERM_InitializeDevice($) { Log3 $name, 3, "OWTHERM_InitializeDevice: unknown unit $unit"; } #-- these values are rather complex to obtain, therefore save them in the hash - $hash->{READINGS}{"temperature"}{TYPE} = "temperature"; - $hash->{READINGS}{"temperature"}{UNIT} = $unit; - $hash->{READINGS}{"temperature"}{UNITABBR} = $abbr; + $hash->{READINGS}{"temperature"}{TYPE} = "temperature"; + $hash->{READINGS}{"temperature"}{UNIT} = $abbr; $hash->{ERRCOUNT} = 0; $hash->{tempf}{offset} = $offset; $hash->{tempf}{factor} = $factor; @@ -894,32 +921,53 @@ sub OWFSTHERM_SetValues($$) { # ######################################################################################## # -# OWXTHERM_BinValues - Binary readings into clear values +# OWXTHERM_BinValues - Process reading from one device - translate binary into raw # # Parameter hash = hash of device addressed +# context = mode for evaluating the binary data +# proc = processing instruction, also passed to OWX_Read. +# bitwise interpretation !! +# if 0, nothing special +# if 1 = bit 0, a reset will be performed not only before, but also after +# the last operation in OWX_Read +# if 2 = bit 1, the initial reset of the bus will be suppressed +# if 8 = bit 3, the fillup of the data with 0xff will be suppressed +# if 16= bit 4, the insertion will be at the top of the queue +# owx_dev = ROM ID of slave device +# crcpart = part of the data that needs to be part of the CRC check +# numread = number of bytes to receive +# res = result string +# # ######################################################################################## -sub OWXTHERM_BinValues($$$$$$) { - my ($hash, $reset, $owx_dev, $command, $numread, $res) = @_; - - #Log3 $name, 1,"OWXTHERM_BinValues context = $context"; +sub OWXTHERM_BinValues($$$$$$$) { + my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_; my ($i,$j,$k,@data,$ow_thn,$ow_tln); my $change = 0; - - #Log3 $name, 1,"OWXTHERM: data length from reading device is ".length($res)." bytes"; - #-- process results - die "$owx_dev not accessible in 2nd step" unless ( defined $res and $res ne 0 ); + my $name = $hash->{NAME}; + my $msg; + OWX_WDBG($name,"OWTHERM_BinValues called for device $name with ",$res) + if( $main::owx_debug>2 ); #-- process results @data=split(//,$res); - die "invalid data length, ".int(@data)." instead of 9 bytes" - if (@data != 9); - die "invalid data" - if (ord($data[7])<=0); - die "invalid CRC" - if (OWX_CRC8(substr($res,0,8),$data[8])==0); + if (@data != 9){ + $msg="Error - $name returns invalid data length, ".int(@data)." instead of 9 bytes, "; + }elsif(ord($data[7])<=0){ + $msg="Error - $name returns invalid data, "; + }elsif(OWX_CRC8(substr($res,0,8),$data[8])==0){ + $msg="Error - invalid data from device $name, invalid CRC, "; + }else{ + $msg="No error, "; + for(my $i=0;$i<8;$i++){ + $hash->{owg_val}->[$i] = (ord($data[0])>>$i) & 1; + $hash->{owg_vax}->[$i] = (ord($data[1])>>$i) & 1; + }; + } + OWX_WDBG($name,"OWXTHERM_BinValues: ".$msg,$res) + if( $main::owx_debug>2 ); #-- this must be different for the different device types # family = 10 => DS1820, DS18S20 @@ -967,7 +1015,7 @@ sub OWXTHERM_BinValues($$$$$$) { $ow_tln = ord($data[3]) > 127 ? 128-ord($data[3]) : ord($data[3]); } else { - die "OWXTHERM: Unknown device family $hash->{OW_FAMILY}\n"; + die "OWTHERM: $name: Unknown device family $hash->{OW_FAMILY}\n"; } #-- process alarm settings @@ -977,7 +1025,6 @@ sub OWXTHERM_BinValues($$$$$$) { #-- and now from raw to formatted values $hash->{PRESENT} = 1; my $value = OWTHERM_FormatValues($hash); - Log3 $hash->{NAME}, 5, $value; return undef; } @@ -1002,35 +1049,51 @@ sub OWXTHERM_GetValues($) { #-- hash of the busmaster my $master = $hash->{IODev}; my $name = $hash->{NAME}; + + my $res; #-- check, if the conversion has been called before for all sensors if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){ $con=0; } - #-- if the conversion has not been called before + #-- issue the match ROM command \x55 and the start conversion command \x44 + #-- conversion needs some 950 ms - but we may also do it in shorter time ! if( $con==1 ){ - #-- issue the match ROM command \x55 and the start conversion command \x44 - OWX_Reset($master); - if( OWX_Complex($master,$owx_dev,"\x44",0) eq 0 ){ - return "$owx_dev not accessible"; - } - #-- conversion needs some 950 ms - but we may also do it in shorter time ! - select(undef,undef,undef,$convtimes{AttrVal($name,"resolution",12)}*0.001); + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + if( OWX_Complex($master,$owx_dev,"\x44",0) eq 0 ){ + return "OWTHERM: $name not accessible"; + } + select(undef,undef,undef,$convtimes{AttrVal($name,"resolution",12)}*0.001); + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, undef, 0, $owx_dev, "\x44", 0, 0, undef, undef, $convtimes{AttrVal($name,"resolution",12)}*0.001); + } } #-- NOW ask the specific device #-- issue the match ROM command \x55 and the read scratchpad command \xBE #-- reading 9 + 1 + 8 data bytes and 1 CRC byte = 19 bytes - OWX_Reset($master); - my $res=OWX_Complex($master,$owx_dev,"\xBE",9); - return "$owx_dev not accessible in reading" - if( $res eq 0 ); - return "$owx_dev has returned invalid data" - if( length($res)!=19); - eval { - OWXTHERM_BinValues($hash,undef,$owx_dev,undef,undef,substr($res,10,9)); - }; - return $@ ? $@ : undef; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + my $res=OWX_Complex($master,$owx_dev,"\xBE",9); + return "OWTHERM: $name not accessible in reading" + if( $res eq 0 ); + return "OWTHERM: $name has returned invalid data" + if( length($res)!=19); + eval { + OWXTHERM_BinValues($hash,undef,$owx_dev,undef,undef,9,substr($res,10,9)); + }; + return $@ ? $@ : undef; + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, undef, 0, $owx_dev, "\xBE", 0, 9, 10, \&OWXTHERM_BinValues, 0); + return undef; + } } ####################################################################################### @@ -1045,8 +1108,6 @@ sub OWXTHERM_GetValues($) { sub OWXTHERM_SetValues($$) { my ($hash, $args) = @_; - my ($i,$j,$k); - my $name = $hash->{NAME}; #-- ID of the device @@ -1079,12 +1140,18 @@ sub OWXTHERM_SetValues($$) { # 3. \x48 sent by WriteBytePower after match ROM => command ok, no effect on EEPROM my $select=sprintf("\x4E%c%c%c",$thp,$tlp,$cfg); - OWX_Reset($master); - my $res=OWX_Complex($master,$owx_dev,$select,3); - if( $res eq 0 ){ - return "OWXTHERM: Device $owx_dev not accessible"; + #-- OLD OWX interface + if( !$master->{ASYNCHRONOUS} ){ + OWX_Reset($master); + my $res=OWX_Complex($master,$owx_dev,$select,3); + if( $res eq 0 ){ + return "OWTHERM: $name not accessible for setting"; + } + #-- NEW OWX interface + }else{ + #### master slave context proc owx_dev data crcpart numread startread callback delay + OWX_Qomplex($master, $hash, undef, 0, $owx_dev, $select, 0, 3, 10, undef, 0); } - return undef; } @@ -1137,7 +1204,7 @@ sub OWXTHERM_PT_GetValues($) { $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE",9); PT_WAIT_THREAD($thread->{pt_execute}); die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR); - OWXTHERM_BinValues($hash,1,$owx_dev,undef,9,$thread->{pt_execute}->PT_RETVAL()); + OWXTHERM_BinValues($hash,undef,1,$owx_dev,undef,9,$thread->{pt_execute}->PT_RETVAL()); PT_END; }); } @@ -1299,12 +1366,10 @@ sub OWXTHERM_PT_SetValues($$) { =end html