# # # 09_USF1000.pm # written by Dr. Boris Neubert 2009-06-20 # e-mail: omega at online dot de # ############################################## # $Id$ package main; use strict; use warnings; my $PI= 3.141592653589793238; my $dev= "a5ce aa"; ############################# sub USF1000_Initialize($) { my ($hash) = @_; $hash->{Match} = "^81..(04|0c)..0101a001a5ceaa00...."; $hash->{DefFn} = "USF1000_Define"; $hash->{UndefFn} = "USF1000_Undef"; $hash->{ParseFn} = "USF1000_Parse"; $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:0,1 " . "model:usf1000s loglevel:0,1,2,3,4,5,6"; } ############################# sub USF1000_Define($$) { my ($hash, $def) = @_; my @a = split("[ \t][ \t]*", $def); my $u= "wrong syntax: define USF1000 geometry"; my $g= "wrong geometry for USF1000"; # geometry (units: meter) # cub length width height offset cuboid 3+4 # cylv diameter height offset vertical cylinder 3+3 # the offset is measured from the TOP of the box! return $u if(int(@a)< 6); my $name = $a[0]; my $geometry = $a[2]; if($geometry eq "cub") { # cuboid return $g if(int(@a)< 7); $hash->{GEOMETRY}= $geometry; $hash->{LENGTH}= $a[3]; $hash->{WIDTH}= $a[4]; $hash->{HEIGHT}= $a[5]; $hash->{OFFSET}= $a[6]; $hash->{CAPACITY}= int($hash->{LENGTH}*$hash->{WIDTH}*$hash->{HEIGHT}*100.0+0.5)*10.0; } elsif($geometry eq "cylv") { # vertical cylinder return $g if(int(@a)< 6); $hash->{GEOMETRY}= $geometry; $hash->{DIAMETER}= $a[3]; $hash->{HEIGHT}= $a[4]; $hash->{OFFSET}= $a[5]; $hash->{CAPACITY}= int($PI*$hash->{DIAMETER}*$hash->{DIAMETER}/4.0*$hash->{HEIGHT}*100.0+0.5)*10.0; } else { return $g; } $modules{USF1000}{defptr}{$dev} = $hash; AssignIoPort($hash); } ############################# sub USF1000_Undef($$) { my ($hash, $name) = @_; delete($modules{USF1000}{defptr}{$dev}); return undef; } ############################# sub USF1000_Parse($$) { my ($hash, $msg) = @_; # hash points to the FHZ, not to the USF1000 if(!defined($modules{USF1000}{defptr}{$dev})) { Log 3, "USF1000 Unknown device, please define it"; return "UNDEFINED USF1000 USF1000 cylv 1 1 0.5"; } my $def= $modules{USF1000}{defptr}{$dev}; my $name= $def->{NAME}; return "" if(IsIgnored($name)); my $t= TimeNow(); # Msg format: # 01 23 45 67 8901 2345 6789 01 23 45 67 # 81 0c 04 .. 0101 a001 a5ce aa 00 cc xx my $cc= substr($msg, 24, 2); my $xx= substr($msg, 26, 2); my $lowbattery= (hex($cc) & 0x40 ? 1 : 0); my $testmode= (hex($cc) & 0x80 ? 1 : 0); my $distance= hex($xx)/100.0; # in meters my $valid= (($distance>0.00) && ($distance<2.55)); if($valid) { my $wlevel = $def->{HEIGHT}-($distance-$def->{OFFSET}); # water level my $geometry= $def->{GEOMETRY}; my $capacity= $def->{CAPACITY}; # capacity of tank (for distance= offset) in liters my $volume; # current volume in tank in liters my $flevel; # fill level in percent if($geometry eq "cub") { # cuboid $volume = $def->{LENGTH}*$def->{WIDTH}*$wlevel*1000.0; } elsif($geometry eq "cylv") { # vertical cylinder $volume = $PI*$def->{DIAMETER}*$def->{DIAMETER}/4.0*$wlevel*1000.0; } else { return 0; } $flevel = int($volume/$capacity*100.0+0.5); $volume= int($volume/10.0+0.5)*10.0; if($flevel>-5) { # reflections may lead to false reading (distance too large) # the meaningless results are suppressed my $state= sprintf("v: %d V: %d", $flevel, $volume); $def->{CHANGED}[0] = $state; $def->{STATE} = $state; $def->{READINGS}{state}{TIME} = $t; $def->{READINGS}{state}{VAL} = $state; Log GetLogLevel($name, 4), "USF1000 $name: $state"; $def->{READINGS}{distance}{TIME} = $t; $def->{READINGS}{distance}{VAL} = $distance; $def->{READINGS}{level}{TIME} = $t; $def->{READINGS}{level}{VAL} = $flevel; $def->{READINGS}{volume}{TIME} = $t; $def->{READINGS}{volume}{VAL} = $volume; } } my $warnings= ($lowbattery ? "Battery low" : ""); if($testmode) { $warnings.= "; " if($warnings); $warnings.= "Test mode"; } $warnings= $warnings ? $warnings : "none"; $def->{READINGS}{"warnings"}{TIME} = $t; $def->{READINGS}{"warnings"}{VAL} = $warnings; return $name; } ############################# 1; =pod =begin html

USF1000

=end html =cut