21_OWAD.pm 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857
  1. ########################################################################################
  2. #
  3. # OWAD.pm
  4. #
  5. # FHEM module to commmunicate with 1-Wire A/D converters DS2450
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. # Norbert Truchsess
  9. #
  10. # $Id: 21_OWAD.pm 11130 2016-03-27 09:14:38Z pahenning $
  11. #
  12. ########################################################################################
  13. #
  14. # define <name> OWAD [<model>] <ROM_ID> [interval] or or OWAD <FAM_ID>.<ROM_ID> [interval]
  15. #
  16. # where <name> may be replaced by any name string
  17. #
  18. # <model> is a 1-Wire device type. If omitted, we assume this to be an
  19. # DS2450 A/D converter
  20. # <FAM_ID> is a 1-Wire family id, currently allowed value is 20
  21. # <ROM_ID> is a 12 character (6 byte) 1-Wire ROM ID
  22. # without Family ID, e.g. A2D90D000800
  23. # [interval] is an optional query interval in seconds
  24. #
  25. # get <name> id => FAM_ID.ROM_ID.CRC
  26. # get <name> present => 1 if device present, 0 if not
  27. # get <name> interval => query interval
  28. # get <name> reading => measurement for all channels
  29. # get <name> alarm => alarm measurement settings for all channels
  30. # get <name> status => alarm and i/o status for all channels
  31. # get <name> version => OWX version number
  32. #
  33. # set <name> interval => set period for measurement
  34. #
  35. # Additional attributes are defined in fhem.cfg, in some cases per channel, where <channel>=A,B,C,D
  36. #
  37. # attr <name> stateAL0 "<string>" = character string for denoting low normal condition, default is empty
  38. # attr <name> stateAH0 "<string>" = character string for denoting high normal condition, default is empty
  39. # attr <name> stateAL1 "<string>" = character string for denoting low alarm condition, default is ↓
  40. # attr <name> stateAH1 "<string>" = character string for denoting high alarm condition, default is ↑
  41. # attr <name> <channel>Name <string>[|<string>] = name for the channel [|name used in state reading]
  42. # attr <name> <channel>Unit <string> = unit of measurement for this channel used in state reading (default V, none for empty)
  43. # attr <name> <channel>Function <string> = arbitrary functional expression involving the values V<channel>=VA,VB,VC,VD
  44. # VA is replaced by the measured voltage in channel A, etc.
  45. #
  46. # attr <name> <channel>Alarm <string> = alarm setting in this channel, either both, low, high or none (default)
  47. # attr <name> <channel>Low <float> = measurement value (on the scale determined by function) for low alarm
  48. # attr <name> <channel>High <float> = measurement value (on the scale determined by function) for high alarm
  49. #
  50. ########################################################################################
  51. #
  52. # This programm is free software; you can redistribute it and/or modify
  53. # it under the terms of the GNU General Public License as published by
  54. # the Free Software Foundation; either version 2 of the License, or
  55. # (at your option) any later version.
  56. #
  57. # The GNU General Public License can be found at
  58. # http://www.gnu.org/copyleft/gpl.html.
  59. # A copy is found in the textfile GPL.txt and important notices to the license
  60. # from the author is found in LICENSE.txt distributed with these scripts.
  61. #
  62. # This script is distributed in the hope that it will be useful,
  63. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  64. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  65. # GNU General Public License for more details.
  66. #
  67. ########################################################################################
  68. package main;
  69. use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
  70. use strict;
  71. use warnings;
  72. use GPUtils qw(:all);
  73. use Time::HiRes qw( gettimeofday );
  74. #add FHEM/lib to @INC if it's not allready included. Should rather be in fhem.pl than here though...
  75. BEGIN {
  76. if (!grep(/FHEM\/lib$/,@INC)) {
  77. foreach my $inc (grep(/FHEM$/,@INC)) {
  78. push @INC,$inc."/lib";
  79. };
  80. };
  81. };
  82. use ProtoThreads;
  83. no warnings 'deprecated';
  84. sub Log3($$$);
  85. my $owx_version="6.0";
  86. #-- fixed raw channel name, flexible channel name
  87. my @owg_fixed = ("A","B","C","D");
  88. my @owg_channel = ("A","B","C","D");
  89. #-- channel mode - fixed for now, see initialization
  90. my @owg_mode;
  91. #-- resolution in bit - fixed for now, see initialization
  92. my @owg_resoln;
  93. #-- raw range in mV - fixed for now, see initialization
  94. my @owg_range;
  95. my %gets = (
  96. "id" => "",
  97. "present" => "",
  98. "interval" => "",
  99. "reading" => "",
  100. "alarm" => "",
  101. "status" => "",
  102. "version" => ""
  103. );
  104. my %sets = (
  105. "initialize" => "",
  106. "interval" => "",
  107. "AAlarm" => "",
  108. "ALow" => "",
  109. "AHigh" => "",
  110. "BAlarm" => "",
  111. "BLow" => "",
  112. "BHigh" => "",
  113. "CAlarm" => "",
  114. "CLow" => "",
  115. "CHigh" => "",
  116. "DAlarm" => "",
  117. "DLow" => "",
  118. "DHigh" => ""
  119. );
  120. my %updates = (
  121. "present" => "",
  122. "reading" => "",
  123. "alarm" => "",
  124. "status" => ""
  125. );
  126. ########################################################################################
  127. #
  128. # The following subroutines are independent of the bus interface
  129. #
  130. # Prefix = OWAD
  131. #
  132. ########################################################################################
  133. #
  134. # OWAD_Initialize
  135. #
  136. # Parameter hash = hash of device addressed
  137. #
  138. ########################################################################################
  139. sub OWAD_Initialize ($) {
  140. my ($hash) = @_;
  141. $hash->{DefFn} = "OWAD_Define";
  142. $hash->{UndefFn} = "OWAD_Undef";
  143. $hash->{GetFn} = "OWAD_Get";
  144. $hash->{SetFn} = "OWAD_Set";
  145. $hash->{NotifyFn}= "OWAD_Notify";
  146. $hash->{InitFn} = "OWAD_Init";
  147. $hash->{AttrFn} = "OWAD_Attr";
  148. my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2450 ".
  149. "stateAL0 stateAL1 stateAH0 stateAH1 ".
  150. "interval ".
  151. $readingFnAttributes;
  152. for( my $i=0;$i<int(@owg_fixed);$i++ ){
  153. $attlist .= " ".$owg_fixed[$i]."Name";
  154. $attlist .= " ".$owg_fixed[$i]."Function";
  155. $attlist .= " ".$owg_fixed[$i]."Unit";
  156. $attlist .= " ".$owg_fixed[$i]."Alarm:none,low,high,both";
  157. $attlist .= " ".$owg_fixed[$i]."Low";
  158. $attlist .= " ".$owg_fixed[$i]."High";
  159. }
  160. $hash->{AttrList} = $attlist;
  161. #-- value globals
  162. $hash->{owg_status} = [];
  163. #$hash->{owg_state} = undef;
  164. #-- channel values - always the raw values from the device
  165. $hash->{owg_val} = ["","","",""];
  166. #-- alarm status 0 = disabled, 1 = enabled, but not alarmed, 2 = alarmed
  167. $hash->{owg_slow}=[0,0,0,0];
  168. $hash->{owg_shigh}=[0,0,0,0];
  169. #-- alarm values - always the raw values committed to the device
  170. $hash->{owg_vlow} = [];
  171. $hash->{owg_vhigh} = [];
  172. #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer
  173. main::LoadModule("OWX");
  174. }
  175. #########################################################################################
  176. #
  177. # OWAD_Define - Implements DefFn function
  178. #
  179. # Parameter hash = hash of device addressed, def = definition string
  180. #
  181. #########################################################################################
  182. sub OWAD_Define ($$) {
  183. my ($hash, $def) = @_;
  184. my @a = split("[ \t][ \t]*", $def);
  185. my ($name,$model,$fam,$id,$crc,$interval,$scale,$ret);
  186. #-- default
  187. $name = $a[0];
  188. $interval = 300;
  189. $scale = "";
  190. $ret = "";
  191. #-- check syntax
  192. return "OWAD: Wrong syntax, must be define <name> OWAD [<model>] <id> [interval] or OWAD <fam>.<id> [interval]"
  193. if(int(@a) < 2 || int(@a) > 5);
  194. #-- different types of definition allowed
  195. my $a2 = $a[2];
  196. my $a3 = defined($a[3]) ? $a[3] : "";
  197. #-- no model, 12 characters
  198. if( $a2 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  199. $model = "DS2450";
  200. $fam = "20";
  201. $id = $a[2];
  202. if(int(@a)>=4) { $interval = $a[3]; }
  203. #-- no model, 2+12 characters
  204. } elsif( $a2 =~ m/^[0-9|a-f|A-F]{2}\.[0-9|a-f|A-F]{12}$/ ) {
  205. $fam = substr($a[2],0,2);
  206. $id = substr($a[2],3);
  207. if(int(@a)>=4) { $interval = $a[3]; }
  208. if( $fam eq "20" ){
  209. $model = "DS2450";
  210. CommandAttr (undef,"$name model DS2450");
  211. }else{
  212. return "OWAD: Wrong 1-Wire device family $fam";
  213. }
  214. #-- model, 12 characters
  215. } elsif( $a3 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  216. $model = $a[2];
  217. $id = $a[3];
  218. if(int(@a)>=5) { $interval = $a[4]; }
  219. if( $model eq "DS2450" ){
  220. $fam = "20";
  221. CommandAttr (undef,"$name model DS2450");
  222. }else{
  223. return "OWAD: Wrong 1-Wire device model $model";
  224. }
  225. } else {
  226. return "OWAD: $a[0] ID $a[2] invalid, specify a 12 or 2.12 digit value";
  227. }
  228. #-- determine CRC Code
  229. $crc = sprintf("%02x",OWX_CRC($fam.".".$id."00"));
  230. #-- Define device internals
  231. $hash->{ROM_ID} = "$fam.$id.$crc";
  232. $hash->{OW_ID} = $id;
  233. $hash->{OW_FAMILY} = $fam;
  234. $hash->{PRESENT} = 0;
  235. $hash->{INTERVAL} = $interval;
  236. $hash->{ERRCOUNT} = 0;
  237. #-- Couple to I/O device
  238. AssignIoPort($hash);
  239. if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
  240. return "OWAD: Warning, no 1-Wire I/O device found for $name.";
  241. } else {
  242. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; #-- false for now
  243. }
  244. $main::modules{OWAD}{defptr}{$id} = $hash;
  245. #--
  246. readingsSingleUpdate($hash,"state","defined",1);
  247. Log 3, "OWAD: Device $name defined.";
  248. $hash->{NOTIFYDEV} = "global";
  249. if ($init_done) {
  250. OWAD_Init($hash);
  251. }
  252. return undef;
  253. }
  254. ######################################################################################
  255. #
  256. # OWAD_Notify Function -
  257. # Parameter hash = hash of device addressed
  258. # dev = device
  259. #
  260. ######################################################################################
  261. sub OWAD_Notify ($$) {
  262. my ($hash,$dev) = @_;
  263. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  264. OWAD_Init($hash);
  265. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  266. }
  267. }
  268. #####################################################################################
  269. #
  270. # OWAD_Init Function -
  271. # Parameter hash = hash of device addressed
  272. #
  273. #
  274. ######################################################################################
  275. sub OWAD_Init ($) {
  276. my ($hash)=@_;
  277. #-- Start timer for updates
  278. RemoveInternalTimer($hash);
  279. InternalTimer(gettimeofday()+10, "OWAD_InitializeDevice", $hash, 0);
  280. return undef;
  281. }
  282. #######################################################################################
  283. #
  284. # OWAD_Attr - Set one attribute value for device
  285. #
  286. # Parameter hash = hash of device addressed
  287. # a = argument array
  288. #
  289. ########################################################################################
  290. sub OWAD_Attr(@) {
  291. my ($do,$name,$key,$value) = @_;
  292. my $hash = $defs{$name};
  293. my $ret;
  294. if ( $do eq "set") {
  295. ARGUMENT_HANDLER: {
  296. #-- interval modified at runtime
  297. $key eq "interval" and do {
  298. #-- check value
  299. return "OWAD: Set with short interval, must be > 1" if(int($value) < 1);
  300. #-- update timer
  301. $hash->{INTERVAL} = $value;
  302. if ($init_done) {
  303. RemoveInternalTimer($hash);
  304. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWAD_GetValues", $hash, 0);
  305. }
  306. last;
  307. };
  308. #-- alarm settings modified at runtime
  309. $key =~ m/(.*)(Alarm|Low|High)/ and do {
  310. #-- safeguard against uninitialized devices
  311. return undef
  312. if( $hash->{READINGS}{"state"}{VAL} eq "defined" );
  313. $ret = OWAD_Set($hash,($name,$key,$value));
  314. last;
  315. };
  316. $key eq "IODev" and do {
  317. AssignIoPort($hash,$value);
  318. if( defined($hash->{IODev}) ) {
  319. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  320. if ($init_done) {
  321. OWAD_Init($hash);
  322. }
  323. }
  324. last;
  325. };
  326. }
  327. } elsif ( $do eq "del" ) {
  328. ARGUMENT_HANDLER: {
  329. #-- should remove alarm setting, but does nothing so far
  330. $key =~ m/(.*)(Alarm)/ and do {
  331. last;
  332. }
  333. }
  334. }
  335. return $ret;
  336. }
  337. ########################################################################################
  338. #
  339. # OWAD_ChannelNames - find the real channel names
  340. #
  341. # Parameter hash = hash of device addressed
  342. #
  343. ########################################################################################
  344. sub OWAD_ChannelNames($) {
  345. my ($hash) = @_;
  346. my $name = $hash->{NAME};
  347. my $state = $hash->{READINGS}{"state"}{VAL};
  348. my ($cname,@cnama,$unit);
  349. for (my $i=0;$i<int(@owg_fixed);$i++){
  350. #-- name
  351. $cname = defined($attr{$name}{$owg_fixed[$i]."Name"}) ? $attr{$name}{$owg_fixed[$i]."Name"} : "$owg_fixed[$i]";
  352. @cnama = split(/\|/,$cname);
  353. if( int(@cnama)!=2){
  354. push(@cnama,$cnama[0]);
  355. }
  356. $owg_channel[$i]=$cnama[0];
  357. #-- unit
  358. $unit = defined($attr{$name}{$owg_fixed[$i]."Unit"}) ? $attr{$name}{$owg_fixed[$i]."Unit"} : "V";
  359. if($unit eq "none"){
  360. $unit = "";
  361. }else{
  362. $unit = " ".$unit;
  363. }
  364. #-- put into readings
  365. $hash->{READINGS}{$owg_channel[$i]}{ABBR} = $cnama[1];
  366. $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unit;
  367. }
  368. }
  369. ########################################################################################
  370. #
  371. # OWAD_FormatValues - put together various format strings
  372. #
  373. # Parameter hash = hash of device addressed, fs = format string
  374. #
  375. ########################################################################################
  376. sub OWAD_FormatValues($) {
  377. my ($hash) = @_;
  378. my $name = $hash->{NAME};
  379. my $interface = $hash->{IODev}->{TYPE};
  380. my ($vval,$vlow,$vhigh,$vfunc,$ret);
  381. my $vfuncall = "";
  382. my $svalue = "";
  383. #-- insert initial values
  384. for( my $k=0;$k<int(@owg_fixed);$k++ ){
  385. #-- TODO $hash->{owg_val}->[..] might be undefined here?
  386. $vfuncall .= "\$hash->{owg_val}->[$k]=$hash->{owg_val}->[$k];";
  387. }
  388. my $alarm;
  389. my $galarm = 0;
  390. my $achange = 0;
  391. my $schange = 0;
  392. $hash->{ALARM} = 0;
  393. #-- alarm signatures
  394. my $stateal1 = defined($attr{$name}{stateAL1}) ? $attr{$name}{stateAL1} : "↓";
  395. my $stateah1 = defined($attr{$name}{stateAH1}) ? $attr{$name}{stateAH1} : "↑";
  396. my $stateal0 = defined($attr{$name}{stateAL0}) ? $attr{$name}{stateAL0} : "";
  397. my $stateah0 = defined($attr{$name}{stateAH0}) ? $attr{$name}{stateAH0} : "";
  398. #-- no change in any value if invalid reading
  399. for (my $i=0;$i<int(@owg_fixed);$i++){
  400. return "" if( (!defined($hash->{owg_val}->[$i])) || ($hash->{owg_val}->[$i] eq "") );
  401. }
  402. #-- obtain channel names
  403. OWAD_ChannelNames($hash);
  404. #-- put into READINGS
  405. readingsBeginUpdate($hash);
  406. #-- formats for output
  407. for (my $i=0;$i<int(@owg_fixed);$i++){
  408. if (defined($attr{$name}{$owg_fixed[$i]."Function"})){
  409. $vfunc = $attr{$name}{$owg_fixed[$i]."Function"};
  410. } else {
  411. $vfunc = "V$owg_fixed[$i]";
  412. }
  413. $hash->{tempf}{$owg_fixed[$i]}{function} = $vfunc;
  414. #-- replace by proper values (VA -> $hash->{owg_val}->[0] etc.)
  415. # careful: how to prevent {VAL} from being replaced ?
  416. for( my $k=0;$k<int(@owg_fixed);$k++ ){
  417. my $sstr = "V$owg_fixed[$k]";
  418. $vfunc =~ s/VAL/WERT/g;
  419. $vfunc =~ s/$sstr/\$hash->{owg_val}->[$k]/g;
  420. $vfunc =~ s/WERT/VAL/g;
  421. }
  422. #-- determine the measured value from the function
  423. $vfunc = $vfuncall.$vfunc;
  424. $vfunc = eval($vfunc);
  425. if( !$vfunc ){
  426. $vval = 0.0;
  427. } elsif( $vfunc ne "" ){
  428. $vval = $vfunc;
  429. } else {
  430. $vval = "???";
  431. }
  432. #-- low alarm value
  433. $vlow =$hash->{owg_vlow}->[$i];
  434. $main::attr{$name}{$owg_fixed[$i]."Low"}=$vlow;
  435. #-- high alarm value
  436. $vhigh=$hash->{owg_vhigh}->[$i];
  437. $main::attr{$name}{$owg_fixed[$i]."High"}=$vhigh;
  438. #-- string buildup for return value, STATE and alarm
  439. $svalue .= sprintf( "%s: %5.3f%s", $hash->{READINGS}{$owg_channel[$i]}{ABBR}, $vval,$hash->{READINGS}{$owg_channel[$i]}{UNIT});
  440. #-- Test for alarm condition
  441. $alarm = "none";
  442. #-- alarm signature low
  443. #-- TODO may be undefined here?
  444. if( $hash->{owg_slow}->[$i] == 0 ) {
  445. } else {
  446. $alarm="low";
  447. if( $vval > $vlow ){
  448. $hash->{owg_slow}->[$i] = 1;
  449. $svalue .= $stateal0;
  450. } else {
  451. $galarm = 1;
  452. $hash->{owg_slow}->[$i] = 2;
  453. $svalue .= $stateal1;
  454. }
  455. }
  456. #-- alarm signature high
  457. #-- TODO may be undefined here?
  458. if( $hash->{owg_shigh}->[$i] == 0 ) {
  459. } else {
  460. if( $alarm eq "low") {
  461. $alarm="both";
  462. }else{
  463. $alarm="high";
  464. }
  465. if( $vval < $vhigh ){
  466. $hash->{owg_shigh}->[$i] = 1;
  467. $svalue .= $stateah0;
  468. } else {
  469. $galarm = 1;
  470. $hash->{owg_shigh}->[$i] = 2;
  471. $svalue .= $stateah1;
  472. }
  473. }
  474. #-- put into READINGS
  475. $vval = sprintf( "%5.3f", $vval);
  476. readingsBulkUpdate($hash,"$owg_channel[$i]",$vval);
  477. #-- insert space
  478. if( $i<int(@owg_fixed)-1 ){
  479. $svalue .= " ";
  480. }
  481. }
  482. #-- STATE
  483. readingsBulkUpdate($hash,"state",$svalue);
  484. readingsEndUpdate($hash,1);
  485. $hash->{ALARM} = 1
  486. if( $galarm == 1);
  487. return $svalue;
  488. }
  489. ########################################################################################
  490. #
  491. # OWAD_Get - Implements GetFn function
  492. #
  493. # Parameter hash = hash of device addressed, a = argument array
  494. #
  495. ########################################################################################
  496. sub OWAD_Get($@) {
  497. my ($hash, @a) = @_;
  498. my $reading = $a[1];
  499. my $name = $hash->{NAME};
  500. my $model = $hash->{OW_MODEL};
  501. #-- ID of the device, hash of the busmaster
  502. my $owx_dev = $hash->{ROM_ID};
  503. my $master = $hash->{IODev};
  504. my $interface= $hash->{IODev}->{TYPE};
  505. my ($value,$value2,$value3) = (undef,undef,undef);
  506. my $ret = "";
  507. #-- check syntax
  508. return "OWAD: Get argument is missing @a"
  509. if(int(@a) != 2);
  510. #-- check argument
  511. return "OWAD: Get with unknown argument $a[1], choose one of ".join(" ", sort keys %gets)
  512. if(!defined($gets{$a[1]}));
  513. #-- get id
  514. if($a[1] eq "id") {
  515. $value = $owx_dev;
  516. return "$name.id => $value";
  517. }
  518. #-- get present
  519. if($a[1] eq "present") {
  520. #-- asynchronous mode
  521. if( $hash->{ASYNC} ){
  522. my ($task,$task_state);
  523. eval {
  524. OWX_ASYNC_RunToCompletion($hash,OWX_ASYNC_PT_Verify($hash));
  525. };
  526. return GP_Catch($@) if $@;
  527. return "$name.present => ".ReadingsVal($name,"present","unknown");
  528. } else {
  529. $value = OWX_Verify($master,$hash->{ROM_ID});
  530. }
  531. $hash->{PRESENT} = $value;
  532. return "$name.present => $value";
  533. }
  534. #-- get interval
  535. if($a[1] eq "interval") {
  536. $value = $hash->{INTERVAL};
  537. return "$name.interval => $value";
  538. }
  539. #-- get version
  540. if( $a[1] eq "version") {
  541. return "$name.version => $owx_version";
  542. }
  543. #-- get reading according to interface type
  544. if($a[1] eq "reading") {
  545. #-- OWX interface
  546. if( $interface eq "OWX" ){
  547. $ret = OWXAD_GetPage($hash,"reading",1);
  548. }elsif( $interface eq "OWX_ASYNC" ){
  549. eval {
  550. $ret = OWX_ASYNC_RunToCompletion($hash,OWXAD_PT_GetPage($hash,"reading",1));
  551. };
  552. $ret = GP_Catch($@) if $@;
  553. #-- OWFS interface
  554. }elsif( $interface eq "OWServer" ){
  555. $ret = OWFSAD_GetPage($hash,"reading",1);
  556. #-- Unknown interface
  557. }else{
  558. return "OWAD: Get with wrong IODev type $interface";
  559. }
  560. #-- process result
  561. if( $master->{ASYNCHRONOUS} ){
  562. return "OWAD: $name getting reading, please wait for completion";
  563. }else{
  564. if( defined($ret) ){
  565. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  566. if( $hash->{ERRCOUNT} > 5 ){
  567. $hash->{INTERVAL} = 9999;
  568. }
  569. return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret";
  570. }
  571. return "OWAD: $name.reading => ".$hash->{READINGS}{"state"}{VAL};
  572. }
  573. }
  574. #-- get alarm values according to interface type
  575. if($a[1] eq "alarm") {
  576. #-- OWX interface
  577. if( $interface eq "OWX" ){
  578. $ret = OWXAD_GetPage($hash,"alarm",1);
  579. }elsif( $interface eq "OWX_ASYNC" ){
  580. eval {
  581. $ret = OWX_ASYNC_RunToCompletion($hash,OWXAD_PT_GetPage($hash,"alarm",1));
  582. };
  583. $ret = GP_Catch($@) if $@;
  584. #-- OWFS interface
  585. }elsif( $interface eq "OWServer" ){
  586. $ret = OWFSAD_GetPage($hash,"alarm",1);
  587. #-- Unknown interface
  588. }else{
  589. return "OWAD: Get with wrong IODev type $interface";
  590. }
  591. #-- process result
  592. if( $master->{ASYNCHRONOUS} ){
  593. return "OWAD: $name getting alarm values, please wait for completion";
  594. }else{
  595. if( defined($ret) ){
  596. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  597. if( $hash->{ERRCOUNT} > 5 ){
  598. $hash->{INTERVAL} = 9999;
  599. }
  600. return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret";
  601. }
  602. #-- assemble ouput string
  603. $value = "";
  604. for (my $i=0;$i<int(@owg_fixed);$i++){
  605. $value .= sprintf "%s:[%4.2f,%4.2f] ",$owg_channel[$i],
  606. $main::attr{$name}{$owg_channel[$i]."Low"},
  607. $main::attr{$name}{$owg_channel[$i]."High"};
  608. }
  609. return "OWAD: $name.alarm => $value";
  610. }
  611. }
  612. #-- get status values according to interface type
  613. if($a[1] eq "status") {
  614. #-- OWX interface
  615. if( $interface eq "OWX" ){
  616. $ret = OWXAD_GetPage($hash,"status",1);
  617. }elsif( $interface eq "OWX_ASYNC" ){
  618. eval {
  619. $ret = OWX_ASYNC_RunToCompletion($hash,OWXAD_PT_GetPage($hash,"status",1));
  620. };
  621. $ret = GP_Catch($@) if $@;
  622. #-- OWFS interface
  623. }elsif( $interface eq "OWServer" ){
  624. $ret = OWFSAD_GetPage($hash,"status",1);
  625. #-- Unknown interface
  626. }else{
  627. return "OWAD: Get with wrong IODev type $interface";
  628. }
  629. #-- process result
  630. if( $master->{ASYNCHRONOUS} ){
  631. return "OWAD: $name getting status, please wait for completion";
  632. }else{
  633. if( defined($ret) ){
  634. $hash->{ERRCOUNT}=$hash->{ERRCOUNT}+1;
  635. if( $hash->{ERRCOUNT} > 5 ){
  636. $hash->{INTERVAL} = 9999;
  637. }
  638. return "OWAD: Could not get values from device $name for ".$hash->{ERRCOUNT}." times, reason $ret";
  639. }
  640. #-- assemble output string
  641. $value = "\n";
  642. for (my $i=0;$i<int(@owg_fixed);$i++){
  643. $value .= $owg_channel[$i].": ".$owg_mode[$i].", ";
  644. #$value .= "disabled ,"
  645. # if ( !($sb2 && 128) );
  646. $value .= sprintf "raw range %3.2f V, ",$owg_range[$i]/1000;
  647. $value .= sprintf "resolution %d bit, ",$owg_resoln[$i];
  648. if (!defined $hash->{owg_slow}->[$i]) {
  649. $value .= "low alarm undefined, ";
  650. } elsif( $hash->{owg_slow}->[$i]==0 ) {
  651. $value .= "low alarm disabled, ";
  652. } elsif( $hash->{owg_slow}->[$i]==1 ) {
  653. $value .= "low alarm enabled, ";
  654. } elsif( $hash->{owg_slow}->[$i]==2 ) {
  655. $value .= "alarmed low, ";
  656. }
  657. if (!defined $hash->{owg_shigh}) {
  658. $value .= "high alarm undefined";
  659. } elsif( $hash->{owg_shigh}->[$i]==0 ) {
  660. $value .= "high alarm disabled";
  661. } elsif( $hash->{owg_shigh}->[$i]==1 ) {
  662. $value .= "high alarm enabled";
  663. } elsif( $hash->{owg_shigh}->[$i]==2 ) {
  664. $value .= "alarmed high";
  665. }
  666. #-- insert space
  667. if( $i<int(@owg_fixed)-1 ){
  668. $value .= "\n";
  669. }
  670. }
  671. return "OWAD: $name.status => ".$value;
  672. }
  673. }
  674. }
  675. #######################################################################################
  676. #
  677. # OWAD_GetValues - Updates the reading from one device
  678. #
  679. # Parameter hash = hash of device addressed
  680. #
  681. ########################################################################################
  682. sub OWAD_GetValues($) {
  683. my $hash = shift;
  684. my $name = $hash->{NAME};
  685. my $model = $hash->{OW_MODEL};
  686. my $interface= $hash->{IODev}->{TYPE};
  687. my $value = "";
  688. my $ret = "";
  689. my ($ret1,$ret2,$ret3);
  690. #-- define warnings
  691. my $warn = "none";
  692. $hash->{ALARM} = "0";
  693. #-- restart timer for updates
  694. RemoveInternalTimer($hash);
  695. InternalTimer(time()+$hash->{INTERVAL}, "OWAD_GetValues", $hash, 0);
  696. #-- Get readings, alarms and stati according to interface type
  697. if( $interface eq "OWX" ){
  698. #-- max 3 tries
  699. #for(my $try=0; $try<3; $try++){
  700. $ret1 = OWXAD_GetPage($hash,"reading",0);
  701. $ret2 = OWXAD_GetPage($hash,"alarm",0);
  702. $ret3 = OWXAD_GetPage($hash,"status",1);
  703. #}
  704. }elsif( $interface eq "OWX_ASYNC" ){
  705. eval {
  706. OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"reading",0));
  707. OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"alarm",0));
  708. OWX_ASYNC_Schedule( $hash, OWXAD_PT_GetPage($hash,"status",1));
  709. };
  710. $ret .= GP_Catch($@) if $@;
  711. }elsif( $interface eq "OWServer" ){
  712. $ret1 = OWFSAD_GetPage($hash,"reading",0);
  713. $ret2 = OWFSAD_GetPage($hash,"alarm",0);
  714. $ret3 = OWFSAD_GetPage($hash,"status",1);
  715. }else{
  716. return "OWAD: GetValues with wrong IODev type $interface";
  717. }
  718. #-- process results
  719. $ret .= $ret1
  720. if( defined($ret1) );
  721. $ret .= $ret2
  722. if( defined($ret2) );
  723. $ret .= $ret3
  724. if( defined($ret3) );
  725. if( $ret ne "" ){
  726. return "OWAD: Could not get values from device $name, reason $ret";
  727. }
  728. return undef;
  729. }
  730. ########################################################################################
  731. #
  732. # OWAD_InitializeDevice - delayed setting of initial readings and channel names
  733. #
  734. # Parameter hash = hash of device addressed
  735. #
  736. ########################################################################################
  737. sub OWAD_InitializeDevice($) {
  738. my ($hash) = @_;
  739. my $name = $hash->{NAME};
  740. my $interface = $hash->{IODev}->{TYPE};
  741. my $ret="";
  742. my ($ret1,$ret2);
  743. #-- Initial readings
  744. $hash->{owg_val} = ["","","",""];
  745. #-- Initial alarm values
  746. for( my $i=0;$i<int(@owg_fixed);$i++) {
  747. $hash->{ERRCOUNT} = 0;
  748. #-- alarm enabling
  749. if( AttrVal($name,$owg_fixed[$i]."Alarm",undef) ){
  750. my $alarm = AttrVal($name,$owg_fixed[$i]."Alarm",undef);
  751. if( $alarm eq "none" ){
  752. $hash->{owg_slow}->[$i]=0;
  753. $hash->{owg_shigh}->[$i]=0;
  754. }elsif( $alarm eq "low" ){
  755. $hash->{owg_slow}->[$i]=1;
  756. $hash->{owg_shigh}->[$i]=0;
  757. }elsif( $alarm eq "high" ){
  758. $hash->{owg_slow}->[$i]=0;
  759. $hash->{owg_shigh}->[$i]=1;
  760. }elsif( $alarm eq "both" ){
  761. $hash->{owg_slow}->[$i]=1;
  762. $hash->{owg_shigh}->[$i]=1;
  763. }
  764. } else {
  765. $hash->{owg_slow}->[$i]=0;
  766. $hash->{owg_shigh}->[$i]=0;
  767. }
  768. #-- low alarm value - no checking for correct parameters
  769. if( AttrVal($name,$owg_fixed[$i]."Low",undef) ){
  770. $hash->{owg_vlow}->[$i] = $main::attr{$name}{$owg_fixed[$i]."Low"};
  771. } else {
  772. $hash->{owg_vlow}->[$i] = 0;
  773. }
  774. #-- high alarm value
  775. if( AttrVal($name,$owg_fixed[$i]."High",undef) ){
  776. $hash->{owg_vhigh}->[$i] = $main::attr{$name}{$owg_fixed[$i]."High"};
  777. } else {
  778. $hash->{owg_vhigh}->[$i] = 0;
  779. }
  780. }
  781. #-- resolution in bit - fixed for now
  782. @owg_resoln = (16,16,16,16);
  783. #-- raw range in mV - fixed for now
  784. @owg_range = (5120,5120,5120,5120);
  785. #-- mode - fixed for now
  786. @owg_mode = ("input","input","input","input");
  787. #-- OWX interface
  788. if( $interface eq "OWX" ){
  789. $ret1 = OWXAD_SetPage($hash,"status");
  790. $ret2 = OWXAD_SetPage($hash,"alarm");
  791. }elsif( $interface eq "OWX_ASYNC" ){
  792. eval {
  793. OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
  794. OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"alarm"));
  795. };
  796. $ret .= GP_Catch($@) if $@;
  797. #-- OWFS interface
  798. }elsif( $interface eq "OWServer" ){
  799. $ret1 = OWFSAD_SetPage($hash,"status");
  800. $ret2 = OWFSAD_SetPage($hash,"alarm");
  801. }
  802. #-- process results
  803. $ret .= $ret1
  804. if( defined($ret1) );
  805. $ret .= $ret2
  806. if( defined($ret2) );
  807. if( $ret ne "" ){
  808. return "OWAD: Could not initialize device $name, reason: ".$ret;
  809. }
  810. #-- Set state to initialized
  811. readingsSingleUpdate($hash,"state","initialized",1);
  812. return OWAD_GetValues($hash);
  813. }
  814. #######################################################################################
  815. #
  816. # OWAD_Set - Set one value for device
  817. #
  818. # Parameter hash = hash of device addressed
  819. # a = argument array
  820. #
  821. ########################################################################################
  822. sub OWAD_Set($@) {
  823. my ($hash, @a) = @_;
  824. my $key = $a[1];
  825. my $value = $a[2];
  826. #-- for the selector: which values are possible
  827. return join(" ", sort keys %sets) if(@a == 2);
  828. #-- check syntax
  829. return "OWAD: Set needs one parameter when setting this value"
  830. if( int(@a)!=3 );
  831. #-- check argument
  832. if( !defined($sets{$a[1]}) && !($key =~ m/.*(Alarm|Low|High)/) ){
  833. return "OWAD: Set with unknown argument $a[1]";
  834. }
  835. #-- define vars
  836. my $ret = undef;
  837. my $channon = undef;
  838. my $channo = undef;
  839. my $condx;
  840. my $name = $hash->{NAME};
  841. my $model = $hash->{OW_MODEL};
  842. #-- re-intialize
  843. if($key eq "initialize") {
  844. OWADInitializeDevice($hash);
  845. return undef;
  846. }
  847. #-- set new timer interval
  848. if($key eq "interval") {
  849. # check value
  850. return "OWAD: Set with short interval, must be > 1"
  851. if(int($value) < 1);
  852. # update timer
  853. $hash->{INTERVAL} = $value;
  854. RemoveInternalTimer($hash);
  855. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWAD_GetValues", $hash, 0);
  856. return undef;
  857. }
  858. #-- find out which channel we have
  859. my $tc =$key;
  860. if( $tc =~ s/(.*)(Alarm|Low|High)/$channon=$1/se ) {
  861. for (my $i=0;$i<int(@owg_fixed);$i++){
  862. if( $tc eq $owg_fixed[$i] ){
  863. $channo = $i;
  864. $channon = $tc;
  865. last;
  866. }
  867. }
  868. }
  869. return "OWAD: Cannot determine channel from parameter $a[1]"
  870. if( !(defined($channo)));
  871. #-- set these values depending on interface type
  872. my $interface= $hash->{IODev}->{TYPE};
  873. #-- set status values (alarm on or off)
  874. if( $key =~ m/(.*)(Alarm)/ ) {
  875. return "OWAD: Set with wrong value $value for $key, allowed is none/low/high/both"
  876. if($value ne "none" && $value ne "low" && $value ne "high" && $value ne "both");
  877. #-- put into attribute value
  878. if( $main::attr{$name}{$owg_fixed[$channo]."Alarm"} ne $value ){
  879. #Log 1,"OWAD: Correcting attribute value ".$owg_fixed[$channo]."Alarm";
  880. $main::attr{$name}{$owg_fixed[$channo]."Alarm"} = $value
  881. }
  882. #-- put into device
  883. if( $value eq "low" || $value eq "both" ){
  884. $hash->{owg_slow}->[$channo]=1;
  885. } else{
  886. $hash->{owg_slow}->[$channo]=0;
  887. }
  888. if( $value eq "high" || $value eq "both" ){
  889. $hash->{owg_shigh}->[$channo]=1;
  890. } else{
  891. $hash->{owg_shigh}->[$channo]=0;
  892. }
  893. #-- OWX interface
  894. if( $interface eq "OWX" ){
  895. $ret = OWXAD_SetPage($hash,"status");
  896. }elsif( $interface eq "OWX_ASYNC" ){
  897. eval {
  898. OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
  899. };
  900. $ret = GP_Catch($@) if $@;
  901. #-- OWFS interface
  902. }elsif( $interface eq "OWServer" ){
  903. $ret = OWFSAD_SetPage($hash,"status");
  904. } else {
  905. return "OWAD: Set with wrong IODev type $interface";
  906. }
  907. #-- process results
  908. if( defined($ret) ){
  909. return "OWAD: Could not set device $name, reason: ".$ret;
  910. }
  911. #-- set alarm values (alarm voltages)
  912. }elsif( $key =~ m/(.*)(Low|High)/ ) {
  913. #-- find upper and lower boundaries
  914. my $mmin = 0.0;
  915. my $mmax = $owg_range[$channo]/1000;
  916. return sprintf("OWAD: Set with wrong value $value for $key, range is [%3.1f,%3.1f]",$mmin,$mmax)
  917. if($value < $mmin || $value > $mmax);
  918. #-- round to those numbers understood by the device
  919. my $value2 = int($value*256000/$owg_range[$channo]+0.5)*$owg_range[$channo]/256000;
  920. if( $key =~ m/(.*)Low/ ){
  921. #-- put into attribute value
  922. if( $main::attr{$name}{$owg_fixed[$channo]."Low"} != $value2 ){
  923. Log 1,"OWAD: Correcting attribute value ".$owg_fixed[$channo]."Low";
  924. $main::attr{$name}{$owg_fixed[$channo]."Low"} = $value2
  925. }
  926. #-- put into device
  927. $hash->{owg_vlow}->[$channo] = $value2;
  928. } elsif( $key =~ m/(.*)High/ ){
  929. #-- put into attribute value
  930. if( $main::attr{$name}{$owg_fixed[$channo]."High"} != $value2 ){
  931. Log 1,"OWAD: Correcting attribute value ".$owg_fixed[$channo]."High";
  932. $main::attr{$name}{$owg_fixed[$channo]."High"} = $value2
  933. }
  934. #-- put into device
  935. $hash->{owg_vhigh}->[$channo] = $value2;
  936. }
  937. #-- OWX interface
  938. if( $interface eq "OWX" ){
  939. $ret = OWXAD_SetPage($hash,"alarm");
  940. }elsif( $interface eq "OWX_ASYNC" ){
  941. eval {
  942. OWX_ASYNC_Schedule( $hash, OWXAD_PT_SetPage($hash,"status"));
  943. };
  944. $ret = GP_Catch($@) if $@;
  945. #-- OWFS interface
  946. }elsif( $interface eq "OWServer" ){
  947. $ret = OWFSAD_SetPage($hash,"alarm");
  948. } else {
  949. return "OWAD: Set with wrong IODev type $interface";
  950. }
  951. #-- process results
  952. if( defined($ret) ){
  953. return "OWAD: Could not set device $name, reason: ".$ret;
  954. }
  955. }
  956. #-- process results - we have to reread the device
  957. OWAD_GetValues($hash);
  958. Log 4, "OWAD: Set $hash->{NAME} $key $value";
  959. return undef;
  960. }
  961. ########################################################################################
  962. #
  963. # OWAD_Undef - Implements UndefFn function
  964. #
  965. # Parameter hash = hash of device addressed
  966. #
  967. ########################################################################################
  968. sub OWAD_Undef ($) {
  969. my ($hash) = @_;
  970. delete($main::modules{OWAD}{defptr}{$hash->{OW_ID}});
  971. RemoveInternalTimer($hash);
  972. return undef;
  973. }
  974. ########################################################################################
  975. #
  976. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  977. # via OWFS
  978. #
  979. # Prefix = OWFSAD
  980. #
  981. ########################################################################################
  982. #
  983. # OWFSAD_GetPage - Get one memory page from device
  984. #
  985. # Parameter hash = hash of device addressed
  986. # page = "reading", "alarm" or "status"
  987. # final= 1 if FormatValues is to be called
  988. #
  989. ########################################################################################
  990. sub OWFSAD_GetPage($$$) {
  991. my ($hash,$page,$final) = @_;
  992. #-- ID of the device
  993. my $owx_add = substr($hash->{ROM_ID},0,15);
  994. #-- hash of the busmaster
  995. my $master = $hash->{IODev};
  996. my $name = $hash->{NAME};
  997. my ($rel,$rel2,@ral,@ral2,$i,$an,$vn);
  998. #-- reset presence
  999. $hash->{PRESENT} = 0;
  1000. #=============== get the voltage reading ===============================
  1001. if( $page eq "reading"){
  1002. #-- get values - or should we rather use the uncached ones ?
  1003. $rel = OWServer_Read($master,"/$owx_add/volt.ALL");
  1004. return "no return from OWServer"
  1005. if( !defined($rel) );
  1006. return "empty return from OWServer"
  1007. if( $rel eq "" );
  1008. @ral = split(/,/,$rel);
  1009. return "wrong data length from OWServer"
  1010. if( int(@ral) != 4);
  1011. for( $i=0;$i<int(@owg_fixed);$i++){
  1012. $hash->{owg_val}->[$i]= int($ral[$i]*1000)/1000;
  1013. }
  1014. #=============== get the alarm reading ===============================
  1015. } elsif ( $page eq "alarm" ) {
  1016. #-- get values - or should we rather use the uncached ones ?
  1017. $rel = OWServer_Read($master,"/$owx_add/set_alarm/voltlow.ALL");
  1018. $rel2 = OWServer_Read($master,"/$owx_add/set_alarm/volthigh.ALL");
  1019. return "no return from OWServer"
  1020. if( (!defined($rel)) || (!defined($rel2)) );
  1021. return "empty return from OWServer"
  1022. if( ($rel eq "") || ($rel2 eq "") );
  1023. @ral = split(/,/,$rel);
  1024. @ral2= split(/,/,$rel2);
  1025. return "wrong data length from OWServer"
  1026. if( (int(@ral) != 4) || (int(@ral2) != 4) );
  1027. for( $i=0;$i<int(@owg_fixed);$i++){
  1028. $hash->{owg_vlow}->[$i] = int($ral[$i]*1000+0.5)/1000;
  1029. $hash->{owg_vhigh}->[$i] = int($ral2[$i]*1000+0.5)/1000;
  1030. }
  1031. #=============== get the status reading ===============================
  1032. } elsif ( $page eq "status" ) {
  1033. #-- so far not clear, how to find out which type of operation we have.
  1034. # We therefore ASSUME normal operation
  1035. #-- normal operation
  1036. #-- put into globals
  1037. for( $i=0;$i<int(@owg_fixed);$i++){
  1038. $owg_mode[$i] = "input";
  1039. $owg_resoln[$i] = 16;
  1040. $owg_range[$i] = 5120;
  1041. }
  1042. #-- get values - or should we rather use the uncached ones ?
  1043. $rel = OWServer_Read($master,"/$owx_add/alarm/low.ALL");
  1044. $rel2 = OWServer_Read($master,"/$owx_add/set_alarm/low.ALL");
  1045. return "no return from OWServer"
  1046. if( (!defined($rel)) || (!defined($rel2)) );
  1047. return "empty return from OWServer"
  1048. if( ($rel eq "") || ($rel2 eq "") );
  1049. @ral = split(/,/,$rel);
  1050. @ral2= split(/,/,$rel2);
  1051. return "wrong data length from OWServer"
  1052. if( (int(@ral) != 4) || (int(@ral2) != 4) );
  1053. for( $i=0;$i<int(@owg_fixed);$i++){
  1054. #-- low alarm disabled
  1055. if( $ral2[$i]==0 ){
  1056. $an = 0;
  1057. }else {
  1058. #-- low alarm enabled and not set
  1059. if ( $ral[$i]==0 ){
  1060. $an = 1;
  1061. #-- low alarm enabled and set
  1062. }else{
  1063. $an = 2;
  1064. }
  1065. }
  1066. $hash->{owg_slow}->[$i] = $an;
  1067. }
  1068. #-- get values - or should we rather use the uncached ones ?
  1069. $rel = OWServer_Read($master,"/$owx_add/alarm/high.ALL");
  1070. $rel2 = OWServer_Read($master,"/$owx_add/set_alarm/high.ALL");
  1071. return "no return from OWServer"
  1072. if( (!defined($rel)) || (!defined($rel2)) );
  1073. return "empty return from OWServer"
  1074. if( ($rel eq "") || ($rel2 eq "") );
  1075. @ral = split(/,/,$rel);
  1076. @ral2= split(/,/,$rel2);
  1077. return "wrong data length from OWServer"
  1078. if( (int(@ral) != 4) || (int(@ral2) != 4) );
  1079. for( $i=0;$i<int(@owg_fixed);$i++){
  1080. #-- low alarm disabled
  1081. if( $ral2[$i]==0 ){
  1082. $an = 0;
  1083. }else {
  1084. #-- low alarm enabled and not set
  1085. if ( $ral[$i]==0 ){
  1086. $an = 1;
  1087. #-- low alarm enabled and set
  1088. }else{
  1089. $an = 2;
  1090. }
  1091. }
  1092. $hash->{owg_shigh}->[$i] = $an;
  1093. }
  1094. }
  1095. #-- and now from raw to formatted values
  1096. $hash->{PRESENT} = 1;
  1097. if( $final==1){
  1098. my $value = OWAD_FormatValues($hash);
  1099. Log 5, $value;
  1100. }
  1101. return undef
  1102. }
  1103. ########################################################################################
  1104. #
  1105. # OWFSAD_SetPage - Set one page of device
  1106. #
  1107. # Parameter hash = hash of device addressed
  1108. # page = "alarm" or "status"
  1109. #
  1110. ########################################################################################
  1111. sub OWFSAD_SetPage($$) {
  1112. my ($hash,$page) = @_;
  1113. #-- ID of the device
  1114. my $owx_add = substr($hash->{ROM_ID},0,15);
  1115. #-- hash of the busmaster
  1116. my $master = $hash->{IODev};
  1117. my $name = $hash->{NAME};
  1118. my $i;
  1119. my @ral =(0,0,0,0);
  1120. my @ral2=(0,0,0,0);
  1121. #=============== set the alarm values ===============================
  1122. if ( $page eq "alarm" ) {
  1123. OWServer_Write($master, "/$owx_add/set_alarm/voltlow.ALL",join(',',@{$hash->{owg_vlow}}));
  1124. OWServer_Write($master, "/$owx_add/set_alarm/volthigh.ALL",join(',',@{$hash->{owg_vhigh}}));
  1125. #=============== set the status ===============================
  1126. } elsif ( $page eq "status" ) {
  1127. for( $i=0;$i<int(@owg_fixed);$i++){
  1128. if( $owg_mode[$i] eq "input" ){
  1129. #-- resolution (TODO: check !)
  1130. #
  1131. #-- alarm enabled
  1132. if( defined($hash->{owg_slow}->[$i]) ){
  1133. $ral[$i]=1
  1134. if($hash->{owg_slow}->[$i]>0);
  1135. }
  1136. if( defined($hash->{owg_shigh}->[$i]) ){
  1137. $ral2[$i]=1
  1138. if($hash->{owg_shigh}->[$i]>0);
  1139. }
  1140. }
  1141. }
  1142. OWServer_Write($master, "/$owx_add/set_alarm/low.ALL",join(',',@ral));
  1143. OWServer_Write($master, "/$owx_add/set_alarm/high.ALL",join(',',@ral2));
  1144. #=============== wrong page write attempt ===============================
  1145. } else {
  1146. return "wrong memory page write attempt";
  1147. }
  1148. return undef;
  1149. }
  1150. ########################################################################################
  1151. #
  1152. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  1153. # directly to the FHEM server
  1154. #
  1155. # Prefix = OWXAD
  1156. #
  1157. ########################################################################################
  1158. #
  1159. # OWXAD_BinValues - Process reading from one device - translate binary into raw
  1160. #
  1161. # Parameter hash = hash of device addressed
  1162. # context = mode for evaluating the binary data
  1163. # proc = processing instruction, also passed to OWX_Read.
  1164. # bitwise interpretation !!
  1165. # if 0, nothing special
  1166. # if 1 = bit 0, a reset will be performed not only before, but also after
  1167. # the last operation in OWX_Read
  1168. # if 2 = bit 1, the initial reset of the bus will be suppressed
  1169. # if 8 = bit 3, the fillup of the data with 0xff will be suppressed
  1170. # if 16= bit 4, the insertion will be at the top of the queue
  1171. # owx_dev = ROM ID of slave device
  1172. # crcpart = part of the data that needs to be part of the CRC check
  1173. # numread = number of bytes to receive
  1174. # res = result string
  1175. #
  1176. #
  1177. ########################################################################################
  1178. sub OWXAD_BinValues($$$$$$$) {
  1179. my ($hash, $context, $proc, $owx_dev, $crcpart, $numread, $res) = @_;
  1180. #-- hash of the busmaster
  1181. my $master = $hash->{IODev};
  1182. my $name = $hash->{NAME};
  1183. my @data=[];
  1184. my $value;
  1185. my $msg;
  1186. OWX_WDBG($name,"OWXAD_BinValues called for device $name in context $context with ",$res)
  1187. if( $main::owx_debug>2 );
  1188. my $final = ($context =~ /\.final$/ );
  1189. my ($ow_thn,$ow_tln);
  1190. #-- process results
  1191. @data=split(//,$res);
  1192. if (@data != 10){
  1193. $msg="$name returns invalid data length, ".int(@data)." instead of 10 bytes ";
  1194. }elsif (OWX_CRC16($crcpart.substr($res,0,8),$data[8],$data[9])==0){
  1195. $msg="$name returns invalid CRC "
  1196. }else{
  1197. $msg="No error ";
  1198. }
  1199. OWX_WDBG($name,"OWXAD_BinValues: ".$msg,$crcpart)
  1200. if( $main::owx_debug>2 );
  1201. #=============== get the voltage reading ===============================
  1202. if( $context =~ /^ds2450.getreading/ ){
  1203. for( my $i=0;$i<int(@owg_fixed);$i++){
  1204. $hash->{owg_val}->[$i]= (ord($data[2*$i])+256*ord($data[1+2*$i]) )/(1<<$owg_resoln[$i]) * $owg_range[$i]/1000;
  1205. }
  1206. #=============== get the alarm reading ===============================
  1207. } elsif ( $context =~ /^ds2450.getalarm/ ){
  1208. for( my $i=0;$i<int(@owg_fixed);$i++){
  1209. $hash->{owg_vlow}->[$i] = int(ord($data[2*$i])/256 * $owg_range[$i]+0.5)/1000;
  1210. $hash->{owg_vhigh}->[$i] = int(ord($data[1+2*$i])/256 * $owg_range[$i]+0.5)/1000;
  1211. }
  1212. #=============== get the status reading ===============================
  1213. } elsif ( $context =~ /^ds2450.getstatus/ ) {
  1214. my ($sb1,$sb2);
  1215. for( my $i=0;$i<int(@owg_fixed);$i++){
  1216. $sb1 = ord($data[2*$i]);
  1217. $sb2 = ord($data[1+2*$i]);
  1218. #Log 1,"VOR TEST sb1=$sb1 sb2=$sb2 UND mit 128 ist ".($sb1 && 128);
  1219. #-- normal operation
  1220. if( ($sb1 && 128)==0) {
  1221. #-- put into globals
  1222. $owg_mode[$i] = "input";
  1223. $owg_resoln[$i] = ($sb1 & 15);
  1224. $owg_resoln[$i] = 16
  1225. if ($owg_resoln[$i] == 0);
  1226. $owg_range[$i] = ($sb2 & 1) ? 5120 : 2560;
  1227. my $an;
  1228. #-- low alarm disabled
  1229. if( ($sb2 & 4)==0 ){
  1230. $an = 0;
  1231. }else {
  1232. #-- low alarm enabled and not set
  1233. if ( ($sb2 & 16)==0 ){
  1234. $an = 1;
  1235. #-- low alarm enabled and set
  1236. }else{
  1237. $an = 2;
  1238. }
  1239. }
  1240. $hash->{owg_slow}->[$i]= $an;
  1241. #-- high alarm disabled
  1242. if( ($sb2 & 8)==0 ){
  1243. $an = 0;
  1244. }else {
  1245. #-- high alarm enabled and not set
  1246. if ( ($sb2 & 32)==0 ){
  1247. $an = 1;
  1248. #-- high alarm enabled and set
  1249. }else{
  1250. $an = 2;
  1251. }
  1252. }
  1253. $hash->{owg_shigh}->[$i]= $an;
  1254. #-- output operation
  1255. } else {
  1256. $owg_mode[$i] = "output";
  1257. #-- assemble status string
  1258. $hash->{owg_status}->[$i] = $owg_mode[$i].", ";
  1259. $hash->{owg_status}->[$i] .= ($sb1 & 64 ) ? "ON" : "OFF";
  1260. }
  1261. }
  1262. }
  1263. #-- and now from raw to formatted values
  1264. $hash->{PRESENT} = 1;
  1265. if( $final ){
  1266. my $value = OWAD_FormatValues($hash);
  1267. }
  1268. return undef
  1269. }
  1270. ########################################################################################
  1271. #
  1272. # OWXAD_GetPage - Get one memory page from device
  1273. #
  1274. # Parameter hash = hash of device addressed
  1275. # page = "reading", "alarm" or "status"
  1276. # final= 1 if FormatValues is to be called
  1277. #
  1278. ########################################################################################
  1279. sub OWXAD_GetPage($$$@) {
  1280. my ($hash,$page,$final,$sync) = @_;
  1281. my ($select, $res, $res2, $res3, @data, $an, $vn);
  1282. #-- ID of the device, hash of the busmaster
  1283. my $owx_dev = $hash->{ROM_ID};
  1284. my $master = $hash->{IODev};
  1285. my ($i,$j,$k);
  1286. #-- reset presence
  1287. $hash->{PRESENT} = 0;
  1288. #=============== get the voltage reading ===============================
  1289. if( $page eq "reading") {
  1290. #-- issue the match ROM command \x55 and the start conversion command
  1291. OWX_Reset($master);
  1292. $res= OWX_Complex($master,$owx_dev,"\x3C\x0F\x00\xFF\xFF",0);
  1293. if( $res eq 0 ){
  1294. return "not accessible for conversion";
  1295. }
  1296. #-- conversion needs some 5 ms per channel
  1297. select(undef,undef,undef,0.02);
  1298. #-- issue the match ROM command \x55 and the read conversion page command
  1299. # \xAA\x00\x00
  1300. $select="\xAA\x00\x00";
  1301. #=============== get the alarm reading ===============================
  1302. } elsif ( $page eq "alarm" ) {
  1303. #-- issue the match ROM command \x55 and the read alarm page command
  1304. # \xAA\x10\x00
  1305. $select="\xAA\x10\x00";
  1306. #=============== get the status reading ===============================
  1307. } elsif ( $page eq "status" ) {
  1308. #-- issue the match ROM command \x55 and the read status memory page command
  1309. # \xAA\x08\x00 r
  1310. $select="\xAA\x08\x00";
  1311. #=============== wrong value requested ===============================
  1312. } else {
  1313. return "wrong memory page requested from $owx_dev";
  1314. }
  1315. my $context = "ds2450.get".$page.($final ? ".final" : "");
  1316. #-- OLD OWX interface
  1317. if( !$master->{ASYNCHRONOUS} ){
  1318. #-- reset the bus
  1319. OWX_Reset($master);
  1320. #-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes
  1321. $res=OWX_Complex($master,$owx_dev,$select,10);
  1322. return "$owx_dev not accessible in reading page $page"
  1323. if( $res eq 0 );
  1324. return "$owx_dev has returned invalid data"
  1325. if( length($res)!=22);
  1326. #-- for processing we also need the 3 command bytes
  1327. return OWXAD_BinValues($hash,$context,1,undef,$owx_dev,$select,substr($res,12,10));
  1328. #-- NEW OWX interface
  1329. }else{
  1330. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1331. # 1 additional reset after last action
  1332. OWX_Qomplex($master, $hash, $context, 1, $owx_dev, $select, $select, 10, 12, \&OWXAD_BinValues, 0);
  1333. return undef;
  1334. }
  1335. }
  1336. ########################################################################################
  1337. #
  1338. # OWXAD_SetPage - Set one page of device
  1339. #
  1340. # Parameter hash = hash of device addressed
  1341. # page = "alarm" or "status"
  1342. #
  1343. ########################################################################################
  1344. sub OWXAD_SetPage($$) {
  1345. my ($hash,$page) = @_;
  1346. my ($select, $res, $res2, $res3, @data);
  1347. #-- ID of the device, hash of the busmaster
  1348. my $owx_dev = $hash->{ROM_ID};
  1349. my $master = $hash->{IODev};
  1350. my ($i,$j,$k);
  1351. #=============== set the alarm values ===============================
  1352. if ( $page eq "alarm" ) {
  1353. #-- issue the match ROM command \x55 and the set alarm page command
  1354. # \x55\x10\x00 reading 8 data bytes and 2 CRC bytes
  1355. $select="\x55\x10\x00";
  1356. for( $i=0;$i<int(@owg_fixed);$i++){
  1357. $select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vlow}->[$i]*256000/$owg_range[$i]);
  1358. $select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vhigh}->[$i]*256000/$owg_range[$i]);
  1359. }
  1360. #++Use of uninitialized value within @owg_vlow in multiplication at
  1361. #++/usr/share/fhem/FHEM/21_OWAD.pm line 1362.
  1362. #=============== set the status ===============================
  1363. } elsif ( $page eq "status" ) {
  1364. my ($sb1,$sb2)=(0,0);
  1365. #-- issue the match ROM command \x55 and the set status memory page command
  1366. # \x55\x08\x00 reading 8 data bytes and 2 CRC bytes
  1367. $select="\x55\x08\x00";
  1368. for( $i=0;$i<int(@owg_fixed);$i++){
  1369. #if( $owg_mode[$i] eq "input" ){
  1370. if( 1 > 0){
  1371. #-- resolution (TODO: check !)
  1372. $sb1 = $owg_resoln[$i] & 15;
  1373. #-- alarm enabled
  1374. if( defined($hash->{owg_slow}->[$i]) ){
  1375. $sb2 = ( $hash->{owg_slow}->[$i] ne 0 ) ? 4 : 0;
  1376. }
  1377. if( defined($hash->{owg_shigh}->[$i]) ){
  1378. $sb2 += ( $hash->{owg_shigh}->[$i] ne 0 ) ? 8 : 0;
  1379. }
  1380. #-- range
  1381. $sb2 |= 1
  1382. if( $owg_range[$i] > 2560 );
  1383. } else {
  1384. $sb1 = 128;
  1385. $sb2 = 0;
  1386. }
  1387. $select .= sprintf "%c\xFF\xFF\xFF",$sb1;
  1388. $select .= sprintf "%c\xFF\xFF\xFF",$sb2;
  1389. }
  1390. #=============== wrong page write attempt ===============================
  1391. } else {
  1392. return "wrong memory page write attempt";
  1393. }
  1394. #-- OLD OWX interface
  1395. if( !$master->{ASYNCHRONOUS} ){
  1396. OWX_Reset($master);
  1397. $res=OWX_Complex($master,$owx_dev,$select,0);
  1398. if( $res eq 0 ){
  1399. return "device $owx_dev not accessible for writing";
  1400. }
  1401. #-- NEW OWX interface
  1402. }else{
  1403. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1404. OWX_Qomplex($master, $hash, undef, 0, $owx_dev, $select, 0, 0, 0, undef, 0);
  1405. }
  1406. return undef;
  1407. }
  1408. ########################################################################################
  1409. #
  1410. # OWXAD_PT_GetPage - Get one memory page from device
  1411. #
  1412. # Parameter hash = hash of device addressed
  1413. # page = "reading", "alarm" or "status"
  1414. # final= 1 if FormatValues is to be called
  1415. #
  1416. ########################################################################################
  1417. sub OWXAD_PT_GetPage($$$) {
  1418. my ($hash,$page,$final) = @_;
  1419. return PT_THREAD(sub {
  1420. my ($thread) = @_;
  1421. my ($res, $res2, $res3, @data, $an, $vn);
  1422. #-- ID of the device, hash of the busmaster
  1423. my $owx_dev = $hash->{ROM_ID};
  1424. my $master = $hash->{IODev};
  1425. my ($i,$j,$k);
  1426. PT_BEGIN($thread);
  1427. #=============== get the voltage reading ===============================
  1428. if( $page eq "reading") {
  1429. #-- issue the match ROM command \x55 and the start conversion command
  1430. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, "\x3C\x0F\x00\xFF\xFF", 0 );
  1431. $thread->{ExecuteTime} = gettimeofday() + 0.07; # was 0.02
  1432. PT_WAIT_THREAD($thread->{pt_execute});
  1433. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1434. PT_YIELD_UNTIL(gettimeofday() >= $thread->{ExecuteTime});
  1435. delete $thread->{ExecuteTime};
  1436. #-- issue the match ROM command \x55 and the read conversion page command
  1437. # \xAA\x00\x00
  1438. $thread->{'select'}="\xAA\x00\x00";
  1439. #=============== get the alarm reading ===============================
  1440. } elsif ( $page eq "alarm" ) {
  1441. #-- issue the match ROM command \x55 and the read alarm page command
  1442. # \xAA\x10\x00
  1443. $thread->{'select'}="\xAA\x10\x00";
  1444. #=============== get the status reading ===============================
  1445. } elsif ( $page eq "status" ) {
  1446. #-- issue the match ROM command \x55 and the read status memory page command
  1447. # \xAA\x08\x00 r
  1448. $thread->{'select'}="\xAA\x08\x00";
  1449. #=============== wrong value requested ===============================
  1450. } else {
  1451. die "wrong memory page requested from $owx_dev";
  1452. }
  1453. #-- reading 9 + 3 + 8 data bytes and 2 CRC bytes = 22 bytes
  1454. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $thread->{'select'}, 10 );
  1455. PT_WAIT_THREAD($thread->{pt_execute});
  1456. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1457. my $response = $thread->{pt_execute}->PT_RETVAL();
  1458. my $res = OWXAD_BinValues($hash,"ds2450.get".$page.($final ? ".final" : ""),1,$owx_dev,$thread->{'select'},10,$response);
  1459. if ($res) {
  1460. die $res;
  1461. }
  1462. PT_END;
  1463. });
  1464. }
  1465. ########################################################################################
  1466. #
  1467. # OWXAD_PT_SetPage - Set one page of device
  1468. #
  1469. # Parameter hash = hash of device addressed
  1470. # page = "alarm" or "status"
  1471. #
  1472. ########################################################################################
  1473. sub OWXAD_PT_SetPage($$) {
  1474. my ($hash,$page) = @_;
  1475. return PT_THREAD(sub {
  1476. my ($thread) = @_;
  1477. my ($select, $res, $res2, $res3, @data);
  1478. #-- ID of the device, hash of the busmaster
  1479. my $owx_dev = $hash->{ROM_ID};
  1480. my $master = $hash->{IODev};
  1481. my ($i,$j,$k);
  1482. PT_BEGIN($thread);
  1483. #=============== set the alarm values ===============================
  1484. if ( $page eq "alarm" ) {
  1485. #-- issue the match ROM command \x55 and the set alarm page command
  1486. # \x55\x10\x00 reading 8 data bytes and 2 CRC bytes
  1487. $select="\x55\x10\x00";
  1488. for( $i=0;$i<int(@owg_fixed);$i++){
  1489. $select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vlow}->[$i]*256000/$owg_range[$i]);
  1490. $select .= sprintf "%c\xFF\xFF\xFF",int($hash->{owg_vhigh}->[$i]*256000/$owg_range[$i]);
  1491. }
  1492. #++Use of uninitialized value within @owg_vlow in multiplication at
  1493. #++/usr/share/fhem/FHEM/21_OWAD.pm line 1362.
  1494. #=============== set the status ===============================
  1495. } elsif ( $page eq "status" ) {
  1496. my ($sb1,$sb2)=(0,0);
  1497. #-- issue the match ROM command \x55 and the set status memory page command
  1498. # \x55\x08\x00 reading 8 data bytes and 2 CRC bytes
  1499. $select="\x55\x08\x00";
  1500. for( $i=0;$i<int(@owg_fixed);$i++){
  1501. #if( $owg_mode[$i] eq "input" ){
  1502. if( 1 > 0){
  1503. #-- resolution (TODO: check !)
  1504. $sb1 = $owg_resoln[$i] & 15;
  1505. #-- alarm enabled
  1506. if( defined($hash->{owg_slow}->[$i]) ){
  1507. $sb2 = ( $hash->{owg_slow}->[$i] ne 0 ) ? 4 : 0;
  1508. }
  1509. if( defined($hash->{owg_shigh}->[$i]) ){
  1510. $sb2 += ( $hash->{owg_shigh}->[$i] ne 0 ) ? 8 : 0;
  1511. }
  1512. #-- range
  1513. $sb2 |= 1
  1514. if( $owg_range[$i] > 2560 );
  1515. } else {
  1516. $sb1 = 128;
  1517. $sb2 = 0;
  1518. }
  1519. $select .= sprintf "%c\xFF\xFF\xFF",$sb1;
  1520. $select .= sprintf "%c\xFF\xFF\xFF",$sb2;
  1521. }
  1522. #=============== wrong page write attempt ===============================
  1523. } else {
  1524. PT_EXIT("wrong memory page write attempt");
  1525. }
  1526. #"setpage"
  1527. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev, $select, 0 );
  1528. PT_WAIT_THREAD($thread->{pt_execute});
  1529. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1530. PT_END;
  1531. });
  1532. }
  1533. 1;
  1534. =pod
  1535. =begin html
  1536. <a name="OWAD"></a>
  1537. <h3>OWAD</h3>
  1538. <p>FHEM module to commmunicate with 1-Wire A/D converters<br /><br />
  1539. <br />This 1-Wire module works with the OWX interface module or with the OWServer interface module
  1540. (prerequisite: Add this module's name to the list of clients in OWServer).
  1541. Please define an <a href="#OWX">OWX</a> device or <a href="#OWServer">OWServer</a> device first. <br/></p>
  1542. <br /><h4>Example</h4>
  1543. <p>
  1544. <code>define OWX_AD OWAD 724610000000 45</code>
  1545. <br />
  1546. <code>attr OWX_AD DAlarm high</code>
  1547. <br />
  1548. <code>attr OWX_AD DName humidity</code>
  1549. <br />
  1550. <code>attr OWX_AD DUnit %</code>
  1551. <br />
  1552. <code>attr OWX_AD DFunction VD*31.907097-0.8088</code>
  1553. <br />
  1554. <code>attr OWX_AD DHigh 50.0</code>
  1555. <br />
  1556. </p><br />
  1557. <a name="OWADdefine"></a>
  1558. <h4>Define</h4>
  1559. <p>
  1560. <code>define &lt;name&gt; OWAD [&lt;model&gt;] &lt;id&gt; [&lt;interval&gt;]</code> or <br/>
  1561. <code>define &lt;name&gt; OWAD &lt;fam&gt;.&lt;id&gt; [&lt;interval&gt;]</code>
  1562. <br /><br /> Define a 1-Wire A/D converter.<br /><br /></p>
  1563. <ul>
  1564. <li>
  1565. <code>[&lt;model&gt;]</code><br /> Defines the A/D converter model (and thus 1-Wire
  1566. family id), currently the following values are permitted: <ul>
  1567. <li>model DS2450 with family id 20 (default if the model parameter is
  1568. omitted)</li>
  1569. </ul>
  1570. </li>
  1571. <li>
  1572. <code>&lt;fam&gt;</code>
  1573. <br />2-character unique family id, see above
  1574. </li>
  1575. <li>
  1576. <code>&lt;id&gt;</code>
  1577. <br />12-character unique ROM id of the converter device without family id and CRC
  1578. code </li>
  1579. <li>
  1580. <code>&lt;interval&gt;</code>
  1581. <br />Measurement interval in seconds. The default is 300 seconds. </li>
  1582. </ul>
  1583. <br />
  1584. <a name="OWADset"></a>
  1585. <h4>Set</h4>
  1586. <ul>
  1587. <li><a name="owad_interval">
  1588. <code>set &lt;name&gt; interval &lt;int&gt;</code></a><br /> Measurement
  1589. interval in seconds. The default is 300 seconds. </li>
  1590. </ul>
  1591. <br />
  1592. <a name="OWADget"></a>
  1593. <h4>Get</h4>
  1594. <ul>
  1595. <li><a name="owad_id">
  1596. <code>get &lt;name&gt; id</code></a>
  1597. <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
  1598. <li><a name="owad_present">
  1599. <code>get &lt;name&gt; present</code>
  1600. </a>
  1601. <br /> Returns 1 if this 1-Wire device is present, otherwise 0. </li>
  1602. <li><a name="owad_interval2">
  1603. <code>get &lt;name&gt; interval</code></a><br />Returns measurement interval in
  1604. seconds. </li>
  1605. <li><a name="owad_reading">
  1606. <code>get &lt;name&gt; reading</code></a><br />Obtain the measuement values. </li>
  1607. <li><a name="owad_alarm">
  1608. <code>get &lt;name&gt; alarm</code></a><br />Obtain the alarm values. </li>
  1609. <li><a name="owad_status">
  1610. <code>get &lt;name&gt; status</code></a><br />Obtain the i/o status values.
  1611. </li>
  1612. </ul>
  1613. <br />
  1614. <a name="OWADattr"></a>
  1615. <h4>Attributes</h4>
  1616. <ul>
  1617. <li><a name="owad_stateAL0"><code>attr &lt;name&gt; stateAL0 &lt;string&gt;</code></a>
  1618. <br />character string for denoting low normal condition, default is empty </li>
  1619. <li><a name="owad_stateAH0"><code>attr &lt;name&gt; stateAH0 &lt;string&gt;</code></a>
  1620. <br />character string for denoting high normal condition, default is empty </li>
  1621. <li><a name="owad_stateAL1"><code>attr &lt;name&gt; stateAL1 &lt;string&gt;</code></a>
  1622. <br />character string for denoting low alarm condition, default is ↓</li>
  1623. <li><a name="owad_stateAH1"><code>attr &lt;name&gt; stateAH1 &lt;string&gt;</code></a>
  1624. <br />character string for denoting high alarm condition, default is ↑</li>
  1625. </ul> For each of the following attributes, the channel identification A,B,C,D may be used. <ul>
  1626. <li><a name="owad_cname"><code>attr &lt;name&gt; &lt;channel&gt;Name
  1627. &lt;string&gt;[|&lt;string&gt;]</code></a>
  1628. <br />name for the channel [|short name used in state reading]. </li>
  1629. <li><a name="owad_cunit"><code>attr &lt;name&gt; &lt;channel&gt;Unit
  1630. &lt;string&gt;</code></a>
  1631. <br />unit of measurement for this channel used in state reading (default "V", set to "none" for empty). </li>
  1632. <li><a name="owad_cfunction"> <code>attr &lt;name&gt; &lt;channel&gt;Function
  1633. &lt;string&gt;</code></a>
  1634. <br />arbitrary functional expression involving the variables VA,VB,VC,VD. VA is replaced by
  1635. the (raw) measured voltage in channel A, etc. This attribute allows linearization of measurement
  1636. curves as well as the mixing of various channels. </li>
  1637. <li><a name="owad_calarm"><code>attr &lt;name&gt; &lt;channel&gt;Alarm
  1638. &lt;string&gt;</code></a>
  1639. <br />alarm setting in this channel, either both, low, high or none (default). </li>
  1640. <li><a name="owad_clow"><code>attr &lt;name&gt; &lt;channel&gt;Low
  1641. &lt;float&gt;</code></a>
  1642. <br />measurement value for low alarm. </li>
  1643. <li><a name="owad_chigh"><code>attr &lt;name&gt; &lt;channel&gt;High
  1644. &lt;float&gt;</code></a>
  1645. <br />measurement value for highalarm. </li>
  1646. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1647. </ul>
  1648. =end html
  1649. =cut