From 8a0ad7b62a59e9ffb21100be577f1ec3df5f63b0 Mon Sep 17 00:00:00 2001 From: Adimarantis Date: Thu, 28 Oct 2021 19:07:38 +0000 Subject: [PATCH] 58_RPI_1Wire: Support multiple busmasters, enhancements, fixes git-svn-id: https://svn.fhem.de/fhem/trunk@25140 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/58_RPI_1Wire.pm | 103 ++++++++++++++++++++++++-------------- fhem/FHEM/98_freezemon.pm | 5 +- 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index d351e07ad..938b83d37 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - change: 58_RPI_1Wire: Support for multiple Busmasters, enhancements, fixes - bugfix: 88_HMCCU: Keep eventMap when resetting attributes - bugfix: 88_HMCCU: Fixed attribute room bug - new: 58_RPI_1Wire: Raspberry Pi 1Wire interface replacing 58_GPIO4 diff --git a/fhem/FHEM/58_RPI_1Wire.pm b/fhem/FHEM/58_RPI_1Wire.pm index bf81f3296..5fde43c09 100755 --- a/fhem/FHEM/58_RPI_1Wire.pm +++ b/fhem/FHEM/58_RPI_1Wire.pm @@ -4,7 +4,6 @@ #and RoBue to access 1-Wire-Clones with ID: 28 53 44 54 xx xx xx #Possible Extensions: -#Check if bulk_read is writable, give hints and enable BUSMASTER to trigger this on a regular basis -> there is currently an issue when having non temperature w1 devices!!!! #Writing to the switches is not supported (but I also don't have the HW to test that) package main; @@ -34,7 +33,8 @@ sub RPI_1Wire_Initialize { "$readingFnAttributes"; } -my $w1_path="/sys/devices/w1_bus_master1"; +my $w1_path="/sys/bus/w1/devices"; +my $ms_path="/sys/devices/w1_bus_master"; my $dht_path="/sys/devices/platform/dht11@"; my %RPI_1Wire_Devices = @@ -67,8 +67,8 @@ sub RPI_1Wire_Notify { my $def=$own_hash->{DEF}; $def="" if (!defined $def); #GetDevices is triggering the autocreate calls, but this is not yet working (autocreate not ready?) so delay this by 10 seconds - InternalTimer(gettimeofday()+10, "RPI_1Wire_GetDevices", $own_hash, 0) if $own_hash->{DEF} eq "BUSMASTER"; - RPI_1Wire_Init($own_hash,$ownName." ".$own_hash->{TYPE}." ".$def); + RPI_1Wire_Init($own_hash,$def,0); + InternalTimer(gettimeofday()+10, "RPI_1Wire_GetDevices", $own_hash, 0) if $own_hash->{DEF} =~ /BUSMASTER/; } } @@ -89,44 +89,50 @@ sub RPI_1Wire_Define { # $hash->{NOTIFYDEV} = "global"; if ($init_done) { Log3 $hash->{NAME}, 2, "Define init_done: $def"; - my $ret=RPI_1Wire_Init($hash,$hash->{NAME}." ".$hash->{TYPE}." ".$hash->{DEF}); + $def =~ s/^\S+\s*\S+\s*//; #Remove devicename and type + my $ret=RPI_1Wire_Init($hash,$def,1); return $ret if $ret; } return; } ################################### sub RPI_1Wire_Init { # - my ( $hash, $args ) = @_; - Log3 $hash->{NAME}, 2, $hash->{NAME}.": Init: $args"; + my ( $hash, $args, $check ) = @_; + Log3 $hash->{NAME}, 2, $hash->{NAME}.": Init: $args $check"; if (! -e "$w1_path") { $hash->{STATE} ="No 1-Wire Bus found"; Log3 $hash->{NAME}, 3, $hash->{NAME}.": Init: $hash->{STATE}"; return $hash->{STATE}; } - my @a = (); - @a = split("[ \t]+", $args) if defined $args; - shift @a;shift @a; - my $name = $hash->{NAME}; - if (defined $args && @a!=1) { - return "syntax: define RPI_1Wire |BUSMASTER"; + my @a = split("[ \t]+", $args); + if (@a!=1) { + return "syntax: define RPI_1Wire |BUSMASTER|DHT11-|DHT22-"; } + my $name = $hash->{NAME}; my $arg=$a[0]; $hash->{helper}{write}=""; + $hash->{helper}{duration}=0; my $device=""; my $family=""; my $id=""; my $dev=0; - if ($arg eq "BUSMASTER") { - $device=$arg; - $family=$arg; + if ($arg =~ /(BUSMASTER)(-\d)?$/) { + $device=$1; + $family=$1; + $id=1; + $id=abs($2) if defined $2; #abs to get rid of the "-" + if (! -e $ms_path.$id) { + readingsSingleUpdate($hash,"failreason","Device not found",0); + return "Device $device $id does not exist"; + } } elsif ($arg =~ /DHT(11|22)-(\d+)/) { return "Module RPi::DHT missing (see https://github.com/bublath/rpi-dht)" if defined $DHT_missing; $id=$2; $family="DHT".$1; $device=$family; } else { - return "Device $arg does not exist" if (! -e "$w1_path/$arg"); + return "Device $arg does not exist" if (! -e "$w1_path/$arg" and $check==1); #Only quit if coming from interactive define ($family, $id) = split('-',$arg); return "Unknown device family $family" if !defined $RPI_1Wire_Devices{$family}; $device=$RPI_1Wire_Devices{$family}{name}; @@ -142,15 +148,11 @@ sub RPI_1Wire_Init { # delete($hash->{setList}{therm_bulk_read}); RPI_1Wire_DeviceUpdate($hash); } else { - my $bulk=$hash->{bulk_read}; - if (!defined $bulk) { - $hash->{bulk_read}="off"; - $bulk="off"; - } - if (! -w "$w1_path/therm_bulk_read") { + my $bulk=ReadingsVal($name,"therm_bulk_read","off"); + if (! -w $ms_path.$id."/therm_bulk_read") { delete($hash->{setList}{therm_bulk_read}); delete($hash->{setList}{update}); - $hash->{bulk_read}="off"; + readingsSingleUpdate($hash, 'therm_bulk_read', "off",0); } elsif ($bulk eq "on") { $hash->{setList}{update}="noArg"; #Restore set command in case it was deleted previously RPI_1Wire_DeviceUpdate($hash); @@ -189,10 +191,11 @@ sub RPI_1Wire_GetDevices { my ($hash) = @_; Log3 $hash->{NAME}, 3 , $hash->{NAME}.": GetDevices"; my @devices; - if (open(my $fh, "<", "$w1_path/w1_master_slaves")) { + if (open(my $fh, "<", $ms_path.$hash->{id}."/w1_master_slaves")) { while (my $device = <$fh>) { chomp $device; #remove \n Log3 $hash->{NAME}, 4 , $hash->{NAME}.": Found device $device"; + push @devices,$device; my $found=0; foreach my $dev ( sort keys %main::defs ) { if ($defs{$dev}->{TYPE} eq "RPI_1Wire" && $defs{$dev}->{DEF} eq $device) { $found=1; } @@ -207,6 +210,7 @@ sub RPI_1Wire_GetDevices { } close($fh); } + $hash->{devices}=join(" ",@devices); return; } @@ -216,15 +220,15 @@ sub RPI_1Wire_DeviceUpdate { my $family=$hash->{family}; if (!defined $family) { #For safety, if a device was not ready during startup it sometimes is not properly initialized when being reconnected - return RPI_1Wire_Init($hash,$name." ".$hash->{TYPE}." ".$hash->{DEF}); + return RPI_1Wire_Init($hash,$hash->{DEF},0); } my $pollingInterval = AttrVal($name,"pollingInterval",60); + return if $pollingInterval<1; Log3 $name, 4 , $name.": DeviceUpdate($hash->{NAME}), pollingInterval:$pollingInterval"; -# RPI_1Wire_Poll($hash); - #Einfach "delete?" oder eventuell "kill" auf hängenden Prozess? + my $mode=AttrVal($name,"mode","nonblocking"); if ($family eq "BUSMASTER") { - if ($hash->{bulk_read} eq "on") { + if (ReadingsVal($name,"therm_bulk_read","off") eq "on") { $mode="bulk_read"; } else { return; #once set to "off" the timer won't be started again by exiting here @@ -255,7 +259,8 @@ sub RPI_1Wire_DeviceUpdate { } sub RPI_1Wire_TriggerBulk { - my $path="$w1_path/therm_bulk_read"; + my ($hash) = @_; + my $path=$ms_path.$hash->{id}."/therm_bulk_read"; if (open(my $fh, ">", $path)) { print $fh "trigger\n"; close($fh); @@ -344,10 +349,10 @@ sub RPI_1Wire_Set { RPI_1Wire_GetConfig($hash); } elsif ($cmd eq "therm_bulk_read" and @args==1) { if ($args[0] eq "on") { - $hash->{bulk_read}="on"; + readingsSingleUpdate($hash, 'therm_bulk_read', "on",1); return RPI_1Wire_DeviceUpdate($hash); } else { - $hash->{bulk_read}="off"; + readingsSingleUpdate($hash, 'therm_bulk_read', "off",1); } } return; @@ -390,9 +395,9 @@ sub RPI_1Wire_Get { my $script= "SUBSYSTEM==\"w1*\", PROGRAM=\"/bin/sh -c \'\\\n"; $script .= "chown -R root:gpio /sys/devices/w1*;\\\n"; - $script .= "chmod g+w /sys/devices/w1_bus_master1/therm_bulk_read;\\\n"; - $script .= "chmod g+w /sys/devices/w1_bus_master1/*/resolution;\\\n"; - $script .= "chmod g+w /sys/devices/w1_bus_master1/*/conv_time;\\ \'\"\n"; + $script .= "chmod g+w /sys/devices/w1_bus_master*/therm_bulk_read;\\\n"; + $script .= "chmod g+w /sys/devices/w1_bus_master*/*/resolution;\\\n"; + $script .= "chmod g+w /sys/devices/w1_bus_master*/*/conv_time;\\ \'\"\n"; return $ret.$script; } @@ -404,6 +409,7 @@ sub RPI_1Wire_GetConfig { readingsBeginUpdate($hash); my $device=$hash->{DEF}; my $fh; + my $conv=0; my $path="$w1_path/$device/resolution"; if (open($fh, "<", $path)) { my $line = <$fh>; @@ -415,9 +421,12 @@ sub RPI_1Wire_GetConfig { if (open($fh, "<", $path)) { my $line = <$fh>; chomp $line; + $conv=$line; readingsBulkUpdate($hash,"conv_time",$line); close($fh); } + if (ReadingsVal($hash->{NAME},"mode","nonblocking") eq "timer" && $conv>10) { + } readingsEndUpdate($hash,1); } @@ -542,7 +551,7 @@ sub RPI_1Wire_Poll { ################################################# my $elapsed = tv_interval ($start,[gettimeofday]); Log3 $hash->{NAME}, 4, $hash->{NAME}.": Poll for $type took $elapsed s"; - return $retval; + return $retval." duration=$elapsed"; } #get attribute "faultvalues" and return values that are contained in this space seperated list @@ -569,6 +578,9 @@ sub RPI_1Wire_FinishFn { my $decimals = AttrVal($name,"decimals",3); readingsBeginUpdate($hash); my $state=""; + if (ReadingsAge($name,"failreason",0)>300) { + readingsBulkUpdate($hash,"failreason","ok"); # Reset fail reason after 5 minutes to avoid confusion + } foreach (@ret) { my ($par,$val)=split("=",$_); @@ -578,6 +590,13 @@ sub RPI_1Wire_FinishFn { $val=sprintf( '%.'.$decimals.'f',$val*AttrVal($name,"tempFactor",1.0)+AttrVal($name,"tempOffset",0)); readingsBulkUpdate($hash,"temperature",$val); $state.="T: $val "; + } elsif ($par eq "duration") { + my $duration=ReadingsVal($name,"duration",0); + readingsBulkUpdate($hash,$par,sprintf("%.2f",$val)); + my $mode=AttrVal($name,"mode","nonblocking"); + if ($duration>0.5 and $val>0.5 and $mode ne "nonblocking") { #Only complain with 2 values in raw >0.5s + readingsBulkUpdate($hash,"failreason","Read>0.5s - nonblocking mode recommended"); + } } elsif ($par eq "error") { readingsBulkUpdate($hash,"failures",ReadingsVal($name,"failures",0)+1); readingsBulkUpdate($hash,"failreason",$val); @@ -605,6 +624,10 @@ sub RPI_1Wire_Attr { # if ($val ne "blocking" && $val ne "nonblocking" && $val ne "timer") { return "Unknown mode $val"; } + RPI_1Wire_GetConfig($hash); #Make sure the test is done with updated HW values + if ($val eq "timer" && ReadingsVal($name,"conv_time",1000)>10) { + return "Using timer mode is only recommended with reduced conv_time\nTry to adjust conv_time to 2"; + } #Restart Timer RPI_1Wire_DeviceUpdate($hash); } elsif ($attr eq "tempFactor" || $attr eq "tempOffset" || $attr eq "decimals") { @@ -667,7 +690,10 @@ For German documentation see Wiki<