21_OWTHERM.pm 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346
  1. ########################################################################################
  2. #
  3. # OWTHERM.pm
  4. #
  5. # FHEM module to commmunicate with 1-Wire temperature sensors DS1820, DS18S20, DS18B20, DS1822
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. #
  9. # $Id: 21_OWTHERM.pm 15339 2017-10-29 08:14:07Z phenning $
  10. #
  11. ########################################################################################
  12. #
  13. # This programm is free software; you can redistribute it and/or modify
  14. # it under the terms of the GNU General Public License as published by
  15. # the Free Software Foundation; either version 2 of the License, or
  16. # (at your option) any later version.
  17. #
  18. # The GNU General Public License can be found at
  19. # http://www.gnu.org/copyleft/gpl.html.
  20. # A copy is found in the textfile GPL.txt and important notices to the license
  21. # from the author is found in LICENSE.txt distributed with these scripts.
  22. #
  23. # This script is distributed in the hope that it will be useful,
  24. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  25. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  26. # GNU General Public License for more details.
  27. #
  28. ########################################################################################
  29. package main;
  30. use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
  31. use strict;
  32. use warnings;
  33. use Time::HiRes qw( gettimeofday );
  34. #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
  35. BEGIN {
  36. if (!grep(/FHEM\/lib$/,@INC)) {
  37. foreach my $inc (grep(/FHEM$/,@INC)) {
  38. push @INC,$inc."/lib";
  39. };
  40. };
  41. };
  42. use ProtoThreads;
  43. no warnings 'deprecated';
  44. sub Log3($$$);
  45. sub AttrVal($$$);
  46. my $owx_version="7.01";
  47. my %gets = (
  48. "id" => ":noArg",
  49. "temperature" => ":noArg",
  50. "alarm" => ":noArg",
  51. "version" => ":noArg"
  52. );
  53. my %sets = (
  54. "interval" => "",
  55. "tempHigh" => "",
  56. "tempLow" => ""
  57. );
  58. my %updates = (
  59. "present" => "",
  60. "temperature" => "",
  61. "alarm" => ""
  62. );
  63. #-- conversion times in milliseconds depend on resolution
  64. my %convtimes = (
  65. 9 => 100,
  66. 10 => 200,
  67. 11 => 400,
  68. 12 => 1000,
  69. );
  70. ########################################################################################
  71. #
  72. # The following subroutines are independent of the bus interface
  73. #
  74. # Prefix = OWTHERM
  75. #
  76. ########################################################################################
  77. #
  78. # OWTHERM_Initialize
  79. #
  80. # Parameter hash = hash of device addressed
  81. #
  82. ########################################################################################
  83. sub OWTHERM_Initialize ($) {
  84. my ($hash) = @_;
  85. $hash->{DefFn} = "OWTHERM_Define";
  86. $hash->{UndefFn} = "OWTHERM_Undef";
  87. $hash->{GetFn} = "OWTHERM_Get";
  88. $hash->{SetFn} = "OWTHERM_Set";
  89. $hash->{NotifyFn}= "OWTHERM_Notify";
  90. $hash->{InitFn} = "OWTHERM_Init";
  91. $hash->{AttrFn} = "OWTHERM_Attr";
  92. $hash->{AttrList}= "IODev model:DS1820,DS18B20,DS1822 ".
  93. "stateAL stateAH ".
  94. "tempOffset tempUnit:Celsius,Fahrenheit,Kelvin ".
  95. "tempConv:onkick,onread tempLow tempHigh ".
  96. "resolution:9,10,11,12 interval ".
  97. $readingFnAttributes;
  98. #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer
  99. main::LoadModule("OWX");
  100. }
  101. ########################################################################################
  102. #
  103. # OWTHERM_Define - Implements DefFn function
  104. #
  105. # Parameter hash = hash of device addressed, def = definition string
  106. #
  107. ########################################################################################
  108. sub OWTHERM_Define ($$) {
  109. my ($hash, $def) = @_;
  110. # define <name> OWTHERM [<model>] <id> [interval]
  111. # e.g.: define flow OWTHERM 525715020000 300
  112. my @a = split("[ \t][ \t]*", $def);
  113. my ($name,$model,$fam,$id,$crc,$interval,$ret);
  114. #-- default
  115. $name = $a[0];
  116. $interval = 300;
  117. $ret = "";
  118. #-- check syntax
  119. return "OWTHERM: Wrong syntax, must be define <name> OWTHERM [<model>] <id> [interval] or OWTHERM <fam>.<id> [interval]"
  120. if(int(@a) < 2 || int(@a) > 6);
  121. #-- different types of definition allowed
  122. my $a2 = $a[2];
  123. my $a3 = defined($a[3]) ? $a[3] : "";
  124. #-- no model, 12 characters
  125. if( $a2 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  126. $model = "DS1820";
  127. CommandAttr (undef,"$name model DS1820");
  128. $fam = "10";
  129. $id = $a[2];
  130. if(int(@a)>=4) { $interval = $a[3]; }
  131. #-- no model, 2+12 characters
  132. } elsif( $a2 =~ m/^[0-9|a-f|A-F]{2}\.[0-9|a-f|A-F]{12}$/ ) {
  133. $fam = substr($a[2],0,2);
  134. $id = substr($a[2],3);
  135. if(int(@a)>=4) { $interval = $a[3]; }
  136. if( $fam eq "10" ){
  137. $model = "DS1820";
  138. CommandAttr (undef,"$name model DS1820");
  139. }elsif( $fam eq "22" ){
  140. $model = "DS1822";
  141. CommandAttr (undef,"$name model DS1822");
  142. }elsif( $fam eq "28" ){
  143. $model = "DS18B20";
  144. CommandAttr (undef,"$name model DS18B20");
  145. }else{
  146. return "OWTHERM: Wrong 1-Wire device family $fam";
  147. }
  148. #-- model, 12 characters
  149. } elsif( $a3 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  150. $model = $a[2];
  151. $id = $a[3];
  152. if(int(@a)>=5) { $interval = $a[4]; }
  153. if( $model eq "DS1820" ){
  154. $fam = "10";
  155. CommandAttr (undef,"$name model DS1820");
  156. }elsif( $model eq "DS1822" ){
  157. $fam = "22";
  158. CommandAttr (undef,"$name model DS1822");
  159. }elsif( $model eq "DS18B20" ){
  160. $fam = "28";
  161. CommandAttr (undef,"$name model DS18B20");
  162. }else{
  163. return "OWTHERM: Wrong 1-Wire device model $model";
  164. }
  165. } else {
  166. return "OWTHERM: $a[0] ID $a[2] invalid, specify a 12 or 2.12 digit value";
  167. }
  168. #-- determine CRC Code
  169. $crc = sprintf("%02X",OWX_CRC($fam.".".$id."00"));
  170. #-- define device internals
  171. $hash->{ALARM} = 0;
  172. $hash->{OW_ID} = $id;
  173. $hash->{OW_FAMILY} = $fam;
  174. $hash->{PRESENT} = 0;
  175. $hash->{ROM_ID} = "$fam.$id.$crc";
  176. $hash->{INTERVAL} = $interval;
  177. $hash->{ERRCOUNT} = 0;
  178. #-- temperature globals - always the raw values from/for the device
  179. $hash->{owg_temp} = "";
  180. $hash->{owg_th} = "";
  181. $hash->{owg_tl} = "";
  182. #-- Couple to I/O device
  183. AssignIoPort($hash);
  184. if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
  185. return "OWTHERM: Warning, no 1-Wire I/O device found for $name.";
  186. #-- if coupled, test if ASYNC or not
  187. } else {
  188. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  189. }
  190. $modules{OWTHERM}{defptr}{$id} = $hash;
  191. #--
  192. readingsSingleUpdate($hash,"state","defined",1);
  193. Log3 $name, 3, "OWTHERM: Device $name defined.";
  194. $hash->{NOTIFYDEV} = "global";
  195. if ($init_done) {
  196. OWTHERM_Init($hash);
  197. }
  198. return undef;
  199. }
  200. #######################################################################################
  201. #
  202. # OWTHERM_Notify - Implements the Notify function
  203. #
  204. # Parameter hash = hash of device addressed
  205. # a = argument array
  206. #
  207. ########################################################################################
  208. sub OWTHERM_Notify ($$) {
  209. my ($hash,$dev) = @_;
  210. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  211. OWTHERM_Init($hash);
  212. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  213. }
  214. }
  215. #######################################################################################
  216. #
  217. # OWTHERM_Init - Implements the Init function
  218. #
  219. # Parameter hash = hash of device addressed
  220. # a = argument array
  221. #
  222. ########################################################################################
  223. sub OWTHERM_Init ($) {
  224. my ($hash)=@_;
  225. #-- Start timer for updates
  226. RemoveInternalTimer($hash);
  227. InternalTimer(gettimeofday()+10, "OWTHERM_GetValues", $hash, 0);
  228. return undef;
  229. }
  230. #######################################################################################
  231. #
  232. # OWTHERM_Attr - Set one attribute value for device
  233. #
  234. # Parameter hash = hash of device addressed
  235. # a = argument array
  236. #
  237. ########################################################################################
  238. sub OWTHERM_Attr(@) {
  239. my ($do,$name,$key,$value) = @_;
  240. my $hash = $defs{$name};
  241. my $ret;
  242. if ( $do eq "set") {
  243. ARGUMENT_HANDLER: {
  244. #-- interval modified at runtime
  245. $key eq "interval" and do {
  246. #-- check value
  247. return "OWTHERM: set $name interval must be >=0" if(int($value) < 0);
  248. #-- update timer
  249. $hash->{INTERVAL} = int($value);
  250. if ($init_done) {
  251. RemoveInternalTimer($hash);
  252. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWTHERM_GetValues", $hash, 0);
  253. }
  254. last;
  255. };
  256. #-- resolution modified at runtime
  257. $key eq "resolution" and do {
  258. $hash->{owg_cf} = $value;
  259. last;
  260. };
  261. #-- alarm settings modified at runtime
  262. $key =~ m/(.*)(Low|High)/ and do {
  263. #-- safeguard against uninitialized devices
  264. return undef
  265. if( $hash->{READINGS}{"state"}{VAL} eq "defined" );
  266. $ret = OWTHERM_Set($hash,($name,$key,$value));
  267. last;
  268. };
  269. $key eq "IODev" and do {
  270. AssignIoPort($hash,$value);
  271. if( defined($hash->{IODev}) ) {
  272. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  273. if ($init_done) {
  274. OWTHERM_Init($hash);
  275. }
  276. }
  277. last;
  278. };
  279. }
  280. }
  281. return $ret;
  282. }
  283. ########################################################################################
  284. #
  285. # OWTHERM_FormatValues - put together various format strings
  286. #
  287. # Parameter hash = hash of device addressed, fs = format string
  288. #
  289. ########################################################################################
  290. sub OWTHERM_FormatValues($) {
  291. my ($hash) = @_;
  292. my $name = $hash->{NAME};
  293. my $interface = $hash->{IODev}->{TYPE};
  294. my ($unit,$offset,$factor,$abbr,$vval,$vlow,$vhigh,$statef,$stateal,$stateah);
  295. my $svalue = "";
  296. #-- attributes defined ?
  297. $stateal = AttrVal($name,"stateAL","↓");
  298. $stateah = AttrVal($name,"stateAH","↑");
  299. $unit = AttrVal($name,"tempUnit","Celsius");
  300. $offset = AttrVal($name,"tempOffset",0.0);
  301. $factor = 1.0;
  302. if( $unit eq "none" ){
  303. $abbr = "";
  304. }elsif( $unit eq "Celsius" ){
  305. $abbr = " °C";
  306. } elsif ($unit eq "Kelvin" ){
  307. $abbr = " K";
  308. $offset += "273.16"
  309. } elsif ($unit eq "Fahrenheit" ){
  310. $abbr = " °F";
  311. $offset = ($offset+32)/1.8;
  312. $factor = 1.8;
  313. } else {
  314. $abbr=" ?";
  315. Log3 $name, 3, "OWTHERM_FormatValues: Unknown temperature unit $unit";
  316. }
  317. #-- these values are rather complex to obtain, therefore save them in the hash
  318. $hash->{READINGS}{"temperature"}{UNIT} = $abbr;
  319. $hash->{tempf}{offset} = $offset;
  320. $hash->{tempf}{factor} = $factor;
  321. #-- no change in any value if invalid reading
  322. return if( $hash->{owg_temp} eq "");
  323. #-- correct values for proper offset, factor
  324. $vval = ($hash->{owg_temp} + $offset)*$factor;
  325. $vlow = floor(($hash->{owg_tl} + $offset)*$factor+0.5);
  326. $vhigh = floor(($hash->{owg_th} + $offset)*$factor+0.5);
  327. $main::attr{$name}{"tempLow"} = $vlow;
  328. $main::attr{$name}{"tempHigh"} = $vhigh;
  329. #-- formats for output
  330. $statef = "T: %5.2f".$abbr;
  331. $svalue = sprintf($statef,$vval);
  332. #-- Test for alarm condition
  333. $hash->{ALARM} = 1;
  334. if( ($vval <= $vlow) && ( $vval >= $vhigh ) ){
  335. $svalue .= " ".$stateal.$stateah;
  336. }elsif( $vval <= $vlow ){
  337. $svalue .= " ".$stateal;
  338. }elsif( $vval >= $vhigh ){
  339. $svalue .= " ".$stateah;
  340. } else {
  341. $hash->{ALARM} = 0;
  342. }
  343. main::OWX_Alarms($hash->{IODev})
  344. if( $hash->{ALARM} );
  345. #-- put into READINGS
  346. readingsBeginUpdate($hash);
  347. readingsBulkUpdate($hash,"temperature",$vval);
  348. #-- STATE
  349. readingsBulkUpdate($hash,"state",$svalue);
  350. readingsEndUpdate($hash,1);
  351. return $svalue;
  352. }
  353. ########################################################################################
  354. #
  355. # OWTHERM_Get - Implements GetFn function
  356. #
  357. # Parameter hash = hash of device addressed, a = argument array
  358. #
  359. ########################################################################################
  360. sub OWTHERM_Get($@) {
  361. my ($hash, @a) = @_;
  362. my $reading = $a[1];
  363. my $name = $hash->{NAME};
  364. my $model = $hash->{OW_MODEL};
  365. my $value = undef;
  366. my $ret = "";
  367. #-- check syntax
  368. return "OWTHERM: Get argument is missing @a"
  369. if(int(@a) != 2);
  370. #-- check argument
  371. my $msg = "OWTHERM: Get with unknown argument $a[1], choose one of ";
  372. $msg .= "$_$gets{$_} " foreach (keys%gets);
  373. return $msg
  374. if(!defined($gets{$a[1]}));
  375. #-- get id
  376. if($a[1] eq "id") {
  377. $value = $hash->{ROM_ID};
  378. return "$name.id => $value";
  379. }
  380. #-- hash of the busmaster
  381. my $master = $hash->{IODev};
  382. #-- Get other values according to interface type
  383. my $interface= $hash->{IODev}->{TYPE};
  384. #-- get version
  385. if( $a[1] eq "version") {
  386. return "$name.version => $owx_version";
  387. }
  388. #-- OWX interface
  389. if( $interface eq "OWX" ){
  390. $ret = OWXTHERM_GetValues($hash);
  391. #-- OWX_ASYNC interface
  392. }elsif( $interface eq "OWX_ASYNC" ){
  393. eval {
  394. $ret = OWX_ASYNC_RunToCompletion($hash,OWXTHERM_PT_GetValues($hash));
  395. };
  396. $ret = GP_Catch($@) if $@;
  397. #-- OWFS interface
  398. }elsif( $interface eq "OWServer" ){
  399. $ret = OWFSTHERM_GetValues($hash);
  400. #-- Unknown interface
  401. }else{
  402. return "OWTHERM: Get with wrong IODev type $interface";
  403. }
  404. #-- process results
  405. if( $master->{ASYNCHRONOUS} ){
  406. #return "OWTHERM: $name getting values, please wait for completion";
  407. return undef;
  408. }else{
  409. #-- when we have a return code, we have an error
  410. if( defined($ret) ){
  411. return "OWTHERM: Could not get values from device $name, return was $ret";
  412. }
  413. #-- return the special reading
  414. if ($reading eq "temperature") {
  415. return "OWTHERM: $name.temperature => ".
  416. $hash->{READINGS}{"temperature"}{VAL};
  417. } elsif ($reading eq "alarm") {
  418. return "OWTHERM: $name.alarm => L ".$main::attr{$name}{"tempLow"}.
  419. " H ".$main::attr{$name}{"tempHigh"};
  420. } else {
  421. return undef;
  422. }
  423. }
  424. }
  425. #######################################################################################
  426. #
  427. # OWTHERM_GetValues - Updates the readings from device
  428. #
  429. # Parameter hash = hash of device addressed
  430. #
  431. ########################################################################################
  432. sub OWTHERM_GetValues($@) {
  433. my $hash = shift;
  434. my $name = $hash->{NAME};
  435. my $value = "";
  436. my $ret;
  437. #-- check if device needs to be initialized
  438. if( $hash->{READINGS}{"state"}{VAL} eq "defined"){
  439. OWTHERM_InitializeDevice($hash);
  440. OWTHERM_FormatValues($hash);
  441. }
  442. RemoveInternalTimer($hash);
  443. #-- auto-update for device disabled;
  444. return undef
  445. if( $hash->{INTERVAL} == 0 );
  446. #-- restart timer for updates
  447. InternalTimer(time()+$hash->{INTERVAL}, "OWTHERM_GetValues", $hash, 0);
  448. #-- Get values according to interface type
  449. my $interface= $hash->{IODev}->{TYPE};
  450. if( $interface eq "OWX" ){
  451. $ret = OWXTHERM_GetValues($hash);
  452. }elsif( $interface eq "OWX_ASYNC" ){
  453. #-- skip, if the conversion is driven by master
  454. unless ( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
  455. eval {
  456. OWX_ASYNC_Schedule( $hash, OWXTHERM_PT_GetValues($hash) );
  457. };
  458. $ret = GP_Catch($@) if $@;
  459. }
  460. }elsif( $interface eq "OWServer" ){
  461. $ret = OWFSTHERM_GetValues($hash);
  462. }else{
  463. Log3 $name, 3, "OWTHERM: GetValues with wrong IODev type $interface";
  464. return 1;
  465. }
  466. #-- process results
  467. if( defined($ret) ){
  468. return "OWTHERM: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret";
  469. }
  470. return undef;
  471. }
  472. ########################################################################################
  473. #
  474. # OWTHERM_InitializeDevice - delayed setting of initial readings
  475. #
  476. # Parameter hash = hash of device addressed
  477. #
  478. ########################################################################################
  479. sub OWTHERM_InitializeDevice($) {
  480. my ($hash) = @_;
  481. my $name = $hash->{NAME};
  482. my $master = $hash->{IODev};
  483. my $interface = $master->{TYPE};
  484. my @a = ($name,"",0);
  485. my ($unit,$offset,$factor,$abbr,$value,$ret);
  486. #-- attributes defined ?
  487. $unit = AttrVal($name,"tempUnit","Celsius");
  488. $offset = AttrVal($name,"tempOffset",0.0);
  489. $factor = 1.0;
  490. if( $unit eq "Celsius" ){
  491. $abbr = "°C";
  492. } elsif ($unit eq "Kelvin" ){
  493. $abbr = "K";
  494. $offset += "273.16"
  495. } elsif ($unit eq "Fahrenheit" ){
  496. $abbr = "°F";
  497. $offset = ($offset+32)/1.8;
  498. $factor = 1.8;
  499. } else {
  500. $abbr="?";
  501. Log3 $name, 3, "OWTHERM_InitializeDevice: unknown unit $unit";
  502. }
  503. #-- these values are rather complex to obtain, therefore save them in the hash
  504. $hash->{READINGS}{"temperature"}{TYPE} = "temperature";
  505. $hash->{READINGS}{"temperature"}{UNIT} = $abbr;
  506. $hash->{ERRCOUNT} = 0;
  507. $hash->{tempf}{offset} = $offset;
  508. $hash->{tempf}{factor} = $factor;
  509. #-- Check if temperature conversion is consistent
  510. if( $interface =~ /^OWX/ ){
  511. if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
  512. if( !(defined($hash->{IODev}->{dokick})) ||
  513. ( defined($hash->{IODev}->{dokick}) && ($hash->{IODev}->{dokick} ne "1") )){
  514. Log3 $name, 1,"OWTHERM: Attribute tempConv=onkick changed to onread for $name because interface is not kicking";
  515. $attr{$name}{tempConv}="onread";
  516. }
  517. }
  518. }elsif( $interface eq "OWServer" ){
  519. if( !(defined($attr{$name}{tempConv})) ||
  520. (defined($attr{$name}{tempConv}) && ($attr{$name}{tempConv} eq "onread") ) ){
  521. Log3 $name, 1,"OWTHERM: Attribute tempConv=onread changed to onkick for $name because interface is OWFS";
  522. $attr{$name}{tempConv}="onread";
  523. }
  524. }
  525. my $args = {};
  526. #-- Set the attribute values if defined
  527. if ( defined($attr{$name}{resolution}) ) {
  528. $args->{resolution} = $attr{$name}{resolution};
  529. }
  530. if( defined($attr{$name}{"tempLow"}) ){
  531. $args->{tempLow} = floor($attr{$name}{"tempLow"}/$factor-$offset+0.5);
  532. }
  533. if( defined($attr{$name}{"tempHigh"}) ){
  534. $args->{tempHigh} = floor($attr{$name}{"tempHigh"}/$factor-$offset+0.5);
  535. }
  536. #-- put into device
  537. #-- OWX interface
  538. if( $interface eq "OWX" ){
  539. $ret = OWXTHERM_SetValues($hash,$args);
  540. }elsif( $interface eq "OWX_ASYNC" ){
  541. eval {
  542. $ret = OWX_ASYNC_RunToCompletion($hash,OWXTHERM_PT_SetValues($hash,$args));
  543. };
  544. $ret = GP_Catch($@) if $@;
  545. #-- OWFS interface
  546. }elsif( $interface eq "OWServer" ){
  547. $ret = OWFSTHERM_SetValues($hash,$args);
  548. }
  549. #-- process results
  550. if( defined($ret) ){
  551. return "OWTHERM: Could not initialize device $name, reason: ".$ret;
  552. }
  553. #-- Set state to initialized
  554. readingsSingleUpdate($hash,"state","initialized",1);
  555. return undef;
  556. }
  557. #######################################################################################
  558. #
  559. # OWTHERM_Set - Set one value for device
  560. #
  561. # Parameter hash = hash of device addressed
  562. # a = argument string
  563. #
  564. ########################################################################################
  565. sub OWTHERM_Set($@) {
  566. my ($hash, @a) = @_;
  567. #-- for the selector: which values are possible
  568. return join(" ", sort keys %sets) if(@a == 2);
  569. #-- check syntax
  570. return "OWTHERM: Set needs one parameter"
  571. if(int(@a) != 3);
  572. #-- check argument
  573. return "OWTHERM: Set with unknown argument $a[1], choose one of ".join(",", sort keys %sets)
  574. if(!defined($sets{$a[1]}));
  575. #-- define vars
  576. my $key = $a[1];
  577. my $value = $a[2];
  578. my $ret = undef;
  579. my $name = $hash->{NAME};
  580. my $model = $hash->{OW_MODEL};
  581. #-- set new timer interval
  582. if($key eq "interval") {
  583. # check value
  584. return "OWTHERM: set $name interval must be >= 0"
  585. if(int($value) < 0);
  586. $hash->{INTERVAL} = int($value);
  587. RemoveInternalTimer($hash);
  588. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWTHERM_GetValues", $hash, 0);
  589. }
  590. #-- set tempLow or tempHigh
  591. if( (lc($key) eq "templow") || (lc($key) eq "temphigh")) {
  592. my $interface = $hash->{IODev}->{TYPE};
  593. my $offset = defined($hash->{tempf}{offset}) ? $hash->{tempf}{offset} : 0.0;
  594. my $factor = defined($hash->{tempf}{factor}) ? $hash->{tempf}{factor} : 1.0;
  595. #-- Only integer values are allowed
  596. $value = floor($value+0.5);
  597. #-- First we have to read the current data, because alarms may not be set independently
  598. $hash->{owg_tl} = floor($main::attr{$name}{"tempLow"}/$factor-$offset+0.5);
  599. $hash->{owg_th} = floor($main::attr{$name}{"tempHigh"}/$factor-$offset+0.5);
  600. #-- find upper and lower boundaries for given offset/factor
  601. my $mmin = floor((-55+$offset)*$factor+0.5);
  602. my $mmax = floor((125+$offset)*$factor+0.5);
  603. return sprintf("OWTHERM: Set with wrong value $value for $key, range is [%3.1f,%3.1f]",$mmin,$mmax)
  604. if($value < $mmin || $value > $mmax);
  605. #-- seems to be ok, correcting for offset and factor
  606. my $args = {
  607. $key => floor($value/$factor-$offset+0.5),
  608. };
  609. #-- put into attribute value
  610. if( lc($key) eq "templow" ){
  611. if( $main::attr{$name}{"tempLow"} != $value ){
  612. $main::attr{$name}{"tempLow"} = $value;
  613. }
  614. }
  615. if( lc($key) eq "temphigh" ){
  616. if( $main::attr{$name}{"tempHigh"} != $value ){
  617. $main::attr{$name}{"tempHigh"} = $value;
  618. }
  619. }
  620. #-- put into device
  621. #-- OWX interface
  622. if( $interface eq "OWX" ){
  623. $ret = OWXTHERM_SetValues($hash,$args);
  624. }elsif( $interface eq "OWX_ASYNC" ){
  625. $args->{format} = 1;
  626. eval {
  627. OWX_ASYNC_Schedule( $hash, OWXTHERM_PT_SetValues($hash,$args) );
  628. };
  629. $ret = GP_Catch($@) if $@;
  630. #-- OWFS interface
  631. }elsif( $interface eq "OWServer" ){
  632. $ret = OWFSTHERM_SetValues($hash,$args);
  633. } else {
  634. return "OWTHERM: Set with wrong IODev type $interface";
  635. }
  636. #-- process results
  637. if( defined($ret) ){
  638. return "OWTHERM: Could not set device $name, reason: ".$ret;
  639. }
  640. }
  641. #-- process results
  642. $hash->{PRESENT} = 1;
  643. #OWTHERM_FormatValues($hash);
  644. Log3 $name, 4, "OWTHERM: Set $hash->{NAME} $key $value";
  645. return undef;
  646. }
  647. ########################################################################################
  648. #
  649. # OWTHERM_Undef - Implements UndefFn function
  650. #
  651. # Parameter hash = hash of device addressed
  652. #
  653. ########################################################################################
  654. sub OWTHERM_Undef ($) {
  655. my ($hash) = @_;
  656. delete($modules{OWTHERM}{defptr}{$hash->{OW_ID}});
  657. RemoveInternalTimer($hash);
  658. return undef;
  659. }
  660. ########################################################################################
  661. #
  662. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  663. # via OWFS
  664. #
  665. # Prefix = OWFSTHERM
  666. #
  667. ########################################################################################
  668. #
  669. # OWFSTHERM_GetValues - Get values from device
  670. #
  671. # Parameter hash = hash of device addressed
  672. #
  673. ########################################################################################
  674. sub OWFSTHERM_GetValues($) {
  675. my ($hash) = @_;
  676. #-- ID of the device
  677. my $owx_add = substr($hash->{ROM_ID},0,15);
  678. #-- hash of the busmaster
  679. my $master = $hash->{IODev};
  680. my $name = $hash->{NAME};
  681. #-- reset presence
  682. $hash->{PRESENT} = 0;
  683. #-- resolution (set by Attribute 'resolution' on OWFS)
  684. my $resolution = defined $hash->{owg_cf} ? $hash->{owg_cf} : "";
  685. #-- get values - or should we rather get the uncached ones ?
  686. $hash->{owg_temp} = OWServer_Read($master,"/$owx_add/temperature$resolution");
  687. my $ow_thn = OWServer_Read($master,"/$owx_add/temphigh");
  688. my $ow_tln = OWServer_Read($master,"/$owx_add/templow");
  689. return "no return from OWServer"
  690. if( (!defined($hash->{owg_temp})) || (!defined($ow_thn)) || (!defined($ow_tln)) );
  691. return "empty return from OWServer"
  692. if( ($hash->{owg_temp} eq "") || ($ow_thn eq "") || ($ow_tln eq "") );
  693. #-- process alarm settings
  694. $hash->{owg_tl} = $ow_tln;
  695. $hash->{owg_th} = $ow_thn;
  696. #-- and now from raw to formatted values
  697. $hash->{PRESENT} = 1;
  698. my $value = OWTHERM_FormatValues($hash);
  699. Log3 $name, 5, $value;
  700. return undef;
  701. }
  702. ########################################################################################
  703. #
  704. # OWFSTHERM_SetValues - Set values in device
  705. #
  706. # Parameter hash = hash of device addressed
  707. #
  708. ########################################################################################
  709. sub OWFSTHERM_SetValues($$) {
  710. my ($hash,$args) = @_;
  711. #-- ID of the device
  712. my $owx_add = substr($hash->{ROM_ID},0,15);
  713. #-- hash of the busmaster
  714. my $master = $hash->{IODev};
  715. my $name = $hash->{NAME};
  716. #-- $owg_tl and $owg_th are preset and may be changed here
  717. foreach my $key (keys %$args) {
  718. my $value = $args->{$key};
  719. next unless (defined $value and $value ne "");
  720. if( lc($key) eq "templow") {
  721. $hash->{owg_tl} = $value;
  722. } elsif( lc($key) eq "temphigh") {
  723. $hash->{owg_th} = $value;
  724. } elsif( lc($key) eq "resolution") {
  725. $hash->{owg_cf} = $value;
  726. next;
  727. } else {
  728. next;
  729. }
  730. OWServer_Write($master, "/$owx_add/".lc($key),$value);
  731. }
  732. return undef
  733. }
  734. ########################################################################################
  735. #
  736. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  737. # directly to the FHEM server
  738. #
  739. # Prefix = OWXTHERM
  740. #
  741. ########################################################################################
  742. #
  743. # OWXTHERM_BinValues - Process reading from one device - translate binary into raw
  744. #
  745. # Parameter hash = hash of device addressed
  746. # context = mode for evaluating the binary data
  747. # proc = processing instruction, also passed to OWX_Read.
  748. # bitwise interpretation !!
  749. # if 0, nothing special
  750. # if 1 = bit 0, a reset will be performed not only before, but also after
  751. # the last operation in OWX_Read
  752. # if 2 = bit 1, the initial reset of the bus will be suppressed
  753. # if 8 = bit 3, the fillup of the data with 0xff will be suppressed
  754. # if 16= bit 4, the insertion will be at the top of the queue
  755. # owx_dev = ROM ID of slave device
  756. # crcpart = part of the data that needs to be part of the CRC check
  757. # numread = number of bytes to receive
  758. # res = result string
  759. #
  760. #
  761. ########################################################################################
  762. sub OWXTHERM_BinValues($$$$$$$) {
  763. my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_;
  764. #-- hash of the busmaster
  765. my $master = $hash->{IODev};
  766. my $name = $hash->{NAME};
  767. my ($i,$j,$k,@data,$ow_thn,$ow_tln);
  768. my $error = 0;
  769. my $change = 0;
  770. my $msg;
  771. OWX_WDBGL($name,5,"OWXTHERM_BinValues called for device $name in context $context with data ",$res);
  772. #-- we have to get rid of the first 10 bytes
  773. if( length($res) == 19 ){
  774. $res=substr($res,10);
  775. }
  776. @data=split(//,$res);
  777. #-- process results
  778. if (@data != 9){
  779. $error = 1;
  780. $msg = "$name: invalid data length, ".int(@data)." instead of 9 bytes, ";
  781. }elsif(ord($data[7])<=0){
  782. $error = 1;
  783. $msg = "$name: invalid data, ";
  784. }elsif(OWX_CRC8(substr($res,0,8),$data[8])==0){
  785. $error = 1;
  786. $msg = "$name: invalid CRC, ";
  787. }else{
  788. $msg = "$name: no error, ";
  789. }
  790. #-- this must be different for the different device types
  791. # family = 10 => DS1820, DS18S20
  792. if( $hash->{OW_FAMILY} eq "10" ) {
  793. my $count_remain = ord($data[6]);
  794. my $count_perc = ord($data[7]);
  795. my $delta = ($count_perc != 0)?(-0.25 + ($count_perc - $count_remain)/$count_perc):0;
  796. my $lsb = ord($data[0]);
  797. my $msb = 0;
  798. my $sign = ord($data[1]) & 255;
  799. #-- test with -25 degrees
  800. #$lsb = 12*16+14;
  801. #$sign = 1;
  802. #$delta = 0;
  803. #-- 2's complement form = signed bytes
  804. $hash->{owg_temp} = int($lsb/2) + $delta;
  805. if( $sign !=0 ){
  806. $hash->{owg_temp} = -128+$hash->{owg_temp};
  807. }
  808. $ow_thn = ord($data[2]) > 127 ? 128-ord($data[2]) : ord($data[2]);
  809. $ow_tln = ord($data[3]) > 127 ? 128-ord($data[3]) : ord($data[3]);
  810. } elsif ( ($hash->{OW_FAMILY} eq "22") || ($hash->{OW_FAMILY} eq "28") ) {
  811. my $lsb = ord($data[0]);
  812. my $msb = ord($data[1]) & 7;
  813. my $sign = ord($data[1]) & 248;
  814. #-- test with -55 degrees
  815. #$lsb = 9*16;
  816. #$sign = 1;
  817. #$msb = 7;
  818. #-- 2's complement form = signed bytes
  819. $hash->{owg_temp} = $msb*16+ $lsb/16;
  820. if( $sign !=0 ){
  821. $hash->{owg_temp} = -128+$hash->{owg_temp};
  822. }
  823. $ow_thn = ord($data[2]) > 127 ? 128-ord($data[2]) : ord($data[2]);
  824. $ow_tln = ord($data[3]) > 127 ? 128-ord($data[3]) : ord($data[3]);
  825. }
  826. #-- process alarm settings
  827. $hash->{owg_tl} = $ow_tln;
  828. $hash->{owg_th} = $ow_thn;
  829. OWX_WDBGL($name,5-4*$error,"OWXTHERM_BinValues: ".$msg." ".$hash->{owg_temp}." ",$res);
  830. #-- and now from raw to formatted values
  831. if( $error ){
  832. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  833. }else{
  834. $hash->{PRESENT} = 1;
  835. OWTHERM_FormatValues($hash);
  836. }
  837. return undef;
  838. }
  839. ########################################################################################
  840. #
  841. # OWXTHERM_GetValues - Trigger reading from one device
  842. #
  843. # Parameter hash = hash of device addressed
  844. #
  845. ########################################################################################
  846. sub OWXTHERM_GetValues($) {
  847. my ($hash) = @_;
  848. #-- For default, perform the conversion now
  849. my $con=1;
  850. #-- ID of the device
  851. my $owx_dev = $hash->{ROM_ID};
  852. #-- hash of the busmaster
  853. my $master = $hash->{IODev};
  854. my $name = $hash->{NAME};
  855. my $res;
  856. #-- check, if the conversion has been called before for all sensors
  857. if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
  858. $con=0;
  859. }
  860. #-- if the conversion has not been called before
  861. #-- issue the match ROM command \x55 and the start conversion command \x44
  862. #-- conversion needs some 950 ms - but we may also do it in shorter time !
  863. if( $con==1 ){
  864. #-- OLD OWX interface
  865. if( !$master->{ASYNCHRONOUS} ){
  866. OWX_Reset($master);
  867. if( OWX_Complex($master,$owx_dev,"\x44",0) eq 0 ){
  868. return "OWTHERM: $name not accessible";
  869. }
  870. select(undef,undef,undef,$convtimes{AttrVal($name,"resolution",12)}*0.001);
  871. #-- NEW OWX interface
  872. }else{
  873. #### master slave context proc owx_dev data crcpart numread startread callback delay
  874. OWX_Qomplex($master, $hash, "convert", 5, $owx_dev, "\x44", 0, 1, undef, undef, $convtimes{AttrVal($name,"resolution",12)}*0.001 );
  875. }
  876. }
  877. #-- NOW ask the specific device
  878. #-- issue the match ROM command \x55 and the read scratchpad command \xBE
  879. #-- reading 9 + 1 + 8 data bytes and 1 CRC byte = 19 bytes
  880. #-- OLD OWX interface
  881. if( !$master->{ASYNCHRONOUS} ){
  882. OWX_Reset($master);
  883. my $res=OWX_Complex($master,$owx_dev,"\xBE",9);
  884. return "OWTHERM: $name not accessible in reading"
  885. if( $res eq 0 );
  886. Log 1,"OWTHERM: $name has returned invalid data of length ".length($res)
  887. if( length($res)!=19);
  888. return OWXTHERM_BinValues($hash,"getsp",$owx_dev,undef,undef,9,substr($res,10,9));
  889. #-- NEW OWX interface
  890. }else{
  891. #### master slave context proc owx_dev data crcpart numread startread callback delay
  892. OWX_Qomplex($master, $hash, "readsp", 1, $owx_dev, "\xBE", 0, 19, 0, \&OWXTHERM_BinValues, undef);
  893. return undef;
  894. }
  895. }
  896. #######################################################################################
  897. #
  898. # OWXTHERM_SetValues - Implements SetFn function
  899. #
  900. # Parameter hash = hash of device addressed
  901. # a = argument array
  902. #
  903. ########################################################################################
  904. sub OWXTHERM_SetValues($$) {
  905. my ($hash, $args) = @_;
  906. my $name = $hash->{NAME};
  907. #-- ID of the device
  908. my $owx_dev = $hash->{ROM_ID};
  909. #-- hash of the busmaster
  910. my $master = $hash->{IODev};
  911. return undef unless (defined $args->{resolution} or defined $args->{tempLow} or defined $args->{tempHigh});
  912. #-- $owg_tl and $owg_th are preset and may be changed here
  913. foreach my $key (keys %$args) {
  914. $hash->{owg_tl} = $args->{$key} if( lc($key) eq "templow");
  915. $hash->{owg_th} = $args->{$key} if( lc($key) eq "temphigh");
  916. $hash->{owg_cf} = $args->{$key} if( lc($key) eq "resolution");
  917. }
  918. #-- put into 2's complement formed (signed byte)
  919. my $tlp = $hash->{owg_tl} < 0 ? 128 - $hash->{owg_tl} : $hash->{owg_tl};
  920. my $thp = $hash->{owg_th} < 0 ? 128 - $hash->{owg_th} : $hash->{owg_th};
  921. #-- resolution is defined in bits 5+6 of configuration register
  922. my $cfg = defined $hash->{owg_cf} ? (($hash->{owg_cf}-9) << 5) | 0x1f : 0x7f;
  923. #-- issue the match ROM command \x55 and the write scratchpad command \x4E,
  924. # followed by 3 bytes of data (alarm_temp_high, alarm_temp_low, config)
  925. # config-byte of 0x7F means 12 bit resolution (750ms convert time)
  926. #
  927. # so far writing the EEPROM does not work properly.
  928. # 1. \x48 directly appended to the write scratchpad command => command ok, no effect on EEPROM
  929. # 2. \x48 appended to match ROM => command not ok.
  930. # 3. \x48 sent by WriteBytePower after match ROM => command ok, no effect on EEPROM
  931. my $select=sprintf("\x4E%c%c%c",$thp,$tlp,$cfg);
  932. #-- OLD OWX interface
  933. if( !$master->{ASYNCHRONOUS} ){
  934. OWX_Reset($master);
  935. my $res=OWX_Complex($master,$owx_dev,$select,3);
  936. if( $res eq 0 ){
  937. return "OWTHERM: $name not accessible for setting";
  938. }
  939. #-- NEW OWX interface
  940. }else{
  941. #### master slave context proc owx_dev data crcpart numread startread callback delay
  942. OWX_Qomplex($master, $hash, "writesp", 0, $owx_dev, $select, 0, 3, 10, undef, undef);
  943. }
  944. return undef;
  945. }
  946. ########################################################################################
  947. #
  948. # OWXTHERM_GetValues - Trigger reading from one device
  949. #
  950. # Parameter hash = hash of device addressed
  951. #
  952. ########################################################################################
  953. sub OWXTHERM_PT_GetValues($) {
  954. my ($hash) = @_;
  955. return PT_THREAD(sub {
  956. my ($thread) = @_;
  957. #-- For default, perform the conversion now
  958. my $con=1;
  959. #-- ID of the device
  960. my $owx_dev = $hash->{ROM_ID};
  961. #-- hash of the busmaster
  962. my $master = $hash->{IODev};
  963. my $name = $hash->{NAME};
  964. PT_BEGIN($thread);
  965. #-- check, if the conversion has been called before for all sensors
  966. if( defined($attr{$name}{tempConv}) && ( $attr{$name}{tempConv} eq "onkick") ){
  967. $con=0;
  968. }
  969. #-- if the conversion has not been called before
  970. if( $con==1 ){
  971. #-- issue the match ROM command \x55 and the start conversion command \x44
  972. my $now = gettimeofday();
  973. my $delay = $convtimes{AttrVal($name,"resolution",12)};
  974. $thread->{ExecuteTime} = $now + $delay*0.001;
  975. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\x44",0);
  976. PT_WAIT_THREAD($thread->{pt_execute});
  977. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  978. PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
  979. delete $thread->{ExecuteTime};
  980. }
  981. #-- NOW ask the specific device
  982. #-- issue the match ROM command \x55 and the read scratchpad command \xBE
  983. #-- reading 9 + 1 + 8 data bytes and 1 CRC byte = 19 bytes
  984. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xBE",9);
  985. PT_WAIT_THREAD($thread->{pt_execute});
  986. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  987. OWXTHERM_BinValues($hash,undef,1,$owx_dev,undef,9,$thread->{pt_execute}->PT_RETVAL());
  988. PT_END;
  989. });
  990. }
  991. #######################################################################################
  992. #
  993. # OWXTHERM_PT_SetValues - Implements SetFn function async
  994. #
  995. # Parameter hash = hash of device addressed
  996. # a = argument array
  997. #
  998. ########################################################################################
  999. sub OWXTHERM_PT_SetValues($$) {
  1000. my ($hash,$args) = @_;
  1001. return PT_THREAD( sub {
  1002. my ($thread) = @_;
  1003. my ($i,$j,$k);
  1004. my $name = $hash->{NAME};
  1005. #-- ID of the device
  1006. my $owx_dev = $hash->{ROM_ID};
  1007. #-- hash of the busmaster
  1008. my $master = $hash->{IODev};
  1009. PT_BEGIN($thread);
  1010. unless (defined $args->{resolution} or defined $args->{tempLow} or defined $args->{tempHigh}) {
  1011. PT_EXIT;
  1012. }
  1013. #-- $owg_tl and $owg_th are preset and may be changed here
  1014. foreach my $key (keys %$args) {
  1015. $hash->{owg_tl} = $args->{$key} if( lc($key) eq "templow");
  1016. $hash->{owg_th} = $args->{$key} if( lc($key) eq "temphigh");
  1017. $hash->{owg_cf} = $args->{$key} if( lc($key) eq "resolution");
  1018. }
  1019. #-- put into 2's complement formed (signed byte)
  1020. my $tlp = $hash->{owg_tl} < 0 ? 128 - $hash->{owg_tl} : $hash->{owg_tl};
  1021. my $thp = $hash->{owg_th} < 0 ? 128 - $hash->{owg_th} : $hash->{owg_th};
  1022. #-- resolution is defined in bits 5+6 of configuration register
  1023. my $cfg = defined $hash->{owg_cf} ? (($hash->{owg_cf}-9) << 5) | 0x1f : 0x7f;
  1024. #-- issue the match ROM command \x55 and the write scratchpad command \x4E,
  1025. # followed by 3 bytes of data (alarm_temp_high, alarm_temp_low, config)
  1026. # config-byte of 0x7F means 12 bit resolution (750ms convert time)
  1027. #
  1028. # so far writing the EEPROM does not work properly.
  1029. # 1. \x48 directly appended to the write scratchpad command => command ok, no effect on EEPROM
  1030. # 2. \x48 appended to match ROM => command not ok.
  1031. # 3. \x48 sent by WriteBytePower after match ROM => command ok, no effect on EEPROM
  1032. my $select=sprintf("\x4E%c%c%c",$thp,$tlp,$cfg);
  1033. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select,3);
  1034. PT_WAIT_THREAD($thread->{pt_execute});
  1035. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1036. #-- process results
  1037. $hash->{PRESENT} = 1;
  1038. if ($args->{format}) {
  1039. OWTHERM_FormatValues($hash);
  1040. }
  1041. PT_END;
  1042. });
  1043. }
  1044. 1;
  1045. =pod
  1046. =item device
  1047. =item summary to control 1-Wire temperature sensors DS1820, DS18S20, DS18B20, DS1822
  1048. =begin html
  1049. <a name="OWTHERM"></a>
  1050. <h3>OWTHERM</h3>
  1051. <p>FHEM module to commmunicate with 1-Wire bus digital thermometer devices<br />
  1052. <br />This 1-Wire module works with the OWX interface module or with the OWServer interface module
  1053. (prerequisite: Add this module's name to the list of clients in OWServer).
  1054. Please define an <a href="#OWX">OWX</a> device or <a href="#OWServer">OWServer</a> device first. <br />
  1055. </p>
  1056. <h4>Example</h4>
  1057. <p>
  1058. <code>define OWX_T OWTHERM DS18B20 E8D09B030000 300</code>
  1059. <br />
  1060. <code>attr OWX_T tempUnit Kelvin</code>
  1061. <br />
  1062. </p><br />
  1063. <a name="OWTHERMdefine"></a>
  1064. <h4>Define</h4>
  1065. <p>
  1066. <code>define &lt;name&gt; OWTHERM [&lt;model&gt;] &lt;id&gt; [&lt;interval&gt;]</code> or <br/>
  1067. <code>define &lt;name&gt; OWTHERM &lt;fam&gt;.&lt;id&gt; [&lt;interval&gt;]</code>
  1068. <br /><br /> Define a 1-Wire digital thermometer device.</p>
  1069. <ul>
  1070. <li>
  1071. <code>[&lt;model&gt;]</code><br /> Defines the thermometer model (and thus 1-Wire family
  1072. id) currently the following values are permitted: </p>
  1073. <ul>
  1074. <li>model DS1820 with family id 10 (default if the model parameter is omitted)</li>
  1075. <li>model DS1822 with family id 22</li>
  1076. <li>model DS18B20 with family id 28</li>
  1077. </ul>
  1078. </li>
  1079. <li>
  1080. <code>&lt;fam&gt;</code>
  1081. <br />2-character unique family id, see above </li>
  1082. <li>
  1083. <code>&lt;id&gt;</code>
  1084. <br />12-character unique ROM id of the thermometer device without family id and CRC
  1085. code
  1086. </li>
  1087. <li>
  1088. <code>&lt;interval&gt;</code>
  1089. <br /> Temperature measurement interval in seconds. The default is 300 seconds.
  1090. </li>
  1091. </ul>
  1092. <a name="OWTHERMset"></a>
  1093. <h4>Set</h4>
  1094. <ul>
  1095. <li><a name="owtherm_interval">
  1096. <code>set &lt;name&gt; interval &lt;int&gt;</code></a><br /> Temperature
  1097. readout interval in seconds. The default is 300 seconds, a value of 0 disables the automatic update. <b>Attention:</b>This is the
  1098. readout interval. Whether an actual temperature measurement is performed, is determined by the
  1099. tempConv attribute </li>
  1100. <li><a name="owtherm_tempHigh">
  1101. <code>set &lt;name&gt; tempHigh &lt;float&gt;</code></a>
  1102. <br /> The high alarm temperature (on the temperature scale chosen by the attribute
  1103. value) </li>
  1104. <li><a name="owtherm_tempLow">
  1105. <code>set &lt;name&gt; tempLow &lt;float&gt;</code></a>
  1106. <br /> The low alarm temperature (on the temperature scale chosen by the attribute
  1107. value) </li>
  1108. </ul>
  1109. <br />
  1110. <a name="OWTHERMget"></a>
  1111. <h4>Get</h4>
  1112. <ul>
  1113. <li><a name="owtherm_id">
  1114. <code>get &lt;name&gt; id</code></a>
  1115. <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
  1116. <li><a name="owtherm_temperature">
  1117. <code>get &lt;name&gt; temperature</code></a><br />Obtain the temperature. </li>
  1118. <li><a name="owtherm_alarm">
  1119. <code>get &lt;name&gt; alarm</code></a><br />Obtain the alarm temperature
  1120. values. </li>
  1121. </ul>
  1122. <br />
  1123. <a name="OWTHERMattr"></a>
  1124. <h4>Attributes</h4>
  1125. <ul>
  1126. <li><a name="owtherm_stateAL"><code>attr &lt;name&gt; stateAL &lt;string&gt;</code>
  1127. </a>
  1128. <br />character string for denoting low alarm condition, default is ↓</li>
  1129. <li><a name="owtherm_stateAH"><code>attr &lt;name&gt; stateAH &lt;string&gt;</code>
  1130. </a>
  1131. <br />character string for denoting high alarm condition, default is ↑</li>
  1132. <li><a name="owtherm_tempConv">
  1133. <code>attr &lt;name&gt; tempConv onkick|onread</code>
  1134. </a>
  1135. <br /> determines, whether a temperature measurement will happen when "kicked"
  1136. through the OWX backend module (all temperature sensors at the same time), or on
  1137. reading the sensor (1 second waiting time, default). </li>
  1138. <li><a name="owtherm_tempOffset"><code>attr &lt;name&gt; tempOffset &lt;float&gt;</code>
  1139. </a>
  1140. <br />temperature offset in °C added to the raw temperature reading. </li>
  1141. <li><a name="owtherm_tempUnit"><code>attr &lt;name&gt; tempUnit
  1142. none|Celsius|Kelvin|Fahrenheit</code>
  1143. </a>
  1144. <br />unit of measurement (temperature scale) for state reading (default is Celsius = °C, use "none" for empty).</li>
  1145. <li><a name="owtherm_resolution">
  1146. <code>attr &lt;name&gt; resolution 9|10|11|12</code></a><br /> Temperature
  1147. resolution in bit, only relevant for DS18B20 </li>
  1148. <li><a name="owtherm_interval2">
  1149. <code>attr &lt;name&gt; interval &lt;int&gt;</code></a><br /> Temperature
  1150. readout interval in seconds. The default is 300 seconds. <b>Attention:</b>This is the
  1151. readout interval. Whether an actual temperature measurement is performed, is determined by the
  1152. tempConv attribute </li>
  1153. <li><a name="owtherm_tempHigh2">
  1154. <code>attr &lt;name&gt; tempHigh &lt;float&gt;</code>
  1155. </a>
  1156. <br /> high alarm temperature (on the temperature scale chosen by the attribute
  1157. value). </li>
  1158. <li><a name="owtherm_tempLow2">
  1159. <code>attr &lt;name&gt; tempLow &lt;float&gt;</code>
  1160. </a>
  1161. <br /> low alarm temperature (on the temperature scale chosen by the attribute
  1162. value). </li>
  1163. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1164. </ul>
  1165. =end html
  1166. =cut