From f9a61bbd1def55a28622cf1a1dbb9db1879d67af Mon Sep 17 00:00:00 2001 From: Adimarantis <> Date: Wed, 27 Oct 2021 14:37:05 +0000 Subject: [PATCH] 58_RPI_1Wire: Replaces 58_GPIO4 for Raspberry PI 1Wire support git-svn-id: https://svn.fhem.de/fhem/trunk@25131 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/58_RPI_1Wire.pm | 789 ++++++++++++++++++++++ fhem/MAINTAINER.txt | 1 + fhem/contrib/{ => deprecated}/58_GPIO4.pm | 3 + 4 files changed, 794 insertions(+) create mode 100755 fhem/FHEM/58_RPI_1Wire.pm rename fhem/contrib/{ => deprecated}/58_GPIO4.pm (99%) diff --git a/fhem/CHANGED b/fhem/CHANGED index 68689c71a..d34b2a1b4 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. + - new: 58_RPI_1Wire: Raspberry Pi 1Wire interface replacing 58_GPIO4 - change: 73_AutoShuttersControl: change names of CommandTemplate variables, change commadref for CommandTemplate - feature: 73_AutoShuttersControl: add user control commands, expan diff --git a/fhem/FHEM/58_RPI_1Wire.pm b/fhem/FHEM/58_RPI_1Wire.pm new file mode 100755 index 000000000..bf81f3296 --- /dev/null +++ b/fhem/FHEM/58_RPI_1Wire.pm @@ -0,0 +1,789 @@ +#$Id$ +#Based on GPIO4 by Peter J. Flathmann (peter dot flathmann at web dot de) +#and various extension to the GPIO4 Module by members of the FHEM forum +#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; +use strict; +use warnings; +#use Data::Dumper; +use Time::HiRes qw ( gettimeofday tv_interval ); +use Scalar::Util qw(looks_like_number); +#use vars qw{%attr %defs}; +eval "use RPi::DHT;1" or my $DHT_missing = "yes"; + +sub RPI_1Wire_Initialize { + my ($hash) = @_; + + $hash->{DefFn} = "RPI_1Wire_Define"; + $hash->{FW_detailFn} = "RPI_1Wire_Detail"; + $hash->{FW_deviceOverview} = 1; + $hash->{AttrFn} = "RPI_1Wire_Attr"; + $hash->{UndefFn} = "RPI_1Wire_Undef"; + $hash->{NotifyFn} = "RPI_1Wire_Notify"; + $hash->{GetFn} = "RPI_1Wire_Get"; + $hash->{SetFn} = "RPI_1Wire_Set"; + $hash->{AttrList} = "tempOffset tempFactor pollingInterval ". + "mode:blocking,nonblocking,timer ". + "faultvalues ". + "decimals:0,1,2,3 ". + "$readingFnAttributes"; +} + +my $w1_path="/sys/devices/w1_bus_master1"; +my $dht_path="/sys/devices/platform/dht11@"; + +my %RPI_1Wire_Devices = +( + '10' => {"name"=>"DS18S20", "type"=>"temperature", "path"=>"w1_slave"}, + '12' => {"name"=>"DS2406", "type"=>"switch", "path"=>"state"}, # Not supported by old module + '19' => {"name"=>"DS28E17", "type"=>"i2c bridge"}, + '1c' => {"name"=>"DS28E04", "type"=>"eeprom"}, + '1d' => {"name"=>"DS2423", "type"=>"counter", "path"=>"w1_slave"}, + '26' => {"name"=>"DS2438", "type"=>"voltage", "path"=>"temperature,vdd,vad"}, + '28' => {"name"=>"DS18B20", "type"=>"temperature", "path"=>"w1_slave"}, + '29' => {"name"=>"DS2408", "type"=>"8p-switch", "path"=>"output"}, + '3a' => {"name"=>"DS2413", "type"=>"2p-switch", "path"=>"state"}, # not supported by old module + '3b' => {"name"=>"DS1825", "type"=>"temperature", "path"=>"w1_slave"}, + '42' => {"name"=>"DS28EA00", "type"=>"temperature", "path"=>"w1_slave"}, + 'DHT11' => {"name"=>"DHT11", "type"=>"dht", "path"=>"11"}, + 'DHT22' => {"name"=>"DHT22", "type"=>"dht", "path"=>"22"}, + 'BUSMASTER' => {"name"=>"BUSMASTER", "type"=>"BUSMASTER", "path"=>""} +); + +sub RPI_1Wire_Notify { + my ($own_hash, $dev_hash) = @_; + my $ownName = $own_hash->{NAME}; # own name / hash + return "" if(IsDisabled($ownName)); # Return without any further action if the module is disabled + + my $devName = $dev_hash->{NAME}; # Device that created the events +# Log3 $ownName, 1, $ownName." Notify from $devName"; + my $events = deviceEvents($dev_hash,1); + if ($devName eq "global" and grep(m/^INITIALIZED|REREADCFG$/, @{$events})) { + 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); + } +} + +sub RPI_1Wire_Define { # + my ($hash, $def) = @_; + Log3 $hash->{NAME}, 2, $hash->{NAME}." Define: $def"; + $hash->{setList} = { + "update" => "noArg", + "scan" => "noArg", + "precision" => "9,10,11,12", + "conv_time" => "textField", + "therm_bulk_read" => "on,off", + }; + $hash->{getList}= { + "udev" => "noArg", + }; + + $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}); + return $ret if $ret; + } + return; +} +################################### +sub RPI_1Wire_Init { # + my ( $hash, $args ) = @_; + Log3 $hash->{NAME}, 2, $hash->{NAME}.": Init: $args"; + 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 $arg=$a[0]; + $hash->{helper}{write}=""; + my $device=""; + my $family=""; + my $id=""; + my $dev=0; + if ($arg eq "BUSMASTER") { + $device=$arg; + $family=$arg; + } 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"); + ($family, $id) = split('-',$arg); + return "Unknown device family $family" if !defined $RPI_1Wire_Devices{$family}; + $device=$RPI_1Wire_Devices{$family}{name}; + } + $hash->{id}=$id; + $hash->{model}=$device; #for statistics + $hash->{family}=$family; + my $type=$RPI_1Wire_Devices{$family}{type}; + + #remove set commands that make no sense + if ($device ne "BUSMASTER") { + delete($hash->{setList}{scan}); + 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") { + delete($hash->{setList}{therm_bulk_read}); + delete($hash->{setList}{update}); + $hash->{bulk_read}="off"; + } elsif ($bulk eq "on") { + $hash->{setList}{update}="noArg"; #Restore set command in case it was deleted previously + RPI_1Wire_DeviceUpdate($hash); + } + } + if ($type ne "temperature") { + delete($hash->{setList}{precision}); + delete($hash->{setList}{conv_time}); + } else { + if (!(-w "$w1_path/$arg/conv_time")) { + delete($hash->{setList}{conv_time}); + $hash->{helper}{write}.="conv_time "; + } + if (!(-w "$w1_path/$arg/resolution")) { + delete($hash->{setList}{precision}); + $hash->{helper}{write}.="resolution "; + } + } + RPI_1Wire_Set($hash, $name, "setfromreading"); + #Restore previous settings + my $precision=ReadingsVal($name,"temperature",undef); + my $conv_time=ReadingsVal($name,"conv_time",undef); + if (defined $precision) { + RPI_1Wire_SetPrecision($hash,$precision); + } + if (defined $conv_time) { + RPI_1Wire_SetConversion($hash,$conv_time); + } + RPI_1Wire_GetConfig($hash); + $hash->{STATE} = "Initialized"; + Log3 $hash->{NAME}, 3, $hash->{NAME}.": Init done for $device $family $id $type"; + return; +} + +sub RPI_1Wire_GetDevices { + my ($hash) = @_; + Log3 $hash->{NAME}, 3 , $hash->{NAME}.": GetDevices"; + my @devices; + if (open(my $fh, "<", "$w1_path/w1_master_slaves")) { + while (my $device = <$fh>) { + chomp $device; #remove \n + Log3 $hash->{NAME}, 4 , $hash->{NAME}.": Found device $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; } + } + if ($found == 0) { + my ($family, $id) = split('-',$device); + if (defined $RPI_1Wire_Devices{$family}) { #only autocreate for known devices + Log3 $hash->{NAME}, 4 , $hash->{NAME}.": Autocreate $device"; + DoTrigger("global", "UNDEFINED ".$RPI_1Wire_Devices{$family}{name}."_$id RPI_1Wire $device"); #autocreate + } + } + } + close($fh); + } + return; +} + +sub RPI_1Wire_DeviceUpdate { + my ($hash) = @_; + my $name=$hash->{NAME}; + 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}); + } + my $pollingInterval = AttrVal($name,"pollingInterval",60); + 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") { + $mode="bulk_read"; + } else { + return; #once set to "off" the timer won't be started again by exiting here + } + } + if ($mode eq "nonblocking") { + delete($hash->{helper}{RUNNING_PID}) if(exists($hash->{helper}{RUNNING_PID})); + $hash->{helper}{RUNNING_PID} = BlockingCall("RPI_1Wire_Poll", $hash,"RPI_1Wire_FinishFn"); + Log3 $name, 5, $name.": BlockingCall for $name"; + } elsif ($mode eq "blocking") { + my $ret=RPI_1Wire_Poll($hash); + RPI_1Wire_FinishFn($ret); + } elsif ($mode eq "timer") { + #In case of "hack" using minimal conv_time, trigger conversion twice + my $ret=RPI_1Wire_Poll($hash); + #RPI_1Wire_FinishFn($ret); First result can be ignored + RemoveInternalTimer($hash); + #Table of reasonable conv_times? + InternalTimer(gettimeofday()+1.5, "RPI_1Wire_FromTimer", $hash, 0); + return; + } elsif ($mode eq "bulk_read") { + $hash->{helper}{RUNNING_PID} = BlockingCall("RPI_1Wire_TriggerBulk", $hash,undef); + Log3 $hash->{NAME}, 3, $hash->{NAME}.": Triggered bulk read"; + } + RemoveInternalTimer($hash); + InternalTimer(gettimeofday()+$pollingInterval, "RPI_1Wire_DeviceUpdate", $hash, 0); + return; +} + +sub RPI_1Wire_TriggerBulk { + my $path="$w1_path/therm_bulk_read"; + if (open(my $fh, ">", $path)) { + print $fh "trigger\n"; + close($fh); + } +} + +sub RPI_1Wire_FromTimer { + my ($hash) = @_; + my $name=$hash->{NAME}; + my $ret=RPI_1Wire_Poll($hash); + #Second call is where we read the "real" value + RPI_1Wire_FinishFn($ret); + RemoveInternalTimer($hash); + my $pollingInterval = AttrVal($name,"pollingInterval",60); + InternalTimer(gettimeofday()+$pollingInterval, "RPI_1Wire_DeviceUpdate", $hash, 0); +} + +sub RPI_1Wire_SetPrecision { + my ( $hash, $precision)= @_; + my $fh; + if (!looks_like_number($precision) || $precision < 9 || $precision>12) { + return "Precision needs to be a number between 9 and 12"; + } + my $path="$w1_path/$hash->{DEF}/resolution"; + if (open($fh, ">", $path)) { + print $fh $precision; + close($fh); + } else { + return "Error writing to $w1_path/$hash->{DEF}/resolution"; + } + return; +} + +sub RPI_1Wire_SetConversion { + my ( $hash, $conv_time)= @_; + my $fh; + my $path="$w1_path/$hash->{DEF}/conv_time"; + if (open($fh, ">", $path)) { + print $fh $conv_time; + close($fh); + } else { + return "Error writing to $w1_path/$hash->{DEF}/conv_time"; + } + return; +} + +sub RPI_1Wire_Set { + + my ( $hash, $name, @args ) = @_; + return unless defined $hash->{setList}; + my %sets=%{$hash->{setList}}; + ### Check Args + my $numberOfArgs = int(@args); + return "RPI_1Wire_Set: No cmd specified for set" if ( $numberOfArgs < 1 ); + my $device=$hash->{DEF}; + + my $cmd = shift @args; + if (!exists($sets{$cmd})) { + my @cList; + foreach my $k (keys %sets) { + my $opts = undef; + $opts = $sets{$k}; + + if (defined($opts)) { + push(@cList,$k . ':' . $opts); + } else { + push (@cList,$k); + } + } + return "RPI_1Wire_Set: Unknown argument $cmd, choose one of " . join(" ", @cList); + } # error unknown cmd handling + + if ($cmd eq "precision" and @args==1) { + my $ret=RPI_1Wire_SetPrecision($hash,$args[0]); + return $ret if defined $ret; + RPI_1Wire_GetConfig($hash); + } elsif ($cmd eq "scan") { + RPI_1Wire_GetDevices($hash); + return; + } elsif ($cmd eq "update") { + RPI_1Wire_GetConfig($hash); + return RPI_1Wire_DeviceUpdate($hash); + } elsif ($cmd eq "conv_time" and @args==1) { + my $ret=RPI_1Wire_SetConversion($hash,$args[0]); + return $ret if defined $ret; + RPI_1Wire_GetConfig($hash); + } elsif ($cmd eq "therm_bulk_read" and @args==1) { + if ($args[0] eq "on") { + $hash->{bulk_read}="on"; + return RPI_1Wire_DeviceUpdate($hash); + } else { + $hash->{bulk_read}="off"; + } + } + return; +} + +sub RPI_1Wire_Get { + my ($hash, $name, @args) = @_; + return unless defined $hash->{getList}; + my $family=$hash->{family}; + return unless defined $family; + my $type=$RPI_1Wire_Devices{$family}{type}; + return unless $type eq "temperature"; + return unless $hash->{helper}{write} ne ""; + my %gets=%{$hash->{getList}}; + my $numberOfArgs = int(@args); + return "RPI_1Wire_Get: No cmd specified for get" if ( $numberOfArgs < 1 ); + + my $cmd = shift @args; + + if (!exists($gets{$cmd})) { + my @cList; + foreach my $k (keys %gets) { + my $opts = undef; + $opts = $gets{$k}; + + if (defined($opts)) { + push(@cList,$k . ':' . $opts); + } else { + push (@cList,$k); + } + } + return "RPI_1Wire_Get: Unknown argument $cmd, choose one of " . join(" ", @cList); + } # error unknown cmd handling + + if ($cmd eq "udev") { + my $ret= "In order to be able to use some functionality , write access to certain devices is required\n"; + $ret.= "Recommended way is to create a udev script\n\n"; + $ret.= "Create a text file 99-w1.rules with the content below and copy it to /etc/udev/rules.d/\n"; + $ret.= "You also need to make sure your fhem user is in the gpio group\n\n"; + + 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"; + + return $ret.$script; + } + return; +} + +sub RPI_1Wire_GetConfig { + my ($hash) = @_; + readingsBeginUpdate($hash); + my $device=$hash->{DEF}; + my $fh; + my $path="$w1_path/$device/resolution"; + if (open($fh, "<", $path)) { + my $line = <$fh>; + chomp $line; + readingsBulkUpdate($hash,"precision",$line); + close($fh); + } + $path="$w1_path/$device/conv_time"; + if (open($fh, "<", $path)) { + my $line = <$fh>; + chomp $line; + readingsBulkUpdate($hash,"conv_time",$line); + close($fh); + } + readingsEndUpdate($hash,1); +} + +sub RPI_1Wire_Poll { + my $start = [gettimeofday]; + my ($hash) = @_; + my $device=$hash->{DEF}; + my $family=$hash->{family}; + my $type=$RPI_1Wire_Devices{$family}{type}; + my @path=split(",",$RPI_1Wire_Devices{$family}{path}); + my $id=$hash->{id}; + my $name=$hash->{NAME}; + my $temperature; + my $humidity; + my @counter; + + return if ($device eq "BUSMASTER"); + + my $retval=$name; + my $file=""; + my @data; + foreach (@path) { + $file="$w1_path/$device/$_"; + if ($family =~ /DHT(11|22)/) { + my $env = RPi::DHT->new($id,$1,1); + Log3 $name, 4 , $name.": Using RPi::DHT for $id DHT-$1"; + @data=$env->read(); + last; + } + Log3 $name, 5 , $name.": Open $file"; + my $fh; + my $count=0; + my $loopcount=0; + while ($count==0 && $loopcount<3){ + if (!open($fh, "<", $file)) { + Log3 $name, 2 , $name.": Error opening $file"; + return "$retval error=open_device"; + } + while (my $line = <$fh>) { + chomp($line); #Issue with binary? + push @data, $line; + $count++; + Log3 $name, 5 , $name.": Read $line"; + } + close ($fh); + $loopcount++; + } + if ($count == 0) { + Log3 $name, 2 , $name.": No data found in $file"; + return "$retval error=empty_data"; + } + } + + if ($type =~ /temperature/) { + if ($data[0] =~ /crc.*YES/) { + $data[1] =~ /t=(-?\d+)/; + my $temp = $1/1000.0; + $temp -= 4096 if($temp > 1000); + $retval .= " temperature=$temp"; + } else { + $retval .= " error=crc"; + } + } + + #Special handling for Robue Clone - is anyone using that? + #Running throught the standard branch DS18B20 branch should still work for Robue, right? So we just overwrite any previous temperature or error + if ($type eq "temperature" and $data[0] =~ /crc.*YES/ and substr($device, 6, 6) eq "544853") { + my @owarray = split(" ", $data[0]); + $retval.=" temperature=".(hex($owarray[1]) * 256 + hex($owarray[0]))/10.0; + $retval.=" humidity=".(hex($owarray[3]) * 256 + hex($owarray[2]))/10.0; + $retval.=" value=".hex($owarray[5]) * 256 + hex($owarray[4]); + $retval.=" error=".hex($owarray[7]) if $owarray[7] ne "00"; #Is 00 no error? + } + + if ($type =~ /dht/) { + #Getting data from this sensor is very unreliable. In case it fails (undefined) use the previous value so "state" is always looking ok + if (defined $data[0]) { + $retval.=" temperature=".$data[0]; + $retval.=" humidity=".$data[1]; + } else { + $retval.=" error=crc"; + } + } + + if ($type =~ /voltage/) { + $retval .= " temperature=".$data[0]/256; + $retval .= " vdd=".$data[1]/100; + $retval .= " vad=".$data[2]/100; + } + if ($type =~ /counter/) { + if (defined $data[2] && $data[2] =~ /c=(-?\d+)/) { + $retval .= " counter.A=".$1; + } else { + $retval .= " error=crc"; + } + if (defined $data[3] && $data[3] =~ /c=(-?\d+)/) { + $retval .= " counter.B=".$1; + } else { + $retval .= " error=crc"; + } + } + + ##################### UNTESTED #################### + if ($type =~ /switch/) { + my $pins=unpack("c",$data[0]); # Binary bits + my $data_bin=sprintf("%008b", $pins); + my @pio=split("",$data_bin); + if ($type eq "8p-switch") { + my $pin=7; + foreach (@pio) { + $retval.=" pio".$pin."=".$_; + } + } else { + $retval.= " pioa=".$pio[0]; + if ($type eq "2p-switch") { + $retval.= " piob=".$pio[2]; + } else { + $retval.= " piob=".$pio[1]; + } + } + } + ################################################# + my $elapsed = tv_interval ($start,[gettimeofday]); + Log3 $hash->{NAME}, 4, $hash->{NAME}.": Poll for $type took $elapsed s"; + return $retval; +} + +#get attribute "faultvalues" and return values that are contained in this space seperated list +#temperature apply factor and offset +sub RPI_1Wire_CheckFaultvalues { + my ($hash, $val) = @_; + my @faultvalues = split(" ",AttrVal($hash->{NAME},"faultvalues","")); + for (my $i=0; $i < @faultvalues; $i++) { + if($val == $faultvalues[$i]) { + Log3 $hash->{NAME}, 2, $hash->{NAME}.": Ignoring faultvalue $val"; + return; + } + } + return $val; +} + +sub RPI_1Wire_FinishFn { + my ($string) = @_; + return unless(defined($string)); + my @ret=split(" ",$string); + my $name = shift @ret; + Log3 $name, 5, $name.": Finish: $string"; + my $hash = $defs{$name}; + my $decimals = AttrVal($name,"decimals",3); + readingsBeginUpdate($hash); + my $state=""; + foreach (@ret) { + my ($par,$val)=split("=",$_); + + $val=RPI_1Wire_CheckFaultvalues($hash,$val); + next if !defined $val; + if ($par eq "temperature") { + $val=sprintf( '%.'.$decimals.'f',$val*AttrVal($name,"tempFactor",1.0)+AttrVal($name,"tempOffset",0)); + readingsBulkUpdate($hash,"temperature",$val); + $state.="T: $val "; + } elsif ($par eq "error") { + readingsBulkUpdate($hash,"failures",ReadingsVal($name,"failures",0)+1); + readingsBulkUpdate($hash,"failreason",$val); + } else { + readingsBulkUpdate($hash,$par,$val); + $state.="$par:$val "; + } + } + readingsBulkUpdate($hash,"state",$state) unless $state eq ""; #Don't update state if nothing to update + readingsEndUpdate($hash,1); +} + +sub RPI_1Wire_Attr { # + my ($command, $name, $attr, $val) = @_; + my $hash = $defs{$name}; + return if !defined $val; #nothing to do when deleting an attribute + Log3 $hash->{NAME}, 5, $hash->{NAME}.": Attr $attr=$val"; + if($attr eq "pollingInterval") { + if (!looks_like_number($val) || $val < 0) { + return "pollingInterval has to be a positive number or zero"; + } + #Restart Timer + RPI_1Wire_DeviceUpdate($hash); + } elsif ($attr eq "mode") { + if ($val ne "blocking" && $val ne "nonblocking" && $val ne "timer") { + return "Unknown mode $val"; + } + #Restart Timer + RPI_1Wire_DeviceUpdate($hash); + } elsif ($attr eq "tempFactor" || $attr eq "tempOffset" || $attr eq "decimals") { + if (!looks_like_number($val)) { + return "$attr needs to be numeric"; + } + } + return; +} + +sub RPI_1Wire_Undef { + my ($hash) = @_; + Log 4, "GPIO4: RPI_1Wire_Undef($hash->{NAME})"; + BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID})); + RemoveInternalTimer($hash); + return; +} + +sub RPI_1Wire_Detail { + my ($FW_wname, $name, $room, $pageHash) = @_; + my $hash=$defs{$name}; + my $ret = ""; + if ($hash->{helper}{write} ne "") { + return "Some commands are not available due to missing write permissions to files in $w1_path:
$hash->{helper}{write}
See get udev for help how to resolved this.
"; + } + return; +} + +1; + +=pod +=item device +=item summary Interface for various 1-Wire devices +=item summary_DE Interface für verschiedene 1-Wire Geräte + +=begin html + +

