21_OWVAR.pm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950
  1. ########################################################################################
  2. #
  3. # OWVAR.pm
  4. #
  5. # FHEM module to commmunicate with 1-Wire variable resistor DS2890
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. #
  9. # $Id: 21_OWVAR.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.0";
  47. my $owg_channel = "";
  48. my %gets = (
  49. "id" => ":noArg",
  50. "value" => ":noArg",
  51. "version" => ":noArg"
  52. );
  53. my %sets = (
  54. "value" => ""
  55. );
  56. my %updates = (
  57. "value" => ""
  58. );
  59. ########################################################################################
  60. #
  61. # The following subroutines are independent of the bus interface
  62. #
  63. # Prefix = OWVAR
  64. #
  65. ########################################################################################
  66. #
  67. # OWVAR_Initialize
  68. #
  69. # Parameter hash = hash of device addressed
  70. #
  71. ########################################################################################
  72. sub OWVAR_Initialize ($) {
  73. my ($hash) = @_;
  74. $hash->{DefFn} = "OWVAR_Define";
  75. $hash->{UndefFn} = "OWVAR_Undef";
  76. $hash->{GetFn} = "OWVAR_Get";
  77. $hash->{SetFn} = "OWVAR_Set";
  78. $hash->{NotifyFn}= "OWVAR_Notify";
  79. $hash->{InitFn} = "OWVAR_Init";
  80. $hash->{AttrFn} = "OWVAR_Attr";
  81. $hash->{AttrList}= "IODev model:DS2890 ".
  82. "Name Function Unit ".
  83. $readingFnAttributes;
  84. #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer
  85. main::LoadModule("OWX");
  86. }
  87. ########################################################################################
  88. #
  89. # OWVAR_Define - Implements DefFn function
  90. #
  91. # Parameter hash = hash of device addressed, def = definition string
  92. #
  93. ########################################################################################
  94. sub OWVAR_Define ($$) {
  95. my ($hash, $def) = @_;
  96. # define <name> OWVAR [<model>] <id>
  97. # e.g.: define flow OWVAR 525715020000
  98. my @a = split("[ \t][ \t]*", $def);
  99. my ($name,$model,$fam,$id,$crc,$ret);
  100. #-- default
  101. $name = $a[0];
  102. $ret = "";
  103. #-- check syntax
  104. return "OWVAR: Wrong syntax, must be define <name> OWVAR [<model>] <id> or OWVAR <fam>.<id> "
  105. if(int(@a) < 2 || int(@a) > 5);
  106. #-- different types of definition allowed
  107. my $a2 = $a[2];
  108. my $a3 = defined($a[3]) ? $a[3] : "";
  109. #-- no model, 12 characters
  110. if( $a2 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  111. $model = "DS2890";
  112. CommandAttr (undef,"$name model DS2890");
  113. $fam = "10";
  114. $id = $a[2];
  115. #-- no model, 2+12 characters
  116. } elsif( $a2 =~ m/^[0-9|a-f|A-F]{2}\.[0-9|a-f|A-F]{12}$/ ) {
  117. $fam = substr($a[2],0,2);
  118. $id = substr($a[2],3);
  119. if( $fam eq "2C" ){
  120. $model = "DS2890";
  121. CommandAttr (undef,"$name model DS2890");
  122. }else{
  123. return "OWVAR: Wrong 1-Wire device family $fam";
  124. }
  125. #-- model, 12 characters
  126. } elsif( $a3 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  127. $model = $a[2];
  128. $id = $a[3];
  129. if( $model eq "DS2890" ){
  130. $fam = "2C";
  131. CommandAttr (undef,"$name model DS2890");
  132. }else{
  133. return "OWVAR: Wrong 1-Wire device model $model";
  134. }
  135. } else {
  136. return "OWVAR: $a[0] ID $a[2] invalid, specify a 12 or 2.12 digit value";
  137. }
  138. #-- determine CRC Code
  139. $crc = sprintf("%02X",OWX_CRC($fam.".".$id."00"));
  140. #-- define device internals
  141. $hash->{OW_ID} = $id;
  142. $hash->{OW_FAMILY} = $fam;
  143. $hash->{PRESENT} = 0;
  144. $hash->{ROM_ID} = "$fam.$id.$crc";
  145. #-- value globals - always the raw values from/for the device
  146. $hash->{owg_val} = "";
  147. #-- Couple to I/O device
  148. AssignIoPort($hash);
  149. if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
  150. return "OWVAR: Warning, no 1-Wire I/O device found for $name.";
  151. } else {
  152. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; #-- false for now
  153. }
  154. $modules{OWVAR}{defptr}{$id} = $hash;
  155. #--
  156. readingsSingleUpdate($hash,"state","defined",1);
  157. Log3 $name, 3, "OWVAR: Device $name defined.";
  158. $hash->{NOTIFYDEV} = "global";
  159. if ($init_done) {
  160. OWVAR_Init($hash);
  161. }
  162. return undef;
  163. }
  164. #######################################################################################
  165. #
  166. # OWVAR_Notify - Implements the Notify function
  167. #
  168. # Parameter hash = hash of device addressed
  169. # a = argument array
  170. #
  171. ########################################################################################
  172. sub OWVAR_Notify ($$) {
  173. my ($hash,$dev) = @_;
  174. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  175. OWVAR_Init($hash);
  176. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  177. }
  178. }
  179. #######################################################################################
  180. #
  181. # OWVAR_Init - Implements the Init function
  182. #
  183. # Parameter hash = hash of device addressed
  184. #
  185. ########################################################################################
  186. sub OWVAR_Init ($) {
  187. my ($hash)=@_;
  188. #-- Start timer for updates
  189. RemoveInternalTimer($hash);
  190. InternalTimer(gettimeofday()+10, "OWVAR_GetValues", $hash, 0);
  191. return undef;
  192. }
  193. #######################################################################################
  194. #
  195. # OWVAR_Attr - Set one attribute value for device
  196. #
  197. # Parameter hash = hash of device addressed
  198. # a = argument array
  199. #
  200. ########################################################################################
  201. sub OWVAR_Attr(@) {
  202. my ($do,$name,$key,$value) = @_;
  203. my $hash = $defs{$name};
  204. my $ret;
  205. if ( $do eq "set") {
  206. ARGUMENT_HANDLER: {
  207. #-- IODev
  208. $key eq "IODev" and do {
  209. AssignIoPort($hash,$value);
  210. if( defined($hash->{IODev}) ) {
  211. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  212. if ($init_done) {
  213. OWVAR_Init($hash);
  214. }
  215. }
  216. last;
  217. };
  218. }
  219. }
  220. return $ret;
  221. }
  222. ########################################################################################
  223. #
  224. # OWVAR_ChannelNames - find the real channel names
  225. #
  226. # Parameter hash = hash of device addressed
  227. #
  228. ########################################################################################
  229. sub OWVAR_ChannelNames($) {
  230. my ($hash) = @_;
  231. my $name = $hash->{NAME};
  232. my $state = $hash->{READINGS}{"state"}{VAL};
  233. my ($cname,@cnama,$unit);
  234. #-- name
  235. $cname = defined($attr{$name}{"Name"}) ? $attr{$name}{"Name"} : "value";
  236. @cnama = split(/\|/,$cname);
  237. if( int(@cnama)!=2){
  238. push(@cnama,$cnama[0]);
  239. }
  240. $owg_channel=$cnama[0];
  241. #-- unit
  242. $unit = defined($attr{$name}{"Unit"}) ? $attr{$name}{"Unit"} : "\%";
  243. #-- put into readings
  244. $hash->{READINGS}{"value"}{ABBR} = $cnama[1];
  245. $hash->{READINGS}{"value"}{UNIT} = " ".$unit;
  246. }
  247. ########################################################################################
  248. #
  249. # OWVAR_FormatValues - put together various format strings
  250. #
  251. # Parameter hash = hash of device addressed, fs = format string
  252. #
  253. ########################################################################################
  254. sub OWVAR_FormatValues($) {
  255. my ($hash) = @_;
  256. my $name = $hash->{NAME};
  257. my $interface = $hash->{IODev}->{TYPE};
  258. my ($vval,$vlow,$vhigh,$vfunc,$ufunc,$ret);
  259. #-- no change in any value if invalid reading
  260. #for (my $i=0;$i<int(@owg_fixed);$i++){
  261. # return "" if( (!defined($hash->{owg_val})) || ($hash->{owg_val} eq "") );
  262. #}
  263. #-- obtain channel names
  264. OWVAR_ChannelNames($hash);
  265. #-- put into READINGS
  266. readingsBeginUpdate($hash);
  267. #-- formats for output
  268. if (defined($attr{$name}{"Function"})){
  269. ($vfunc,$ufunc) = split('\|',$attr{$name}{"Function"});
  270. #-- replace by proper values (V -> value)
  271. $vfunc =~ s/V/\$hash->{owg_val}/g;
  272. $vfunc = eval($vfunc);
  273. if( !$vfunc ){
  274. $vval = 0.0;
  275. } elsif( $vfunc ne "" ){
  276. $vval = $vfunc;
  277. } else {
  278. $vval = "???";
  279. }
  280. }else{
  281. $vval = $hash->{owg_val};
  282. }
  283. #-- string buildup for return value, STATE and alarm
  284. my $svalue .= sprintf( "%s: %5.3f%s", $hash->{READINGS}{"value"}{ABBR}, $vval,$hash->{READINGS}{"value"}{UNIT});
  285. #-- put into READINGS
  286. $vval = sprintf( "%5.3f", $vval);
  287. readingsBulkUpdate($hash,$owg_channel,$vval);
  288. #-- STATE
  289. readingsBulkUpdate($hash,"state",$svalue);
  290. readingsEndUpdate($hash,1);
  291. return $svalue;
  292. }
  293. ########################################################################################
  294. #
  295. # OWVAR_Get - Implements GetFn function
  296. #
  297. # Parameter hash = hash of device addressed, a = argument array
  298. #
  299. ########################################################################################
  300. sub OWVAR_Get($@) {
  301. my ($hash, @a) = @_;
  302. my $reading = $a[1];
  303. my $name = $hash->{NAME};
  304. my $model = $hash->{OW_MODEL};
  305. my $value = undef;
  306. my $ret = "";
  307. #-- check syntax
  308. return "OWVAR: Get argument is missing @a"
  309. if(int(@a) < 2);
  310. #-- check argument
  311. my $msg = "OWVAR: Get with unknown argument $a[1], choose one of ";
  312. $msg .= "$_$gets{$_} " foreach (keys%gets);
  313. return $msg
  314. if(!defined($gets{$a[1]}));
  315. #-- get id
  316. if($a[1] eq "id") {
  317. $value = $hash->{ROM_ID};
  318. return "$name.id => $value";
  319. }
  320. #-- hash of the busmaster
  321. my $master = $hash->{IODev};
  322. #-- Get other values according to interface type
  323. my $interface= $hash->{IODev}->{TYPE};
  324. #-- get version
  325. if( $a[1] eq "version") {
  326. return "$name.version => $owx_version";
  327. }
  328. if( $a[1] eq "value") {
  329. #-- OWX interface
  330. if( $interface eq "OWX" ){
  331. #-- not different from getting all values ..
  332. $ret = OWXVAR_GetValues($hash);
  333. }elsif( $interface eq "OWX_ASYNC" ){
  334. Log3 $name,1,"OWVAR: Get ASYNC interface not implemented";
  335. #eval {
  336. # $ret = OWX_ASYNC_RunToCompletion($hash,OWXVAR_PT_GetValues($hash));
  337. #};
  338. #$ret = GP_Catch($@) if $@;
  339. #-- OWFS interface
  340. }elsif( $interface eq "OWServer" ){
  341. $ret = OWFSVAR_GetValues($hash);
  342. #-- Unknown interface
  343. }else{
  344. return "OWVAR: Get with wrong IODev type $interface";
  345. }
  346. }
  347. #-- process results
  348. if( $master->{ASYNCHRONOUS} ){
  349. #return "OWVAR: $name getting value, please wait for completion";
  350. return undef;
  351. }else{
  352. #-- when we have a return code, we have an error
  353. if( defined($ret) ){
  354. return "OWVAR: Could not get values from device $name, return was $ret";
  355. }
  356. #-- return the special reading
  357. if ($reading eq "value") {
  358. return "OWVAR: $name.value => ".
  359. $hash->{READINGS}{"value"}{VAL};
  360. } else {
  361. return undef;
  362. }
  363. }
  364. }
  365. #######################################################################################
  366. #
  367. # OWVAR_GetValues - Updates the readings from device
  368. #
  369. # Parameter hash = hash of device addressed
  370. #
  371. ########################################################################################
  372. sub OWVAR_GetValues($@) {
  373. my $hash = shift;
  374. my $name = $hash->{NAME};
  375. my $value = "";
  376. my $ret;
  377. #-- check if device needs to be initialized
  378. if( $hash->{READINGS}{"state"}{VAL} eq "defined"){
  379. OWVAR_InitializeDevice($hash);
  380. OWVAR_FormatValues($hash);
  381. }
  382. #-- Get values according to interface type
  383. my $interface= $hash->{IODev}->{TYPE};
  384. if( $interface eq "OWX" ){
  385. $ret = OWXVAR_GetValues($hash);
  386. }elsif( $interface eq "OWX_ASYNC" ){
  387. Log3 $name, 1,"OWVAR: Get ASYNC interface not implemented";
  388. }elsif( $interface eq "OWServer" ){
  389. $ret = OWFSVAR_GetValues($hash);
  390. }else{
  391. Log3 $name, 3, "OWVAR: GetValues with wrong IODev type $interface";
  392. return 1;
  393. }
  394. #-- process results
  395. if( defined($ret) ){
  396. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  397. return "OWVAR: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret";
  398. }
  399. return undef;
  400. }
  401. ########################################################################################
  402. #
  403. # OWVAR_InitializeDevice - delayed setting of initial readings
  404. #
  405. # Parameter hash = hash of device addressed
  406. #
  407. ########################################################################################
  408. sub OWVAR_InitializeDevice($) {
  409. my ($hash) = @_;
  410. my $name = $hash->{NAME};
  411. my $interface = $hash->{IODev}->{TYPE};
  412. my $ret="";
  413. my ($ret1,$ret2);
  414. #-- Initial readings
  415. $hash->{owg_val} = "0.0";
  416. $hash->{ERRCOUNT} = 0;
  417. #-- Set state to initialized
  418. readingsSingleUpdate($hash,"state","initialized",1);
  419. return OWVAR_GetValues($hash);
  420. }
  421. #######################################################################################
  422. #
  423. # OWVAR_Set - Set one value for device
  424. #
  425. # Parameter hash = hash of device addressed
  426. # a = argument string
  427. #
  428. ########################################################################################
  429. sub OWVAR_Set($@) {
  430. my ($hash, @a) = @_;
  431. #-- for the selector: which values are possible
  432. return join(" ", sort keys %sets) if(@a == 2);
  433. #-- check syntax
  434. return "OWVAR: Set needs one parameter"
  435. if(int(@a) != 3);
  436. #-- check argument
  437. return "OWVAR: Set with unknown argument $a[1], choose one of ".join(",", sort keys %sets)
  438. if(!defined($sets{$a[1]}));
  439. #-- define vars
  440. my $key = $a[1];
  441. my $value = $a[2];
  442. my $ret = undef;
  443. my($vfunc,$ufunc);
  444. my $name = $hash->{NAME};
  445. my $model = $hash->{OW_MODEL};
  446. my $interface = $hash->{IODev}->{TYPE};
  447. #-- formats for input
  448. if (defined($attr{$name}{"Function"})){
  449. ($vfunc,$ufunc) = split('\|',$attr{$name}{"Function"});
  450. #-- replace by proper values (U -> )
  451. $ufunc =~ s/U/\$value/g;
  452. $ufunc = eval($ufunc);
  453. if( !$ufunc ){
  454. $value = 0.0;
  455. } elsif( $ufunc ne "" ){
  456. $value = $ufunc;
  457. } else {
  458. $value = "???";
  459. }
  460. }
  461. #-- put into device
  462. #-- OWX interface
  463. if( $interface eq "OWX" ){
  464. $ret = OWXVAR_SetValues($hash,$key,$value);
  465. }elsif( $interface eq "OWX_ASYNC" ){
  466. Log3 $name, 1,"OWVAR: Set ASYNC interface not implemented";
  467. #-- OWFS interface
  468. }elsif( $interface eq "OWServer" ){
  469. $ret = OWFSVAR_SetValues($hash,$key,$value);
  470. } else {
  471. return "OWVAR: Set with wrong IODev type $interface";
  472. }
  473. #-- process results
  474. if( defined($ret) ){
  475. return "OWVAR: Could not set device $name, reason: ".$ret;
  476. }
  477. #-- process results
  478. $hash->{PRESENT} = 1;
  479. OWVAR_FormatValues($hash);
  480. Log3 $name, 4, "OWVAR: Set $hash->{NAME} $key $value";
  481. return undef;
  482. }
  483. ########################################################################################
  484. #
  485. # OWVAR_Undef - Implements UndefFn function
  486. #
  487. # Parameter hash = hash of device addressed
  488. #
  489. ########################################################################################
  490. sub OWVAR_Undef ($) {
  491. my ($hash) = @_;
  492. delete($modules{OWVAR}{defptr}{$hash->{OW_ID}});
  493. RemoveInternalTimer($hash);
  494. return undef;
  495. }
  496. ########################################################################################
  497. #
  498. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  499. # via OWFS
  500. #
  501. # Prefix = OWFSVAR
  502. #
  503. ########################################################################################
  504. #
  505. # OWFSVAR_GetValues - Get values from device
  506. #
  507. # Parameter hash = hash of device addressed
  508. #
  509. ########################################################################################
  510. sub OWFSVAR_GetValues($) {
  511. my ($hash) = @_;
  512. #-- ID of the device
  513. my $owx_add = substr($hash->{ROM_ID},0,15);
  514. #-- hash of the busmaster
  515. my $master = $hash->{IODev};
  516. my $name = $hash->{NAME};
  517. #-- reset presence
  518. $hash->{PRESENT} = 0;
  519. #-- get values - or should we rather get the uncached ones ?
  520. Log 1, "OWVAR: trying to read from OWserver /$owx_add/wiper";
  521. my $val = OWServer_Read($master,"/$owx_add/wiper");
  522. return "no return from OWServer"
  523. if( !defined($val) );
  524. return "empty return from OWServer"
  525. if( $val eq "" );
  526. $hash->{owg_val}=sprintf("%5.2f",(1.0-$val/255.0)*100);
  527. #-- and now from raw to formatted values
  528. $hash->{PRESENT} = 1;
  529. my $value = OWVAR_FormatValues($hash);
  530. return undef;
  531. }
  532. ########################################################################################
  533. #
  534. # OWFSVAR_SetValues - Set values in device
  535. #
  536. # Parameter hash = hash of device addressed
  537. #
  538. ########################################################################################
  539. sub OWFSVAR_SetValues($$$) {
  540. my ($hash,$key,$value) = @_;
  541. #-- ID of the device
  542. my $owx_add = substr($hash->{ROM_ID},0,15);
  543. #-- hash of the busmaster
  544. my $master = $hash->{IODev};
  545. my $name = $hash->{NAME};
  546. #-- translate from 0..100 to 0..255
  547. return sprintf("OWFSVAR: Set with wrong value $value for $key, range is [%3.1f,%3.1f]",0,100)
  548. if($value < 0 || $value > 100);
  549. my $pos = floor((100-$value)*2.55+0.5);
  550. Log 1,"OWVAR: trying to write to OWserver /$owx_add/wiper => $pos";
  551. OWServer_Write($master, "/$owx_add/wiper/",$pos);
  552. return undef
  553. }
  554. ########################################################################################
  555. #
  556. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  557. # directly to the FHEM server
  558. #
  559. # Prefix = OWXVAR
  560. #
  561. ########################################################################################
  562. #
  563. # OWXVAR_BinValues - Process reading from one device - translate binary into raw
  564. #
  565. # Parameter hash = hash of device addressed
  566. # context = mode for evaluating the binary data
  567. # proc = processing instruction, also passed to OWX_Read.
  568. # bitwise interpretation !!
  569. # if 0, nothing special
  570. # if 1 = bit 0, a reset will be performed not only before, but also after
  571. # the last operation in OWX_Read
  572. # if 2 = bit 1, the initial reset of the bus will be suppressed
  573. # if 8 = bit 3, the fillup of the data with 0xff will be suppressed
  574. # if 16= bit 4, the insertion will be at the top of the queue
  575. # owx_dev = ROM ID of slave device
  576. # crcpart = part of the data that needs to be part of the CRC check
  577. # numread = number of bytes to receive
  578. # res = result string
  579. #
  580. #
  581. ########################################################################################
  582. sub OWXVAR_BinValues($$$$$$$) {
  583. my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_;
  584. my $master = $hash->{IODev};
  585. my $name = $hash->{NAME};
  586. my $error = 0;
  587. my ($i,$j,$k,@data);
  588. my $change = 0;
  589. my $msg;
  590. OWX_WDBGL($name,4,"OWXVAR_BinValues called for device $name in context $context with data ",$res);
  591. #-- process results
  592. if( $context eq "setstate" ) {
  593. #-- we have to get rid of the first 10 bytes
  594. if( length($res) == 11 ){
  595. $res=substr($res,10);
  596. }
  597. if( length($res) != 1 ) {
  598. $error = 1;
  599. $msg = "$name: invalid data length, ".length($res)." instead of 1 bytes ";
  600. }elsif( $res ne $crcpart ){
  601. $error = 1;
  602. $msg = "$name: invalid data ";
  603. }else{
  604. $msg = "$name: no error, ";
  605. }
  606. OWX_WDBGL($name,5-4*$error,"OWXVAR_BinValues setstate: ".$msg,$res);
  607. #-- increase error count
  608. if( $error ){
  609. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  610. }else{
  611. #### master slave context proc owx_dev data crcpart numread startread callback delay
  612. OWX_Qomplex($master, $hash, "release", 18, $owx_dev, "\x96", 0, 11, 0, \&OWXVAR_BinValues, 0.01);
  613. }
  614. #------------------------------------------------------------------
  615. }elsif( $context eq "release" ) {
  616. #-- we have to get rid of the first 10 bytes
  617. if( length($res) == 11 ){
  618. $res=substr($res,10);
  619. }
  620. if( length($res) != 1 ) {
  621. $error = 1;
  622. $msg = "$name: invalid data length, ".length($res)." instead of 1 bytes ";
  623. }elsif( $res ne "\x96" ){
  624. $error = 1;
  625. $msg = "$name: invalid data ";
  626. }else{
  627. $msg = "$name: no error, ";
  628. }
  629. OWX_WDBGL($name,5-4*$error,"OWXVAR_BinValues release : ".$msg,$res);
  630. #-- increase error count
  631. if( $error ){
  632. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  633. }
  634. #------------------------------------------------------------------
  635. }elsif( $context eq "getstate" ) {
  636. #-- we have to get rid of the first 10 bytes
  637. if( length($res) == 12 ){
  638. $res=substr($res,10);
  639. }
  640. @data=split(//,$res);
  641. #-- process results
  642. if (@data != 2) {
  643. $error = 1;
  644. $msg = "$name: invalid data length, ".int(@data)." instead of 2 bytes ";
  645. }else{
  646. $msg = "$name: no error, ";
  647. }
  648. OWX_WDBGL($name,5-4*$error,"OWXVAR_BinValues getstate: ".$msg,$res);
  649. my $stat = ord($data[0]);
  650. my $val = ord($data[1]);
  651. $hash->{owg_val}=sprintf("%5.2f",(1.0-$val/255.0)*100);
  652. #-- and now from raw to formatted values
  653. $hash->{PRESENT} = 1;
  654. if ( !$error ){
  655. my $value = OWVAR_FormatValues($hash)
  656. }else{
  657. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  658. }
  659. }
  660. return undef;
  661. }
  662. ########################################################################################
  663. #
  664. # OWXVAR_GetValues - Trigger reading from one device
  665. #
  666. # Parameter hash = hash of device addressed
  667. #
  668. ########################################################################################
  669. sub OWXVAR_GetValues($) {
  670. my ($hash) = @_;
  671. #-- ID of the device
  672. my $owx_dev = $hash->{ROM_ID};
  673. #-- hash of the busmaster
  674. my $master = $hash->{IODev};
  675. my $name = $hash->{NAME};
  676. #-- NOW ask the specific device
  677. #-- issue the match ROM command \x55 and the read wiper command \xF0
  678. #-- reading 9 + 1 + 2 data bytes and 0 CRC byte = 12 bytes
  679. #-- OLD OWX interface
  680. if( !$master->{ASYNCHRONOUS} ){
  681. OWX_Reset($master);
  682. my $res=OWX_Complex($master,$owx_dev,"\xF0",2);
  683. return "OWVAR: $name not accessible in reading"
  684. if( $res eq 0 );
  685. return "OWVAR: $name has returned invalid data"
  686. if( length($res)!=12);
  687. OWX_Reset($master);
  688. return OWXVAR_BinValues($hash,"getstate",0,$owx_dev,0,2,substr($res,10,2));
  689. #-- NEW OWX interface
  690. }else{
  691. #### master slave context proc owx_dev data crcpart numread startread callback delay
  692. OWX_Qomplex($master, $hash, "getstate", 0, $owx_dev, "\xF0", 0, 12, 0, \&OWXVAR_BinValues, undef);
  693. return undef;
  694. }
  695. }
  696. #######################################################################################
  697. #
  698. # OWXVAR_SetValues - Implements SetFn function
  699. #
  700. # Parameter hash = hash of device addressed
  701. # a = argument array
  702. #
  703. #######################################################################################
  704. sub OWXVAR_SetValues($$$) {
  705. my ($hash, $key,$value) = @_;
  706. #-- ID of the device
  707. my $owx_dev = $hash->{ROM_ID};
  708. #-- hash of the busmaster
  709. my $master = $hash->{IODev};
  710. my $name = $hash->{NAME};
  711. #-- translate from 0..100 to 0..255
  712. return sprintf("OWXVAR: Set with wrong value $value for $key, range is [%3.1f,%3.1f]",0,100)
  713. if($value < 0 || $value > 100);
  714. my $pos = floor((100-$value)*2.55+0.5);
  715. #-- issue the match ROM command \x55 and the write wiper command \x0F,
  716. # followed by 1 bytes of data
  717. #
  718. my $select=sprintf("\x0F%c",$pos);
  719. #-- OLD OWX interface
  720. if( !$master->{ASYNCHRONOUS} ){
  721. OWX_Reset($master);
  722. my $res=OWX_Complex($master,$owx_dev,$select,1);
  723. return "OWXVAR: $name not accessible"
  724. if( $res eq 0 );
  725. my $rv=ord(substr($res,11,1));
  726. return "OWXVAR: $name: Set failed with return value $rv from set value $pos"
  727. if($rv ne $pos);
  728. my $res2=OWX_Complex($master,$owx_dev,"\x96",1);
  729. my $rv2=ord(substr($res2,11,1));
  730. return "OWXVAR: $name: Set failed with return value $rv2 from release value"
  731. if($rv2 ne 0);
  732. OWX_Reset($master);
  733. $hash->{owg_val}=sprintf("%5.2f",(1-$pos/255.0)*100);
  734. #-- NEW OWX interface
  735. }else{
  736. #### master slave context proc owx_dev data crcpart numread startread callback delay
  737. OWX_Qomplex($master, $hash, "setstate", 0, $owx_dev, $select, substr($select,1), 11, 0, \&OWXVAR_BinValues, 0.1);
  738. $hash->{owg_val}=sprintf("%5.2f",(1-$pos/255.0)*100);
  739. }
  740. return undef;
  741. }
  742. 1;
  743. =pod
  744. =item device
  745. =item summary to control 1-Wire variable resistor DS2890
  746. =begin html
  747. <a name="OWVAR"></a>
  748. <h3>OWVAR</h3>
  749. <p>FHEM module to commmunicate with 1-Wire bus digital potentiometer devices of type DS2890<br />
  750. <br />This 1-Wire module works with the OWX interface module, but not yet with the OWServer interface module.
  751. </p>
  752. <a name="OWVARexample"></a>
  753. <h4>Example</h4>
  754. <p>
  755. <code>define OWX_P OWVAR E8D09B030000 </code>
  756. <br />
  757. <code>attr OWX_P Function 1.02 * V + 0.58 | (U-0.58) / 1.02</code>
  758. <br />
  759. </p><br />
  760. <a name="OWVARdefine"></a>
  761. <h4>Define</h4>
  762. <p>
  763. <code>define &lt;name&gt; OWVAR &lt;id&gt;</code> or <br/>
  764. <code>define &lt;name&gt; OWVAR &lt;fam&gt;.&lt;id&gt; </code>
  765. <br /><br /> Define a 1-Wire digital potentiometer device.</p>
  766. <ul>
  767. <li>
  768. <code>&lt;fam&gt;</code>
  769. <br />2-character unique family id, must be 2C </li>
  770. <li>
  771. <code>&lt;id&gt;</code>
  772. <br />12-character unique ROM id of the thermometer device without family id and CRC
  773. code
  774. </li>
  775. </ul>
  776. <a name="OWVARset"></a>
  777. <h4>Set</h4>
  778. <ul>
  779. <li><a name="owvar_value">
  780. <code>set &lt;name&gt; value &lt;float&gt;</code></a>
  781. <br /> The value of the potentiometer resistance against ground. Arguments may be in the
  782. range of [0,100] without a Function attribute, or in the range needed for a <a href="#owvar_function">Function</a> </li>
  783. </ul>
  784. <br />
  785. <a name="OWVARget"></a>
  786. <h4>Get</h4>
  787. <ul>
  788. <li><a name="owvar_id">
  789. <code>get &lt;name&gt; id</code></a>
  790. <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
  791. </ul>
  792. <br />
  793. <a name="OWVARattr"></a>
  794. <h4>Attributes</h4>
  795. <ul>
  796. <li><a name="owvar_cname"><code>attr &lt;name&gt; Name
  797. &lt;string&gt;[|&lt;string&gt;]</code></a>
  798. <br />name for the reading [|name used in state reading]. </li>
  799. <li><a name="owvar_cunit"><code>attr &lt;name&gt; Unit
  800. &lt;string&gt;[|&lt;string&gt;]</code></a>
  801. <br />unit of measurement used in state reading. </li>
  802. <li><a name="owvar_cfunction"> <code>attr &lt;name&gt; Function
  803. &lt;string&gt;|&lt;string&gt;</code></a>
  804. <br />The first string is an arbitrary functional expression u(V) involving the variable V. V is replaced by
  805. the raw potentiometer reading (in the range of [0,100]). The second string must be the inverse
  806. function v(U) involving the variable U, such that U can be replaced by the value given in the
  807. <a href="#OWVARset">Set</a> argument. Care has to taken that v(U) is in the range [0,100].
  808. No check on the validity of these functions is performed,
  809. <b>singularities may crash FHEM.</b> <a href="#OWVARexample">Example see above</a>.
  810. </li>
  811. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  812. </ul>
  813. =end html
  814. =cut