09_USF1000.pm 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #
  2. #
  3. # 09_USF1000.pm
  4. # written by Dr. Boris Neubert 2009-06-20
  5. # e-mail: omega at online dot de
  6. #
  7. ##############################################
  8. # $Id: 09_USF1000.pm 16375 2018-03-10 15:40:02Z neubert $
  9. package main;
  10. use strict;
  11. use warnings;
  12. my $PI= 3.141592653589793238;
  13. my $dev= "a5ce aa";
  14. #############################
  15. sub
  16. USF1000_Initialize($)
  17. {
  18. my ($hash) = @_;
  19. $hash->{Match} = "^81..(04|0c)..0101a001a5ceaa00....";
  20. $hash->{DefFn} = "USF1000_Define";
  21. $hash->{UndefFn} = "USF1000_Undef";
  22. $hash->{ParseFn} = "USF1000_Parse";
  23. $hash->{AttrList} = "IODev do_not_notify:1,0 ignore:0,1 showtime:0,1 " .
  24. "model:usf1000s " . $readingFnAttributes;
  25. }
  26. #############################
  27. sub
  28. USF1000_Define($$)
  29. {
  30. my ($hash, $def) = @_;
  31. my @a = split("[ \t][ \t]*", $def);
  32. my $u= "wrong syntax: define <name> USF1000 geometry";
  33. my $g= "wrong geometry for USF1000";
  34. # geometry (units: meter)
  35. # cub length width height offset cuboid 3+4
  36. # cylv diameter height offset vertical cylinder 3+3
  37. # the offset is measured from the TOP of the box!
  38. return $u if(int(@a)< 6);
  39. my $name = $a[0];
  40. my $geometry = $a[2];
  41. if($geometry eq "cub") {
  42. # cuboid
  43. return $g if(int(@a)< 7);
  44. $hash->{GEOMETRY}= $geometry;
  45. $hash->{LENGTH}= $a[3];
  46. $hash->{WIDTH}= $a[4];
  47. $hash->{HEIGHT}= $a[5];
  48. $hash->{OFFSET}= $a[6];
  49. $hash->{CAPACITY}= int($hash->{LENGTH}*$hash->{WIDTH}*$hash->{HEIGHT}*100.0+0.5)*10.0;
  50. } elsif($geometry eq "cylv") {
  51. # vertical cylinder
  52. return $g if(int(@a)< 6);
  53. $hash->{GEOMETRY}= $geometry;
  54. $hash->{DIAMETER}= $a[3];
  55. $hash->{HEIGHT}= $a[4];
  56. $hash->{OFFSET}= $a[5];
  57. $hash->{CAPACITY}= int($PI*$hash->{DIAMETER}*$hash->{DIAMETER}/4.0*$hash->{HEIGHT}*100.0+0.5)*10.0;
  58. } else {
  59. return $g;
  60. }
  61. $modules{USF1000}{defptr}{$dev} = $hash;
  62. AssignIoPort($hash);
  63. }
  64. #############################
  65. sub
  66. USF1000_Undef($$)
  67. {
  68. my ($hash, $name) = @_;
  69. delete($modules{USF1000}{defptr}{$dev});
  70. return undef;
  71. }
  72. #############################
  73. sub
  74. USF1000_Parse($$)
  75. {
  76. my ($hash, $msg) = @_; # hash points to the FHZ, not to the USF1000
  77. if(!defined($modules{USF1000}{defptr}{$dev})) {
  78. Log3 $hash, 3, "USF1000 Unknown device, please define it";
  79. return "UNDEFINED USF1000 USF1000 cylv 1 1 0.5";
  80. }
  81. my $def= $modules{USF1000}{defptr}{$dev};
  82. my $name= $def->{NAME};
  83. return "" if(IsIgnored($name));
  84. my $t= TimeNow();
  85. # Msg format:
  86. # 01 23 45 67 8901 2345 6789 01 23 45 67
  87. # 81 0c 04 .. 0101 a001 a5ce aa 00 cc xx
  88. my $cc= substr($msg, 24, 2);
  89. my $xx= substr($msg, 26, 2);
  90. my $lowbattery= (hex($cc) & 0x40 ? 1 : 0);
  91. my $testmode= (hex($cc) & 0x80 ? 1 : 0);
  92. my $distance= hex($xx)/100.0; # in meters
  93. my $valid= (($distance>0.00) && ($distance<2.55));
  94. readingsBeginUpdate($def);
  95. if($valid) {
  96. my $wlevel = $def->{HEIGHT}-($distance-$def->{OFFSET}); # water level
  97. my $geometry= $def->{GEOMETRY};
  98. my $capacity= $def->{CAPACITY}; # capacity of tank (for distance= offset) in liters
  99. my $volume; # current volume in tank in liters
  100. my $flevel; # fill level in percent
  101. if($geometry eq "cub") {
  102. # cuboid
  103. $volume = $def->{LENGTH}*$def->{WIDTH}*$wlevel*1000.0;
  104. } elsif($geometry eq "cylv") {
  105. # vertical cylinder
  106. $volume = $PI*$def->{DIAMETER}*$def->{DIAMETER}/4.0*$wlevel*1000.0;
  107. } else {
  108. return 0;
  109. }
  110. $flevel = int($volume/$capacity*100.0+0.5);
  111. $volume= int($volume/10.0+0.5)*10.0;
  112. if($flevel>-5) {
  113. # reflections may lead to false reading (distance too large)
  114. # the meaningless results are suppressed
  115. my $state= sprintf("v: %d V: %d", $flevel, $volume);
  116. readingsBulkUpdate($def, "state", $state);
  117. readingsBulkUpdate($def, "distance", $distance);
  118. readingsBulkUpdate($def, "level", $flevel);
  119. readingsBulkUpdate($def, "volume", $volume);
  120. #Debug "USF1000 $name: $state";
  121. }
  122. }
  123. my $warnings= ($lowbattery ? "Battery low" : "");
  124. if($testmode) {
  125. $warnings.= "; " if($warnings);
  126. $warnings.= "Test mode";
  127. }
  128. $warnings= $warnings ? $warnings : "none";
  129. readingsBulkUpdate($def, "warnings", $warnings);
  130. readingsEndUpdate($def, 1);
  131. return $name;
  132. }
  133. #############################
  134. 1;
  135. =pod
  136. =item summary USF1000S ultrasonic level transmitter communicating over FHZ
  137. =item summary_DE USF1000S Ultraschall-F&uuml;llstandsmesser angebunden &uuml;ber FHZ
  138. =begin html
  139. <a name="USF1000"></a>
  140. <h3>USF1000</h3>
  141. <ul>
  142. Fhem can receive your tank's fill level from the USF1000S device
  143. through a <a href="#FHZ">FHZ</a> device, so one must be defined first.
  144. The state contains the fill level in % (lower case v in the device state)
  145. and the current volume in liters (upper case V in the device state).
  146. Measured distance to the liquid's surface, fill level, volume and warnings
  147. (Test mode, Battery low) are available. Due to the design of the USF1000S
  148. protocol, you can have only one USF1000S in range of your FHZ as these
  149. devices cannot be distinguished.<br>
  150. <br>
  151. <a name="USF1000Define"></a>
  152. <b>Define</b>
  153. <ul>
  154. <code>define &lt;name&gt; USF1000 &lt;geometry&gt;</code>
  155. <br><br>
  156. <code>&lt;geometry&gt;</code> determines the form of the tank and the
  157. position of the sensor. The following geometries are currently
  158. supported:<br><br>
  159. <ul>
  160. <li><code>cub &lt;length&gt; &lt;width&gt; &lt;height&gt; &lt;offset&gt;</code></li>
  161. <li><code>cylv &lt;diameter&gt; &lt;height&gt; &lt;offset&gt;</code></li>
  162. </ul>
  163. <br>
  164. <code>cub</code> stands for a cuboid whose base is &lt;length&gt; &times; &lt;width&gt;.
  165. <code>cylv</code> stands for a vertical cylinder whose diameter is &lt;diameter&gt;.
  166. &lt;height&gt; is the distance of the surface of the liquid from the ground
  167. if the tank is full. &lt;offset&gt; is the distance of the sensor relative to
  168. the surface of the liquid. All quantities are expressed in meters.<br>
  169. <br>
  170. Example:<br>
  171. <ul>
  172. <code>define MyTank USF1000 cylv 2 1 0.3</code>: a cylindrical water tank with
  173. 2 meters diameter. The water stands 1 meter high if the tank is full. The
  174. sensor is fixed 1,3 meters above ground.<br>
  175. </ul>
  176. </ul>
  177. <br>
  178. <a name="USF1000set"></a>
  179. <b>Set </b>
  180. <ul>
  181. N/A
  182. </ul>
  183. <br>
  184. <a name="USF1000get"></a>
  185. <b>Get</b>
  186. <ul>
  187. N/A
  188. </ul>
  189. <br>
  190. <a name="USF1000attr"></a>
  191. <b>Attributes</b>
  192. <ul>
  193. <li><a href="#IODev">IODev</a></li><br>
  194. <li><a href="#do_not_notify">do_not_notify</a></li>
  195. <li><a href="#showtime">showtime</a></li>
  196. <li><a href="#model">model</a> (usf1000s)</li>
  197. <li><a href="#ignore">ignore</a></li>
  198. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  199. </ul>
  200. <br>
  201. </ul>
  202. =end html
  203. =cut