RPI_1Wire

+ +For German documentation see Wiki + +
+ Define + + + + Set + + + + Get + + + + Attributes + + + Readings + +
+ +=end html +=cut diff --git a/fhem/MAINTAINER.txt b/fhem/MAINTAINER.txt index 5124ff181..b2893b3ca 100644 --- a/fhem/MAINTAINER.txt +++ b/fhem/MAINTAINER.txt @@ -305,6 +305,7 @@ FHEM/57_Calendar.pm neubert Unterstützende Dienste/Kalend FHEM/57_CALVIEW.pm chris1284 Unterstützende Dienste/Kalendermodule FHEM/57_SSCal.pm DS_Starter Unterstützende Dienste/Kalendermodule FHEM/58_HVAC_DaikinAC.pm roelb Heizungssteuerung/Raumklima (preferably in English and a copy as PM) +FHEM/58_RPI_1Wire.pm Adimarantis Einplatinencomputer https://forum.fhem.de/index.php/topic,123499.0.html FHEM/59_HCS.pm hjr Automatisierung (oder auch PM) FHEM/59_LuftdatenInfo igami Bastelecke FHEM/59_OPENWEATHER.pm tupol Unterstützende Dienste/Wettermodule (Link als PM an tupol) diff --git a/fhem/contrib/58_GPIO4.pm b/fhem/contrib/deprecated/58_GPIO4.pm similarity index 99% rename from fhem/contrib/58_GPIO4.pm rename to fhem/contrib/deprecated/58_GPIO4.pm index 171459efd..a21a2cc0a 100644 --- a/fhem/contrib/58_GPIO4.pm +++ b/fhem/contrib/deprecated/58_GPIO4.pm @@ -1,3 +1,6 @@ +#Module deprecated +#Please use 58_RPI_1Wire +# ############################################################################# # # $Id$