21_OWSWITCH.pm 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767
  1. ########################################################################################
  2. #
  3. # OWSWITCH.pm
  4. #
  5. # FHEM module to commmunicate with 1-Wire adressable switches DS2413, DS206, DS2408
  6. #
  7. # Prof. Dr. Peter A. Henning
  8. # Norbert Truchsess
  9. #
  10. # $Id: 21_OWSWITCH.pm 11216 2016-04-10 08:12:19Z pahenning $
  11. #
  12. ########################################################################################
  13. #
  14. # define <name> OWSWITCH [<model>] <ROM_ID> [interval] or OWSWITCH <fam>.<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. # DS2413. Allowed values are DS2413, DS2406, DS2408
  20. # <fam> is a 1-Wire family id, currently allowed values are 12, 29, 3A
  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> input <channel-name> => state for channel (name A, B or defined channel name)
  29. # note: this value reflects the measured value, not necessarily the one set as
  30. # output state, because the output transistors are open collector switches. A measured
  31. # state of 1 = OFF therefore corresponds to an output state of 1 = OFF, but a measured
  32. # state of 0 = ON can also be due to an external shortening of the output.
  33. # get <name> gpio => values for channels
  34. # get <name> version => OWX version number
  35. #
  36. # set <name> interval => set period for measurement
  37. # set <name> output <channel-name> on|off|on-for-timer <int>|on-for-timer <int>
  38. # => set value for channel (name A, B or defined channel name)
  39. # note: 1 = OFF, 0 = ON in normal usage. See also the note above
  40. # ON-for-timer/OFF-for-timer will set the desired value only for <int> seconds
  41. # and then will return to the opposite value.
  42. # set <name> gpio value => set values for channels (3 = both OFF, 1 = B ON 2 = A ON 0 = both ON)
  43. # set <name> init yes => re-initialize device
  44. #
  45. # Additional attributes are defined in fhem.cfg, in some cases per channel, where <channel>=A,B
  46. # Note: attributes are read only during initialization procedure - later changes are not used.
  47. #
  48. # attr <name> stateS <string> = character string denoting external shortening condition, default is X
  49. # attr <name> <channel>Name <string>|<string> = name for the channel [|short name used in state reading]
  50. # attr <name> <channel>Unit <string>|<string> = values to display in state variable for on|off condition
  51. #
  52. ########################################################################################
  53. #
  54. # This programm is free software; you can redistribute it and/or modify
  55. # it under the terms of the GNU General Public License as published by
  56. # the Free Software Foundation; either version 2 of the License, or
  57. # (at your option) any later version.
  58. #
  59. # The GNU General Public License can be found at
  60. # http://www.gnu.org/copyleft/gpl.html.
  61. # A copy is found in the textfile GPL.txt and important notices to the license
  62. # from the author is found in LICENSE.txt distributed with these scripts.
  63. #
  64. # This script is distributed in the hope that it will be useful,
  65. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  66. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  67. # GNU General Public License for more details.
  68. #
  69. ########################################################################################
  70. package main;
  71. use vars qw{%attr %defs %modules $readingFnAttributes $init_done};
  72. use strict;
  73. use warnings;
  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 Log($$);
  85. my $owx_version="6.02";
  86. #-- fixed raw channel name, flexible channel name
  87. my @owg_fixed = ("A","B","C","D","E","F","G","H");
  88. my @owg_channel = ("A","B","C","D","E","F","G","H");
  89. my %gets = (
  90. "id" => "",
  91. "present" => "",
  92. "interval" => "",
  93. "input" => "",
  94. "gpio" => "",
  95. "version" => ""
  96. );
  97. my %sets = (
  98. "interval" => "",
  99. "output" => "",
  100. "gpio" => "",
  101. "init" => ""
  102. );
  103. my %updates = (
  104. "present" => "",
  105. "gpio" => ""
  106. );
  107. my %cnumber = (
  108. "DS2413" => 2,
  109. "DS2406" => 2,
  110. "DS2408" => 8
  111. );
  112. ########################################################################################
  113. #
  114. # The following subroutines are independent of the bus interface
  115. #
  116. # Prefix = OWSWITCH
  117. #
  118. ########################################################################################
  119. #
  120. # OWSWITCH_Initialize
  121. #
  122. # Parameter: hash = hash of device addressed
  123. #
  124. ########################################################################################
  125. sub OWSWITCH_Initialize ($) {
  126. my ($hash) = @_;
  127. $hash->{DefFn} = "OWSWITCH_Define";
  128. $hash->{UndefFn} = "OWSWITCH_Undef";
  129. $hash->{GetFn} = "OWSWITCH_Get";
  130. $hash->{SetFn} = "OWSWITCH_Set";
  131. $hash->{NotifyFn}= "OWSWITCH_Notify";
  132. $hash->{InitFn} = "OWSWITCH_Init";
  133. $hash->{AttrFn} = "OWSWITCH_Attr";
  134. my $attlist = "IODev do_not_notify:0,1 showtime:0,1 model:DS2413,DS2406,DS2408 ".
  135. "stateS interval ".
  136. $readingFnAttributes;
  137. #-- initial list of attributes
  138. for( my $i=0;$i<8;$i++ ){
  139. $attlist .= " ".$owg_fixed[$i]."Name";
  140. $attlist .= " ".$owg_fixed[$i]."Unit";
  141. }
  142. $hash->{AttrList} = $attlist;
  143. #-- channel values - always the raw input resp. output values from the device
  144. $hash->{owg_val} = [];
  145. $hash->{owg_vax} = [];
  146. #-- make sure OWX is loaded so OWX_CRC is available if running with OWServer
  147. main::LoadModule("OWX");
  148. }
  149. #########################################################################################
  150. #
  151. # OWSWITCH_Define - Implements DefFn function
  152. #
  153. # Parameter: hash = hash of device addressed, def = definition string
  154. #
  155. #########################################################################################
  156. sub OWSWITCH_Define ($$) {
  157. my ($hash, $def) = @_;
  158. # define <name> OWSWITCH [<model>] <id> [interval]
  159. # e.g.: define flow OWSWITCH 525715020000 300
  160. my @a = split("[ \t][ \t]*", $def);
  161. my ($name,$model,$fam,$id,$crc,$interval,$scale,$ret);
  162. #-- default
  163. $name = $a[0];
  164. $interval = 300;
  165. $scale = "";
  166. $ret = "";
  167. #-- check syntax
  168. return "OWSWITCH: Wrong syntax, must be define <name> OWSWITCH [<model>] <id> [interval] or OWSWITCH <fam>.<id> [interval]"
  169. if(int(@a) < 2 || int(@a) > 5);
  170. #-- different types of definition allowed
  171. my $a2 = $a[2];
  172. my $a3 = defined($a[3]) ? $a[3] : "";
  173. #-- no model, 12 characters
  174. if( $a2 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  175. $model = "DS2413";
  176. CommandAttr (undef,"$name model DS2413");
  177. $fam = "3A";
  178. $id = $a[2];
  179. if(int(@a)>=4) { $interval = $a[3]; }
  180. #-- no model, 2+12 characters
  181. } elsif( $a2 =~ m/^[0-9|a-f|A-F]{2}\.[0-9|a-f|A-F]{12}$/ ) {
  182. $fam = substr($a[2],0,2);
  183. $id = substr($a[2],3);
  184. if(int(@a)>=4) { $interval = $a[3]; }
  185. if( $fam eq "3A" ){
  186. $model = "DS2413";
  187. CommandAttr (undef,"$name model DS2413");
  188. }elsif( $fam eq "12" ){
  189. $model = "DS2406";
  190. CommandAttr (undef,"$name model DS2406");
  191. }elsif( $fam eq "29" ){
  192. $model = "DS2408";
  193. CommandAttr (undef,"$name model DS2408");
  194. }else{
  195. return "OWSWITCH: Wrong 1-Wire device family $fam";
  196. }
  197. #-- model, 12 characters
  198. } elsif( $a3 =~ m/^[0-9|a-f|A-F]{12}$/ ) {
  199. $model = $a[2];
  200. $id = $a[3];
  201. if(int(@a)>=5) { $interval = $a[4]; }
  202. if( $model eq "DS2413" ){
  203. $fam = "3A";
  204. CommandAttr (undef,"$name model DS2413");
  205. }elsif( $model eq "DS2406" ){
  206. $fam = "12";
  207. CommandAttr (undef,"$name model DS2406");
  208. }elsif( $model eq "DS2408" ){
  209. $fam = "29";
  210. CommandAttr (undef,"$name model DS2408");
  211. }else{
  212. return "OWSWITCH: Wrong 1-Wire device model $model";
  213. }
  214. } else {
  215. return "OWSWITCH: $a[0] ID $a[2] invalid, specify a 12 or 2.12 digit value";
  216. }
  217. #-- determine CRC Code - only if this is a direct interface
  218. $crc = sprintf("%02x",OWX_CRC($fam.".".$id."00"));
  219. #-- Define device internals
  220. $hash->{ROM_ID} = "$fam.$id.$crc";
  221. $hash->{OW_ID} = $id;
  222. $hash->{OW_FAMILY} = $fam;
  223. $hash->{PRESENT} = 0;
  224. $hash->{INTERVAL} = $interval;
  225. #-- Couple to I/O device
  226. AssignIoPort($hash);
  227. if( !defined($hash->{IODev}) or !defined($hash->{IODev}->{NAME}) ){
  228. return "OWSWITCH: Warning, no 1-Wire I/O device found for $name.";
  229. } else {
  230. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0; #-- false for now
  231. }
  232. $main::modules{OWSWITCH}{defptr}{$id} = $hash;
  233. #--
  234. readingsSingleUpdate($hash,"state","defined",1);
  235. Log 3, "OWSWITCH: Device $name defined.";
  236. $hash->{NOTIFYDEV} = "global";
  237. if ($init_done) {
  238. OWSWITCH_Init($hash);
  239. }
  240. return undef;
  241. }
  242. ########################################################################################
  243. #
  244. # OWSWITCH_Notify - Implements Notify function
  245. #
  246. # Parameter: hash = hash of device addressed, def = definition string
  247. #
  248. #########################################################################################
  249. sub OWSWITCH_Notify ($$) {
  250. my ($hash,$dev) = @_;
  251. if( grep(m/^(INITIALIZED|REREADCFG)$/, @{$dev->{CHANGED}}) ) {
  252. OWSWITCH_Init($hash);
  253. } elsif( grep(m/^SAVE$/, @{$dev->{CHANGED}}) ) {
  254. }
  255. }
  256. ########################################################################################
  257. #
  258. # OWSWITCH_Init - Implements Init function
  259. #
  260. # Parameter: hash = hash of device addressed, def = definition string
  261. #
  262. #########################################################################################
  263. sub OWSWITCH_Init ($) {
  264. my ($hash)=@_;
  265. #-- Start timer for updates
  266. RemoveInternalTimer($hash);
  267. InternalTimer(gettimeofday()+10, "OWSWITCH_GetValues", $hash, 0);
  268. return undef;
  269. }
  270. #######################################################################################
  271. #
  272. # OWSWITCH_Attr - Set one attribute value for device
  273. #
  274. # Parameter: hash = hash of device addressed
  275. # a = argument array
  276. #
  277. ########################################################################################
  278. sub OWSWITCH_Attr(@) {
  279. my ($do,$name,$key,$value) = @_;
  280. my $hash = $defs{$name};
  281. my $ret;
  282. if ( $do eq "set") {
  283. ARGUMENT_HANDLER: {
  284. #-- interval modified at runtime
  285. $key eq "interval" and do {
  286. #-- check value
  287. return "OWSWITCH: Set with short interval, must be > 1" if(int($value) < 1);
  288. #-- update timer
  289. $hash->{INTERVAL} = $value;
  290. if ($init_done) {
  291. RemoveInternalTimer($hash);
  292. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWSWITCH_GetValues", $hash, 0);
  293. }
  294. last;
  295. };
  296. $key eq "IODev" and do {
  297. AssignIoPort($hash,$value);
  298. if( defined($hash->{IODev}) ) {
  299. $hash->{ASYNC} = $hash->{IODev}->{TYPE} eq "OWX_ASYNC" ? 1 : 0;
  300. if ($init_done) {
  301. OWSWITCH_Init($hash);
  302. }
  303. }
  304. last;
  305. };
  306. }
  307. }
  308. return $ret;
  309. }
  310. ########################################################################################
  311. #
  312. # OWSWITCH_ChannelNames - find the real channel names
  313. #
  314. # Parameter: hash = hash of device addressed
  315. #
  316. ########################################################################################
  317. sub OWSWITCH_ChannelNames($) {
  318. my ($hash) = @_;
  319. my $name = $hash->{NAME};
  320. my $state = $hash->{READINGS}{"state"}{VAL};
  321. my ($cname,@cnama,$unit,@unarr);
  322. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  323. #-- name
  324. $cname = defined($attr{$name}{$owg_fixed[$i]."Name"}) ? $attr{$name}{$owg_fixed[$i]."Name"} : "$owg_fixed[$i]";
  325. @cnama = split(/\|/,$cname);
  326. if( int(@cnama)!=2){
  327. push(@cnama,$cnama[0]);
  328. }
  329. #-- put into readings
  330. $owg_channel[$i] = $cnama[0];
  331. $hash->{READINGS}{$owg_channel[$i]}{ABBR} = $cnama[1];
  332. #-- unit
  333. my $unit = defined($attr{$name}{$owg_fixed[$i]."Unit"}) ? $attr{$name}{$owg_fixed[$i]."Unit"} : "ON|OFF";
  334. my @unarr= split(/\|/,$unit);
  335. if( int(@unarr)!=2 ){
  336. Log 1, "OWSWITCH: Wrong channel unit specification $unit, replaced by ON|OFF"
  337. if( $state eq "defined");
  338. $unit="ON|OFF";
  339. }
  340. #-- put into readings
  341. $hash->{READINGS}{$owg_channel[$i]}{UNIT} = $unit;
  342. }
  343. }
  344. ########################################################################################
  345. #
  346. # OWSWITCH_FormatValues - put together various format strings
  347. #
  348. # Parameter; hash = hash of device addressed, fs = format string
  349. #
  350. ########################################################################################
  351. sub OWSWITCH_FormatValues($) {
  352. my ($hash) = @_;
  353. my $name = $hash->{NAME};
  354. my ($offset,$factor,$vval,$vvax,$vstr,@unarr,$valid);
  355. my $svalue = "";
  356. #-- external shortening signature
  357. my $sname = defined($attr{$name}{"stateS"}) ? $attr{$name}{"stateS"} : "X";
  358. $sname = ""
  359. if($sname eq "none");
  360. #-- obtain channel names
  361. OWSWITCH_ChannelNames($hash);
  362. #-- put into READINGS
  363. readingsBeginUpdate($hash);
  364. #-- formats for output
  365. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  366. #-- input state is 0 = ON or 1 = OFF
  367. $vval = $hash->{owg_val}->[$i];
  368. #-- output state is 0 = ON or 1 = OFF
  369. $vvax = $hash->{owg_vax}->[$i];
  370. #-- string buildup for return value and STATE
  371. @unarr= split(/\|/,$hash->{READINGS}{$owg_channel[$i]}{UNIT});
  372. $vstr = $unarr[$vval];
  373. #-- put into readings only when valid
  374. if( ($vval == 1) && ($vvax == 0) ){
  375. $vstr ="???"
  376. }else{
  377. $vstr.= $sname if( ($vval == 0) && ($vvax == 1) );
  378. readingsBulkUpdate($hash,$owg_channel[$i],$vstr);
  379. }
  380. $svalue .= sprintf( "%s: %s" , $hash->{READINGS}{$owg_channel[$i]}{ABBR}, $vstr);
  381. #-- insert space
  382. if( $i<($cnumber{$attr{$name}{"model"}}-1) ){
  383. $svalue .= " ";
  384. }
  385. }
  386. #-- STATE
  387. readingsBulkUpdate($hash,"state",$svalue);
  388. readingsEndUpdate($hash,1);
  389. return $svalue;
  390. }
  391. ########################################################################################
  392. #
  393. # OWSWITCH_Get - Implements GetFn function
  394. #
  395. # Parameter: hash = hash of device addressed, a = argument array
  396. #
  397. ########################################################################################
  398. sub OWSWITCH_Get($@) {
  399. my ($hash, @a) = @_;
  400. my $reading = $a[1];
  401. my $name = $hash->{NAME};
  402. my $model = $hash->{OW_MODEL};
  403. my ($value,$value2,$value3) = (undef,undef,undef);
  404. my $ret = "";
  405. my ($offset,$factor,$page,$cname,@cnama,@channel);
  406. #-- check syntax
  407. return "OWSWITCH: Get argument is missing @a"
  408. if(int(@a) < 2);
  409. #-- check argument
  410. return "OWSWITCH: Get with unknown argument $a[1], choose one of ".join(" ", sort keys %gets)
  411. if(!defined($gets{$a[1]}));
  412. #-- get id
  413. if($a[1] eq "id") {
  414. $value = $hash->{ROM_ID};
  415. return "$name.id => $value";
  416. }
  417. #-- hash of the busmaster
  418. my $master = $hash->{IODev};
  419. #-- get present
  420. if($a[1] eq "present") {
  421. #-- asynchronous mode
  422. if( $hash->{ASYNC} ){
  423. eval {
  424. OWX_ASYNC_RunToCompletion($hash,OWX_ASYNC_PT_Verify($hash));
  425. };
  426. return GP_Catch($@) if $@;
  427. return "$name.present => ".ReadingsVal($name,"present","unknown");
  428. } else {
  429. $value = OWX_Verify($master,$hash->{ROM_ID});
  430. }
  431. $hash->{PRESENT} = $value;
  432. return "$name.present => $value";
  433. }
  434. #-- get interval
  435. if($a[1] eq "interval") {
  436. $value = $hash->{INTERVAL};
  437. return "$name.interval => $value";
  438. }
  439. #-- get version
  440. if( $a[1] eq "version") {
  441. return "$name.version => $owx_version";
  442. }
  443. #-- get channel names
  444. OWSWITCH_ChannelNames($hash);
  445. #-- get values according to interface type
  446. my $interface= $hash->{IODev}->{TYPE};
  447. #-- get single state
  448. if( $reading eq "input" ){
  449. return "OWSWITCH: Get needs parameter when reading input: <channel>"
  450. if( int(@a)<2 );
  451. my $fnd=undef;
  452. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  453. if( ($a[2] eq $owg_channel[$i]) || ($a[2] eq $owg_fixed[$i]) ){
  454. $fnd=$i;
  455. last;
  456. }
  457. }
  458. return "OWSWITCH: Invalid input address, must be A,B,... or defined channel name"
  459. if( !defined($fnd) );
  460. #-- OWX interface
  461. if( $interface eq "OWX" ){
  462. OWXSWITCH_GetModState($hash,undef,undef);
  463. }elsif( $interface eq "OWX_ASYNC") {
  464. eval {
  465. $ret = OWX_ASYNC_RunToCompletion($hash,OWXSWITCH_PT_GetState($hash));
  466. };
  467. $ret = GP_Catch($@) if $@;
  468. #-- OWFS interface
  469. }elsif( $interface eq "OWFS" ){
  470. $ret = OWFSSWITCH_GetState($hash);
  471. #-- Unknown interface
  472. }else{
  473. return "OWSWITCH: Get with wrong IODev type $interface";
  474. }
  475. #-- process result
  476. if( ($master->{ASYNCHRONOUS}) && ($interface ne "OWFS") ){
  477. return "OWSWITCH: $name getting input, please wait for completion";
  478. }else{
  479. return $name.".".$a[2]." => ".$hash->{READINGS}{$owg_channel[$fnd]}{VAL};
  480. }
  481. #-- get all states
  482. }elsif( $reading eq "gpio" ){
  483. return "OWSWITCH: Get needs no parameter when reading gpio"
  484. if( int(@a)==1 );
  485. if( $interface eq "OWX" ){
  486. $ret = OWXSWITCH_GetModState($hash,undef,undef);
  487. }elsif( $interface eq "OWX_ASYNC" ){
  488. eval {
  489. $ret = OWX_ASYNC_RunToCompletion($hash,OWXSWITCH_PT_GetState($hash));
  490. };
  491. $ret = GP_Catch($@) if $@;
  492. }elsif( $interface eq "OWServer" ){
  493. $ret = OWFSSWITCH_GetState($hash);
  494. }else{
  495. return "OWSWITCH: Get with wrong IODev type $interface";
  496. }
  497. #-- process results
  498. if( $master->{ASYNCHRONOUS} ){
  499. return "OWSWITCH: $name getting gpio, please wait for completion";
  500. }else{
  501. if( defined($ret) ){
  502. return "OWSWITCH: Could not get values from device $name, reason $ret";
  503. }
  504. return "OWSWITCH: $name.$reading => ".$hash->{READINGS}{"state"}{VAL};
  505. }
  506. }
  507. }
  508. #######################################################################################
  509. #
  510. # OWSWITCH_GetValues - Updates the reading from one device
  511. #
  512. # Parameter hash = hash of device addressed
  513. #
  514. ########################################################################################
  515. sub OWSWITCH_GetValues($) {
  516. my $hash = shift;
  517. my $name = $hash->{NAME};
  518. my $model = $hash->{OW_MODEL};
  519. my $value = "";
  520. my $ret = "";
  521. #-- check if device needs to be initialized
  522. OWSWITCH_InitializeDevice($hash)
  523. if( $hash->{READINGS}{"state"}{VAL} eq "defined");
  524. #-- restart timer for updates
  525. RemoveInternalTimer($hash);
  526. InternalTimer(time()+$hash->{INTERVAL}, "OWSWITCH_GetValues", $hash, 0);
  527. #-- Get readings according to interface type
  528. my $interface= $hash->{IODev}->{TYPE};
  529. if( $interface eq "OWX" ){
  530. #-- max 3 tries
  531. for(my $try=0; $try<3; $try++){
  532. $ret = OWXSWITCH_GetModState($hash,undef,undef);
  533. return if( !defined($ret) );
  534. }
  535. }elsif( $interface eq "OWX_ASYNC" ){
  536. eval {
  537. OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_GetState($hash) );
  538. };
  539. return unless $@;
  540. $ret = GP_Catch($@);
  541. }elsif( $interface eq "OWServer" ){
  542. $ret = OWFSSWITCH_GetState($hash);
  543. }else{
  544. Log 3, "OWSWITCH: GetValues with wrong IODev type $interface";
  545. return 1;
  546. }
  547. #-- process results
  548. if( defined($ret) ){
  549. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  550. $hash->{owg_val}->[$i] = 1;
  551. $hash->{owg_vax}->[$i] = 0;
  552. }
  553. Log 3, "OWSWITCH: Could not get values from device $name, reason $ret";
  554. return 1;
  555. }
  556. return undef;
  557. }
  558. ########################################################################################
  559. #
  560. # OWSWITCH_InitializeDevice - initial readings
  561. #
  562. # Parameter hash = hash of device addressed
  563. #
  564. ########################################################################################
  565. sub OWSWITCH_InitializeDevice($) {
  566. my ($hash) = @_;
  567. my $name = $hash->{NAME};
  568. #-- Initial readings
  569. for( my $i=0;$i<$cnumber{$attr{$name}{"model"}} ;$i++) {
  570. #-- Initial readings ERR
  571. $hash->{owg_val}->[$i] = 1;
  572. $hash->{owg_vax}->[$i] = 0;
  573. }
  574. #-- Set state to initialized
  575. readingsSingleUpdate($hash,"state","initialized",1);
  576. return undef;
  577. }
  578. #######################################################################################
  579. #
  580. # OWSWITCH_Set - Set one value for device
  581. #
  582. # Parameter hash = hash of device addressed
  583. # a = argument array
  584. #
  585. ########################################################################################
  586. sub OWSWITCH_Set($@) {
  587. my ($hash, @a) = @_;
  588. my $key = $a[1];
  589. my $value = $a[2];
  590. my $name = $hash->{NAME};
  591. my $model = $hash->{OW_MODEL};
  592. my ($cname,@cnama,@channel);
  593. my $ret="";
  594. my ($ret1,$ret2);
  595. #-- for the selector: which values are possible
  596. if (@a == 2){
  597. my $newkeys = join(" ", sort keys %sets);
  598. return $newkeys ;
  599. }
  600. #-- check argument
  601. if( !defined($sets{$a[1]}) ){
  602. return "OWSWITCH: Set with unknown argument $a[1]";
  603. }
  604. #-- reset the device
  605. if($key eq "init") {
  606. return "OWSWITCH: Set init needs parameter 'yes'"
  607. if($value ne "yes");
  608. OWSWITCH_InitializeDevice($hash);
  609. return "OWSWITCH: Re-initialized device $name";
  610. }
  611. #-- set new timer interval
  612. if($key eq "interval") {
  613. # check value
  614. return "OWSWITCH: Set with short interval, must be > 1"
  615. if(int($value) < 1);
  616. # update timer
  617. $hash->{INTERVAL} = $value;
  618. RemoveInternalTimer($hash);
  619. InternalTimer(gettimeofday()+$hash->{INTERVAL}, "OWSWITCH_GetValues", $hash, 0);
  620. return undef;
  621. }
  622. #-- obtain channel names
  623. OWSWITCH_ChannelNames($hash);
  624. #-- Set readings according to interface type
  625. my $interface= $hash->{IODev}->{TYPE};
  626. #-- set single state
  627. if( $key eq "output" ){
  628. return "OWSWITCH: Set needs parameter when writing output: <channel>"
  629. if( int(@a)<2 );
  630. #-- find out which channel we have
  631. my $outfnd=undef;
  632. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  633. if( ($a[2] eq $owg_channel[$i]) || ($a[2] eq $owg_fixed[$i]) ){
  634. $outfnd=$i;
  635. last;
  636. }
  637. }
  638. return "OWSWITCH: Invalid output address, must be A,B,... or defined channel name"
  639. if( !defined($outfnd) );
  640. #-- prepare gpio value
  641. my $outval;
  642. my $ntim;
  643. my $nstr="";
  644. if( lc($a[3]) eq "on" ){
  645. $outval = 0;
  646. }elsif( lc($a[3]) eq "off" ){
  647. $outval = 1;
  648. }elsif( lc($a[3]) =~ m/for-timer/ ){
  649. if( !($a[4] =~ m/\d\d\:\d\d\:\d\d/) ){
  650. if( !($a[4] =~ m/\d{1,4}/ )){
  651. return "OWSWITCH: Wrong data value $a[4], must be time format xx:xx:zz or integer";
  652. } else {
  653. $ntim = sprintf("%02d:%02d:%02d",int($a[4]/3600),int( ($a[4] % 3600)/60 ),$a[4] %60);
  654. }
  655. } else {
  656. $ntim= $a[4];
  657. }
  658. if( lc($a[3]) eq "on-for-timer" ){
  659. $outval = 0;
  660. $nstr = "$a[0] $a[1] $a[2] off";
  661. }elsif( lc($a[3]) eq "off-for-timer" ){
  662. $outval = 1;
  663. $nstr = "$a[0] $a[1] $a[2] on";
  664. }
  665. }else{
  666. return "OWSWITCH: Wrong data value $a[3], must be on, off, on-for-timer or off-for-timer";
  667. }
  668. if ($nstr ne ""){
  669. fhem("define ".$a[0].".".$owg_fixed[$outfnd]."Timer at +".$ntim." set ".$nstr);
  670. }
  671. #-- OWX interface
  672. if( $interface eq "OWX" ){
  673. $ret1 = OWXSWITCH_GetModState($hash,$outfnd,$outval);
  674. }elsif( $interface eq "OWX_ASYNC"){
  675. eval {
  676. OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetOutput($hash,$outfnd,$outval) );
  677. };
  678. $ret2 = GP_Catch($@) if $@;
  679. #-- OWFS interface
  680. }elsif( $interface eq "OWServer" ){
  681. $ret1 = OWFSSWITCH_GetState($hash);
  682. my $gpio = 0;
  683. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  684. $gpio += ($hash->{owg_vax}->[$i]<<$i)
  685. };
  686. if( $outval==0 ){
  687. $gpio &= ~(1<<$outfnd);
  688. }else{
  689. $gpio |= (1<<$outfnd);
  690. }
  691. $ret2 = OWFSSWITCH_SetState($hash,$gpio);
  692. #-- Unknown interface
  693. }else{
  694. return "OWSWITCH: Get with wrong IODev type $interface";
  695. }
  696. #-- process results
  697. $ret .= $ret1
  698. if( defined($ret1) );
  699. $ret .= $ret2
  700. if( defined($ret2) );
  701. if( $ret ne "" ){
  702. return "OWSWITCH: Could not set device $name, reason: ".$ret;
  703. }
  704. #-- set state
  705. }elsif( $key eq "gpio" ){
  706. #-- check value and write to device
  707. return "OWSWITCH: Set with wrong value for gpio port, must be 0 <= gpio <= ".((1 << $cnumber{$attr{$name}{"model"}})-1)
  708. if( ! ((int($value) >= 0) && (int($value) <= ((1 << $cnumber{$attr{$name}{"model"}})-1 ))) );
  709. if( $interface eq "OWX" ){
  710. $ret = OWXSWITCH_SetState($hash,int($value));
  711. }elsif( $interface eq "OWX_ASYNC" ){
  712. eval {
  713. OWX_ASYNC_Schedule( $hash, OWXSWITCH_PT_SetState($hash,int($value)) );
  714. };
  715. $ret = GP_Catch($@) if $@;
  716. }elsif( $interface eq "OWServer" ){
  717. $ret = OWFSSWITCH_SetState($hash,int($value));
  718. }else{
  719. return "OWSWITCH: GetValues with wrong IODev type $interface";
  720. }
  721. #-- process results
  722. if($ret){
  723. return "OWSWITCH: Could not set device $name, reason: ".$ret;
  724. }
  725. }
  726. #-- process results - we have to reread the device
  727. #OWSWITCH_GetValues($hash);
  728. Log 4, "OWSWITCH: Set $hash->{NAME} $key $value";
  729. return undef;
  730. }
  731. ########################################################################################
  732. #
  733. # OWSWITCH_Undef - Implements UndefFn function
  734. #
  735. # Parameter hash = hash of device addressed
  736. #
  737. ########################################################################################
  738. sub OWSWITCH_Undef ($) {
  739. my ($hash) = @_;
  740. delete($main::modules{OWSWITCH}{defptr}{$hash->{OW_ID}});
  741. RemoveInternalTimer($hash);
  742. return undef;
  743. }
  744. ########################################################################################
  745. #
  746. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  747. # via OWServer
  748. #
  749. # Prefix = OWFSSWITCH
  750. #
  751. ########################################################################################
  752. #
  753. # OWFSSWITCH_GetState - Get gpio ports from device
  754. #
  755. # Parameter hash = hash of device addressed
  756. #
  757. ########################################################################################
  758. sub OWFSSWITCH_GetState($) {
  759. my ($hash) = @_;
  760. #-- ID of the device
  761. my $owx_add = substr($hash->{ROM_ID},0,15);
  762. #-- hash of the busmaster
  763. my $master = $hash->{IODev};
  764. my $name = $hash->{NAME};
  765. #-- reset presence
  766. $hash->{PRESENT} = 0;
  767. #-- get values - or should we rather use the uncached ones ?
  768. my $rel = OWServer_Read($master,"/$owx_add/sensed.ALL");
  769. my $rex = OWServer_Read($master,"/$owx_add/PIO.ALL");
  770. return "no return from OWServer"
  771. if( !defined($rel) || !defined($rex) );
  772. return "empty return from OWServer"
  773. if( ($rel eq "") || ($rex eq "") );
  774. my @ral = split(/,/,$rel);
  775. my @rax = split(/,/,$rex);
  776. return "wrong data length from OWServer"
  777. if( (int(@ral) != $cnumber{$attr{$name}{"model"}}) || (int(@rax) != $cnumber{$attr{$name}{"model"}}) );
  778. #-- All have the same code here !
  779. #-- family = 12 => DS2406
  780. if( $hash->{OW_FAMILY} eq "12" ) {
  781. #=============== get gpio values ===============================
  782. for(my $i=0;$i<2;$i++){
  783. $hash->{owg_val}->[$i] = $ral[$i];
  784. #-- reading a zero means it is off
  785. $hash->{owg_vax}->[$i] = 1 - $rax[$i];
  786. }
  787. #-- family = 29 => DS2408
  788. }elsif( $hash->{OW_FAMILY} eq "29" ) {
  789. #=============== get gpio values ===============================
  790. for(my $i=0;$i<8;$i++){
  791. $hash->{owg_val}->[$i] = $ral[$i];
  792. #-- reading a zero means it is off
  793. $hash->{owg_vax}->[$i] = 1 - $rax[$i];
  794. }
  795. #-- family = 3A => DS2413
  796. }elsif( $hash->{OW_FAMILY} eq "3A" ) {
  797. #=============== get gpio values ===============================
  798. for(my $i=0;$i<2;$i++){
  799. $hash->{owg_val}->[$i] = $ral[$i];
  800. #-- reading a zero means it is off
  801. $hash->{owg_vax}->[$i] = 1 - $rax[$i];
  802. }
  803. } else {
  804. return "unknown device family $hash->{OW_FAMILY}\n";
  805. }
  806. #-- and now from raw to formatted values
  807. $hash->{PRESENT} = 1;
  808. my $value = OWSWITCH_FormatValues($hash);
  809. Log 5, $value;
  810. return undef;
  811. }
  812. ########################################################################################
  813. #
  814. # OWFSSWITCH_SetState - Set gpio ports in device
  815. #
  816. # Parameter hash = hash of device addressed
  817. #
  818. ########################################################################################
  819. sub OWFSSWITCH_SetState($$) {
  820. my ($hash,$value) = @_;
  821. #-- ID of the device
  822. my $owx_add = substr($hash->{ROM_ID},0,15);
  823. #-- hash of the busmaster
  824. my $master = $hash->{IODev};
  825. my $name = $hash->{NAME};
  826. #-- family = 12 => DS2406
  827. if( $hash->{OW_FAMILY} eq "12" ) {
  828. #=============== set gpio values ===============================
  829. #-- put into local buffer
  830. $hash->{owg_val}->[0] = $value % 2;
  831. $hash->{owg_vax}->[0] = $hash->{owg_val}->[0];
  832. $hash->{owg_val}->[1] = int($value / 2);
  833. $hash->{owg_vax}->[1] = $hash->{owg_val}->[1];
  834. #-- family = 29 => DS2408
  835. }elsif( $hash->{OW_FAMILY} eq "29" ) {
  836. #=============== set gpio values ===============================
  837. for(my $i=0;$i<8;$i++){
  838. $hash->{owg_val}->[$i] = ($value>>$i) & 1;
  839. $hash->{owg_vax}->[$i] = $hash->{owg_val}->[$i]
  840. }
  841. #-- family = 3A => DS2413
  842. }elsif( $hash->{OW_FAMILY} eq "3A" ) {
  843. #=============== set gpio values ===============================
  844. $hash->{owg_val}->[0] = $value % 2;
  845. $hash->{owg_vax}->[0] = $hash->{owg_val}->[0];
  846. $hash->{owg_val}->[1] = int($value / 2);
  847. $hash->{owg_vax}->[1] = $hash->{owg_val}->[1];
  848. } else {
  849. return "unknown device family $hash->{OW_FAMILY}\n";
  850. }
  851. #-- writing a zero will switch output transistor off
  852. my @res;
  853. for(my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  854. $res[$i]=1-$hash->{owg_val}->[$i];
  855. }
  856. OWServer_Write($master, "/$owx_add/PIO.ALL", join(',',@res));
  857. return undef
  858. }
  859. ########################################################################################
  860. #
  861. # The following subroutines in alphabetical order are only for a 1-Wire bus connected
  862. # directly to the FHEM server
  863. #
  864. # Prefix = OWXSWITCH
  865. #
  866. ########################################################################################
  867. #
  868. # OWXSWITCH_BinValues - Process reading from one device - translate binary into raw
  869. #
  870. # Parameter hash = hash of device addressed
  871. # context = mode for evaluating the binary data
  872. # proc = processing instruction, also passed to OWX_Read.
  873. # bitwise interpretation !!
  874. # if 0, nothing special
  875. # if 1 = bit 0, a reset will be performed not only before, but also after
  876. # the last operation in OWX_Read
  877. # if 2 = bit 1, the initial reset of the bus will be suppressed
  878. # if 8 = bit 3, the fillup of the data with 0xff will be suppressed
  879. # if 16= bit 4, the insertion will be at the top of the queue
  880. # owx_dev = ROM ID of slave device
  881. # crcpart = part of the data that needs to be part of the CRC check
  882. # numread = number of bytes to receive
  883. # res = result string
  884. #
  885. #
  886. ########################################################################################
  887. sub OWXSWITCH_BinValues($$$$$$$) {
  888. my ($hash, $context, $reset, $owx_dev, $crcpart, $numread, $res) = @_;
  889. #-- hash of the busmaster
  890. my $master = $hash->{IODev};
  891. my $name = $hash->{NAME};
  892. my @data=[];
  893. my $value;
  894. my $msg;
  895. my $cmd;
  896. my $chip;
  897. my $outfnd;
  898. my $outval;
  899. OWX_WDBG($name,"OWXSWITCH_BinValues called for device $name in context $context with data ",$res)
  900. if( $main::owx_debug>2 );
  901. #-- note: value 1 corresponds to OFF, 0 to ON normally
  902. # val = input value, vax = output value
  903. #-- Outer if - check get or set
  904. if ( $context =~ /^(......)\.(get|mod)state\.?(\d)?\.?(\d)?/){
  905. $cmd = $2;
  906. $chip = $1;
  907. $outfnd = $3;
  908. $outval = $4;
  909. #-- family = 12 => DS2406 -------------------------------------------------------
  910. if( $chip eq "ds2406" ) {
  911. @data=split(//,$res);
  912. if (@data != 4){
  913. $msg="Error - $name returns invalid data length, ".int(@data)." instead of 4 bytes, ";
  914. }elsif(OWX_CRC16($crcpart.substr($res,0,2),$data[2],$data[3]) == 0){
  915. $msg="Error - state could not be set for device $name, invalid CRC, ";
  916. }else{
  917. $msg="No error, ";
  918. $value=ord($data[0]);
  919. $hash->{owg_val}->[0] = ($value>>2) & 1;
  920. $hash->{owg_vax}->[0] = $value & 1;
  921. $hash->{owg_val}->[1] = ($value>>3) & 1;
  922. $hash->{owg_vax}->[1] = ($value>>1) & 1;
  923. }
  924. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  925. if( $main::owx_debug>2 );
  926. #-- family = 29 => DS2408 -------------------------------------------------------
  927. }elsif( $chip eq "ds2408" ) {
  928. @data=split(//,$res);
  929. if (@data != 10){
  930. $msg="Error - $name returns invalid data length, ".int(@data)." instead of 10 bytes, ";
  931. }elsif(ord($data[6])!=255){
  932. $msg="Error - $name returns invalid data, ";
  933. }elsif(OWX_CRC16($crcpart.substr($res,0,8),$data[8],$data[9]) == 0){
  934. $msg="Error - state could not be set for device $name, invalid CRC, ";
  935. }else{
  936. $msg="No error, ";
  937. for(my $i=0;$i<8;$i++){
  938. $hash->{owg_val}->[$i] = (ord($data[0])>>$i) & 1;
  939. $hash->{owg_vax}->[$i] = (ord($data[1])>>$i) & 1;
  940. };
  941. }
  942. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  943. if( $main::owx_debug>2 );
  944. #-- family = 3A => DS2413 -------------------------------------------------------
  945. }elsif( $chip eq "ds2413" ){
  946. @data=split(//,$res);
  947. if (@data != 2){
  948. $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, ";
  949. }elsif((15- (ord($data[0])>>4)) != (ord($data[0]) & 15)){
  950. $msg="Error - $name returns invalid data, ";
  951. }else{
  952. $msg="No error, ";
  953. $hash->{owg_val}->[0] = ord($data[0]) & 1;
  954. $hash->{owg_vax}->[0] = (ord($data[0])>>1) & 1;
  955. $hash->{owg_val}->[1] = (ord($data[0])>>2) & 1;
  956. $hash->{owg_vax}->[1] = (ord($data[0])>>3) & 1;
  957. }
  958. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  959. if( $main::owx_debug>2 );
  960. #--
  961. }else{
  962. die "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues getstate\n";
  963. };
  964. #-- now only if data has to be overwritten
  965. if( $cmd eq "mod" ){
  966. my $gpio = 0;
  967. for (my $i=0;$i<$cnumber{$attr{$name}{"model"}};$i++){
  968. $gpio += ($hash->{owg_vax}->[$i]<<$i)
  969. };
  970. if( $outval==0 ){
  971. $gpio &= ~(1<<$outfnd);
  972. }else{
  973. $gpio |= (1<<$outfnd);
  974. }
  975. #Log 1,"DEBUGGING OWXNG : After reading old gpio as $old, with outval=$outval and outfnd=$outfnd we are setting a new gpio as $gpio";
  976. #-- re-set the state
  977. OWXSWITCH_SetState($hash,$gpio);
  978. }
  979. #-- Now for context setstate
  980. }elsif ( $context =~ /^(......)\.setstate\.?(\d+)?\.?(\d+)?/){
  981. $chip = $1;
  982. $value = $2;
  983. #-- family = 12 => DS2406 -------------------------------------------------------
  984. if( $chip eq "ds2406" ) {
  985. @data=split(//,$res);
  986. if (@data != 2){
  987. $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, ";
  988. }elsif(OWX_CRC16($crcpart,$data[0],$data[1]) == 0){
  989. $msg="Error - state could not be set for device $name, invalid CRC, ";
  990. }else{
  991. $msg="No error, ";
  992. $outval = $value % 2;
  993. $hash->{owg_vax}->[0] = $outval;
  994. $hash->{owg_val}->[0] = 0
  995. if( $outval ==0);
  996. $outval = int($value / 2);
  997. $hash->{owg_vax}->[1] = $outval;
  998. $hash->{owg_val}->[1] = 0
  999. if( $outval ==0);
  1000. }
  1001. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  1002. if( $main::owx_debug>2 );
  1003. #-- family = 29 => DS2408 -------------------------------------------------------
  1004. }elsif( $chip eq "ds2408" ) {
  1005. if (length($res)!=1){
  1006. $msg="Error - $name returns invalid data length, ".length($res)." instead of 1 bytes, ";
  1007. }elsif($res ne "\xAA"){
  1008. $msg="Error - state could not be set for device $name, ";
  1009. }else{
  1010. $msg="No error, ";
  1011. for(my $i=0;$i<8;$i++){
  1012. $outval = ($value >>$i) & 1;
  1013. $hash->{owg_vax}->[$i] = $outval;
  1014. $hash->{owg_val}->[$i] = 0
  1015. if( $outval ==0);
  1016. };
  1017. }
  1018. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  1019. if( $main::owx_debug>2 );
  1020. #-- family = 3A => DS2413 -------------------------------------------------------
  1021. }elsif( $chip eq "ds2413" ){
  1022. @data=split(//,$res);
  1023. if (@data != 2){
  1024. $msg="Error - $name returns invalid data length, ".int(@data)." instead of 2 bytes, ";
  1025. }elsif( $data[0] ne "\xAA"){
  1026. $msg="Error - state could not be set for device $name, ";
  1027. }else{
  1028. $msg="No error, ";
  1029. $outval = (ord($data[1])>>1) & 1;
  1030. $hash->{owg_vax}->[0] = $outval;
  1031. $hash->{owg_val}->[0] = 0
  1032. if( $outval ==0);
  1033. $outval = (ord($data[1])>>3) & 1;
  1034. $hash->{owg_vax}->[1] = $outval;
  1035. $hash->{owg_val}->[1] = 0
  1036. if( $outval ==0);
  1037. }
  1038. OWX_WDBG($name,"OWXSWITCH_BinValues: ".$msg,$res)
  1039. if( $main::owx_debug>2 );
  1040. #--
  1041. }else{
  1042. die "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY} in OWXSWITCH_BinValues setstate\n";
  1043. };
  1044. OWXSWITCH_GetModState($hash,undef,undef);
  1045. }else{
  1046. die "OWSWITCH: unknown context $context in OWXSWITCH_BinValues";
  1047. }
  1048. #-- and now from raw to formatted values
  1049. $hash->{PRESENT} = 1;
  1050. $value = OWSWITCH_FormatValues($hash);
  1051. return undef;
  1052. }
  1053. ########################################################################################
  1054. #
  1055. # OWXSWITCH_GetModState - Get gpio ports from device and overwrite
  1056. #
  1057. # Parameter hash = hash of device addressed
  1058. # mod = if 1, overwrite state with new data
  1059. #
  1060. ########################################################################################
  1061. sub OWXSWITCH_GetModState($$$) {
  1062. my ($hash,$outfnd,$outval) = @_;
  1063. my ($select, $res, @data);
  1064. #-- ID of the device
  1065. my $owx_dev = $hash->{ROM_ID};
  1066. my $owx_rnf = substr($owx_dev,3,12);
  1067. my $owx_f = substr($owx_dev,0,2);
  1068. #-- hash of the busmaster
  1069. my $master = $hash->{IODev};
  1070. my $name = $hash->{NAME};
  1071. #-- reset presence
  1072. $hash->{PRESENT} = 0;
  1073. #-- what do we have to do
  1074. my $context;
  1075. my $proc;
  1076. if( !defined($outfnd) ){
  1077. $context = "getstate";
  1078. #-- take your time
  1079. $proc = 0;
  1080. }else{
  1081. $context = "modstate.$outfnd.$outval";
  1082. #-- faster !
  1083. $proc = 16;
  1084. }
  1085. #-- family = 12 => DS2406
  1086. if( $hash->{OW_FAMILY} eq "12" ) {
  1087. #=============== get gpio values ===============================
  1088. #-- issue the match ROM command \x55 and the access channel command
  1089. # \xF5 plus the two byte channel control and the value
  1090. #-- reading 9 + 3 + 2 data bytes + 2 CRC bytes = 16 bytes
  1091. $select=sprintf("\xF5\xDD\xFF");
  1092. #-- OLD OWX interface
  1093. if( !$master->{ASYNCHRONOUS} ){
  1094. OWX_Reset($master);
  1095. $res=OWX_Complex($master,$owx_dev,$select,4);
  1096. return "OWSWITCH: $name not accessible in reading"
  1097. if( $res eq 0 );
  1098. return "OWSWITCH: $name has returned invalid data"
  1099. if( length($res)!=16);
  1100. #OWX_Reset($master);
  1101. eval {
  1102. OWXSWITCH_BinValues($hash,"ds2406.$context",undef,$owx_dev,$select,4,substr($res,12));
  1103. };
  1104. return $@ ? $@ : undef;
  1105. #-- NEW OWX interface
  1106. }else{
  1107. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1108. OWX_Qomplex($master, $hash, "ds2406.$context", $proc, $owx_dev, $select, $select, 4, 12, \&OWXSWITCH_BinValues, 0);
  1109. return undef;
  1110. }
  1111. #-- family = 29 => DS2408
  1112. }elsif( $hash->{OW_FAMILY} eq "29" ) {
  1113. #=============== get gpio values ===============================
  1114. #-- issue the match ROM command \x55 and the read PIO registers command
  1115. # \xF5 plus the two byte channel target address
  1116. #-- reading 9 + 3 + 8 data bytes + 2 CRC bytes = 22 bytes
  1117. $select=sprintf("\xF0\x88\x00");
  1118. #-- OLD OWX interface
  1119. if( !$master->{ASYNCHRONOUS} ){
  1120. OWX_Reset($master);
  1121. $res=OWX_Complex($master,$owx_dev,$select,10);
  1122. return "OWSWITCH: $name not accessible in reading"
  1123. if( $res eq 0 );
  1124. return "OWSWITCH: $name has returned invalid data"
  1125. if( length($res)!=22);
  1126. #OWX_Reset($master);
  1127. eval {
  1128. OWXSWITCH_BinValues($hash,"ds2408.$context",0,$owx_dev,$select,4,substr($res,12));
  1129. };
  1130. return $@ ? $@ : undef;
  1131. #-- NEW OWX interface
  1132. }else{
  1133. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1134. OWX_Qomplex($master, $hash, "ds2408.$context", $proc, $owx_dev, $select, $select,10, 12, \&OWXSWITCH_BinValues, 0);
  1135. return undef;
  1136. }
  1137. #-- family = 3A => DS2413
  1138. }elsif( $hash->{OW_FAMILY} eq "3A" ) {
  1139. #=============== get gpio values ===============================
  1140. #-- issue the match ROM command \x55 and the read gpio command
  1141. # \xF5 plus 2 empty bytes
  1142. #-- reading 9 + 1 + 2 data bytes = 12 bytes
  1143. #-- OLD OWX interface
  1144. if( !$master->{ASYNCHRONOUS} ){
  1145. OWX_Reset($master);
  1146. $res=OWX_Complex($master,$owx_dev,"\xF5",2);
  1147. return "OWSWITCH: $name not accessible in reading"
  1148. if( $res eq 0 );
  1149. return "OWSWITCH: $name has returned invalid data"
  1150. if( length($res)!=12);
  1151. #OWX_Reset($master);
  1152. eval {
  1153. OWXSWITCH_BinValues($hash,"ds2413.$context",0,$owx_dev,substr($res,9,1),2,substr($res,10));
  1154. };
  1155. return $@ ? $@ : undef;
  1156. #-- NEW OWX interface
  1157. }else{
  1158. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1159. OWX_Qomplex($master, $hash, "ds2413.$context", $proc, $owx_dev, "\xF5", "\xF5", 2, 10, \&OWXSWITCH_BinValues, 0);
  1160. return undef;
  1161. }
  1162. } else {
  1163. return "OWSWITCH: $name has unknown device family $hash->{OW_FAMILY}\n";
  1164. }
  1165. }
  1166. ########################################################################################
  1167. #
  1168. # OWXSWITCH_SetState - Set gpio ports of device
  1169. #
  1170. # Parameter hash = hash of device addressed
  1171. # value = integer value for device gpio output
  1172. #
  1173. ########################################################################################
  1174. sub OWXSWITCH_SetState($$) {
  1175. my ($hash,$value) = @_;
  1176. my ($select, $res, $res2, @data);
  1177. #-- ID of the device
  1178. my $owx_dev = $hash->{ROM_ID};
  1179. my $owx_rnf = substr($owx_dev,3,12);
  1180. my $owx_f = substr($owx_dev,0,2);
  1181. #-- hash of the busmaster
  1182. my $master = $hash->{IODev};
  1183. #-- family = 12 => DS2406
  1184. if( $hash->{OW_FAMILY} eq "12" ) {
  1185. #=============== set gpio values ===============================
  1186. # Writing the output state via the access channel command does
  1187. # not work contrary to documentation. Using the write status command
  1188. #-- issue the match ROM command \x55 and the read status command
  1189. # \xAA at address TA1 = \x07 TA2 = \x00
  1190. #-- reading 9 + 3 + 1 data bytes + 2 CRC bytes = 15 bytes
  1191. OWX_Reset($master);
  1192. $res = OWX_Complex($master,$owx_dev,"\xAA\x07\x00",3);
  1193. if( $res eq 0 ){
  1194. return "device $owx_dev not accessible in writing";
  1195. }
  1196. OWX_Reset($master);
  1197. my $stat = ord(substr($res,12,1));
  1198. my $statneu = ( $stat & 159 ) | (($value<<5) & 96) ;
  1199. #-- call the second step
  1200. #-- issue the match ROM command \x55 and the write status command
  1201. # \x55 at address TA1 = \x07 TA2 = \x00
  1202. #-- reading 9 + 4 + 2 data bytes = 15 bytes
  1203. $select=sprintf("\x55\x07\x00%c",$statneu);
  1204. #-- OLD OWX interface
  1205. if( !$master->{ASYNCHRONOUS} ){
  1206. OWX_Reset($master);
  1207. $res=OWX_Complex($master,$owx_dev,$select,2);
  1208. if( $res eq 0 ){
  1209. return "device $owx_dev not accessible in writing";
  1210. }
  1211. #OWX_Reset($master);
  1212. return OWXSWITCH_BinValues($hash,"ds2406.setstate.$value",0,$owx_dev,$select,2,substr($res,13));
  1213. #-- NEW OWX interface
  1214. }else{
  1215. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1216. # 16 pushes this to the top of the queue
  1217. OWX_Qomplex($master, $hash, "ds2406.setstate.$value", 16, $owx_dev, $select, $select, 2, 13, \&OWXSWITCH_BinValues, 0);
  1218. return undef;
  1219. }
  1220. #-- family = 29 => DS2408
  1221. } elsif( $hash->{OW_FAMILY} eq "29" ) {
  1222. #=============== set gpio values ===============================
  1223. #-- issue the match ROM command \x55 and the write gpio command
  1224. # \x5A plus the value byte and its complement
  1225. $select=sprintf("\x5A%c%c",$value,255-$value);
  1226. #-- OLD OWX interface
  1227. if( !$master->{ASYNCHRONOUS} ){
  1228. OWX_Reset($master);
  1229. $res=OWX_Complex($master,$owx_dev,$select,1);
  1230. if( $res eq 0 ){
  1231. return "device $owx_dev not accessible in writing";
  1232. }
  1233. OWX_Reset($master);
  1234. return OWXSWITCH_BinValues($hash,"ds2408.setstate.$value",0,$owx_dev,0,1,substr($res,12));
  1235. #-- NEW OWX interface
  1236. }else{
  1237. #### master slave context proc owx_dev data crcpart numread startread callback delay
  1238. # 16 pushes this to the top of the queue
  1239. OWX_Qomplex($master, $hash, "ds2408.setstate.$value", 16, $owx_dev, $select, 0, 1, 12, \&OWXSWITCH_BinValues, 0);
  1240. return undef;
  1241. }
  1242. #-- family = 3A => DS2413
  1243. } elsif( $hash->{OW_FAMILY} eq "3A" ) {
  1244. #=============== set gpio values ===============================
  1245. #-- issue the match ROM command \x55 and the write gpio command
  1246. # \x5A plus the value byte and its complement
  1247. $select=sprintf("\x5A%c%c",252+$value,3-$value);
  1248. #-- OLD OWX interface
  1249. if( !$master->{ASYNCHRONOUS} ){
  1250. OWX_Reset($master);
  1251. $res=OWX_Complex($master,$owx_dev,$select,1);
  1252. if( $res eq 0 ){
  1253. return "device $owx_dev not accessible in writing";
  1254. }
  1255. OWX_Reset($master);
  1256. return OWXSWITCH_BinValues($hash,"ds2413.setstate",0,$owx_dev,0,2,substr($res,12));
  1257. #-- NEW OWX interface
  1258. }else{
  1259. #### master slave context proc owx_dev data cmd numread startread callback delay
  1260. # 16 pushes this to the top of the queue
  1261. OWX_Qomplex($master, $hash, "ds2413.setstate", 16, $owx_dev, $select, 0, 2, 12, \&OWXSWITCH_BinValues, 0);
  1262. return undef;
  1263. }
  1264. }else {
  1265. return "unknown device family $hash->{OW_FAMILY}\n";
  1266. }
  1267. }
  1268. ########################################################################################
  1269. #
  1270. # OWXSWITCH_PT_GetState - Get gpio ports from device asynchronous
  1271. #
  1272. # Parameter hash = hash of device addressed
  1273. #
  1274. ########################################################################################
  1275. sub OWXSWITCH_PT_GetState($) {
  1276. my ($hash) = @_;
  1277. return PT_THREAD( sub {
  1278. my ($thread) = @_;
  1279. my ($select, $ret, @data, $response);
  1280. #-- ID of the device
  1281. my $owx_dev = $hash->{ROM_ID};
  1282. #-- hash of the busmaster
  1283. my $master = $hash->{IODev};
  1284. PT_BEGIN($thread);
  1285. my ($i,$j,$k);
  1286. #-- family = 12 => DS2406
  1287. if( $hash->{OW_FAMILY} eq "12" ) {
  1288. #=============== get gpio values ===============================
  1289. #-- issue the match ROM command \x55 and the access channel command
  1290. # \xF5 plus the two byte channel control and the value
  1291. #-- reading 9 + 3 + 2 data bytes + 2 CRC bytes = 16 bytes
  1292. $thread->{'select'}=sprintf("\xF5\xDD\xFF");
  1293. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},4);
  1294. PT_WAIT_THREAD($thread->{pt_execute});
  1295. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1296. $response = $thread->{pt_execute}->PT_RETVAL();
  1297. unless (length($response) == 4) {
  1298. PT_EXIT("$owx_dev has returned invalid data");
  1299. }
  1300. $ret = OWXSWITCH_BinValues($hash,"ds2406.getstate",1,$owx_dev,$thread->{'select'},4,$response);
  1301. if (defined $ret) {
  1302. PT_EXIT($ret);
  1303. }
  1304. #-- family = 29 => DS2408
  1305. }elsif( $hash->{OW_FAMILY} eq "29" ) {
  1306. #=============== get gpio values ===============================
  1307. #-- issue the match ROM command \x55 and the read PIO rtegisters command
  1308. # \xF5 plus the two byte channel target address
  1309. #-- reading 9 + 3 + 8 data bytes + 2 CRC bytes = 22 bytes
  1310. $thread->{'select'}=sprintf("\xF0\x88\x00");
  1311. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},10);
  1312. PT_WAIT_THREAD($thread->{pt_execute});
  1313. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1314. $response = $thread->{pt_execute}->PT_RETVAL();
  1315. unless (length($response) == 10) {
  1316. PT_EXIT("$owx_dev has returned invalid data")
  1317. };
  1318. $ret = OWXSWITCH_BinValues($hash,"ds2408.getstate",1,$owx_dev,$thread->{'select'},10,$response);
  1319. if (defined $ret) {
  1320. PT_EXIT($ret);
  1321. }
  1322. #-- family = 3A => DS2413
  1323. }elsif( $hash->{OW_FAMILY} eq "3A" ) {
  1324. #=============== get gpio values ===============================
  1325. #-- issue the match ROM command \x55 and the read gpio command
  1326. # \xF5 plus 2 empty bytes
  1327. #-- reading 9 + 1 + 2 data bytes = 12 bytes
  1328. $thread->{'select'}="\xF5";
  1329. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'},2);
  1330. PT_WAIT_THREAD($thread->{pt_execute});
  1331. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1332. $response = $thread->{pt_execute}->PT_RETVAL();
  1333. unless (length($response) == 2) {
  1334. PT_EXIT("$owx_dev has returned invalid data");
  1335. }
  1336. $ret = OWXSWITCH_BinValues($hash,"ds2413.getstate",1,$owx_dev,$thread->{'select'},2,$response);
  1337. if (defined $ret) {
  1338. PT_EXIT($ret);
  1339. }
  1340. } else {
  1341. PT_EXIT("unknown device family $hash->{OW_FAMILY}\n");
  1342. }
  1343. PT_END;
  1344. });
  1345. }
  1346. ########################################################################################
  1347. #
  1348. # OWXSWITCH_PT_SetState - Set gpio ports of device asynchronous
  1349. #
  1350. # Parameter hash = hash of device addressed
  1351. # value = integer value for device outputs
  1352. #
  1353. ########################################################################################
  1354. sub OWXSWITCH_PT_SetState($$) {
  1355. my ($hash,$value) = @_;
  1356. return PT_THREAD( sub {
  1357. my ($thread) = @_;
  1358. my ($select,$res,@data);
  1359. #-- ID of the device
  1360. my $owx_dev = $hash->{ROM_ID};
  1361. #-- hash of the busmaster
  1362. my $master = $hash->{IODev};
  1363. PT_BEGIN($thread);
  1364. #-- family = 12 => DS2406
  1365. if( $hash->{OW_FAMILY} eq "12" ) {
  1366. #=============== set gpio values ===============================
  1367. # Writing the output state via the access channel command does
  1368. # not work contrary to documentation. Using the write status command
  1369. #-- issue the match ROM command \x55 and the read status command
  1370. # \xAA at address TA1 = \x07 TA2 = \x00
  1371. #-- reading 9 + 3 + 1 data bytes + 2 CRC bytes = 15 bytes
  1372. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,"\xAA\x07\x00", 3);
  1373. PT_WAIT_THREAD($thread->{pt_execute});
  1374. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1375. $res = $thread->{pt_execute}->PT_RETVAL();
  1376. #-- first step
  1377. my $stat = ord(substr($res,0,1));
  1378. my $statneu = ( $stat & 159 ) | (($value<<5) & 96) ;
  1379. #-- call the second step
  1380. #-- issue the match ROM command \x55 and the write status command
  1381. # \x55 at address TA1 = \x07 TA2 = \x00
  1382. #-- reading 9 + 4 + 2 data bytes = 15 bytes
  1383. $thread->{'select'}=sprintf("\x55\x07\x00%c",$statneu);
  1384. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$thread->{'select'}, 2);
  1385. PT_WAIT_THREAD($thread->{pt_execute});
  1386. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1387. $res = $thread->{pt_execute}->PT_RETVAL();
  1388. my $command = $thread->{'select'};
  1389. #-- second step from above
  1390. @data=split(//,$res);
  1391. if( int(@data) != 2){
  1392. PT_EXIT("state could not be set for device $owx_dev");
  1393. }
  1394. if (OWX_CRC16($command,$data[0],$data[1]) == 0) {
  1395. PT_EXIT("invalid CRC");
  1396. }
  1397. #-- put into local buffer
  1398. $hash->{owg_val}->[0] = $value % 2;
  1399. $hash->{owg_vax}->[0] = $value % 2;
  1400. $hash->{owg_val}->[1] = int($value / 2);
  1401. $hash->{owg_vax}->[1] = int($value / 2);
  1402. #-- family = 29 => DS2408
  1403. } elsif( $hash->{OW_FAMILY} eq "29" ) {
  1404. #=============== set gpio values ===============================
  1405. #-- issue the match ROM command \x55 and the write gpio command
  1406. # \x5A plus the value byte and its complement
  1407. $select=sprintf("\x5A%c%c",$value,255-$value);
  1408. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select, 1);
  1409. PT_WAIT_THREAD($thread->{pt_execute});
  1410. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1411. $res = $thread->{pt_execute}->PT_RETVAL();
  1412. @data=split(//,$res);
  1413. if (@data != 1) {
  1414. PT_EXIT("invalid data length, ".int(@data)." instead of 1 bytes");
  1415. }
  1416. if( $data[0] ne "\xAA") {
  1417. PT_EXIT("state could not be set for device $owx_dev");
  1418. }
  1419. #-- family = 3A => DS2413
  1420. } elsif( $hash->{OW_FAMILY} eq "3A" ) {
  1421. #=============== set gpio values ===============================
  1422. #-- issue the match ROM command \x55 and the write gpio command
  1423. # \x5A plus the value byte and its complement
  1424. $select=sprintf("\x5A%c%c",252+$value,3-$value);
  1425. $thread->{pt_execute} = OWX_ASYNC_PT_Execute($master,1,$owx_dev,$select, 1);
  1426. PT_WAIT_THREAD($thread->{pt_execute});
  1427. die $thread->{pt_execute}->PT_CAUSE() if ($thread->{pt_execute}->PT_STATE() == PT_ERROR);
  1428. $res = $thread->{pt_execute}->PT_RETVAL();
  1429. @data=split(//,$res);
  1430. if (@data != 1) {
  1431. PT_EXIT("invalid data length, ".int(@data)." instead of 1 bytes");
  1432. }
  1433. if( $data[0] ne "\xAA") {
  1434. PT_EXIT("state could not be set for device $owx_dev");
  1435. }
  1436. } else {
  1437. PT_EXIT("unknown device family $hash->{OW_FAMILY}\n");
  1438. }
  1439. PT_END;
  1440. });
  1441. }
  1442. sub OWXSWITCH_PT_SetOutput($$$) {
  1443. my ($hash,$fnd,$nval) = @_;
  1444. return PT_THREAD(sub {
  1445. my ($thread) = @_;
  1446. my ($ret,$value);
  1447. PT_BEGIN($thread);
  1448. $thread->{task} = OWXSWITCH_PT_GetState($hash);
  1449. PT_WAIT_THREAD($thread->{task});
  1450. die $thread->{task}->PT_CAUSE() if ($thread->{task}->PT_STATE() == PT_ERROR);
  1451. $ret = $thread->{task}->PT_RETVAL();
  1452. die $ret if $ret;
  1453. $value = 0;
  1454. #-- vax or val ?
  1455. for (my $i=0;$i<$cnumber{$attr{$hash->{NAME}}{"model"}};$i++){
  1456. $value += ($hash->{owg_vax}->[$i]<<$i)
  1457. if( $i != $fnd );
  1458. $value += ($nval<<$i)
  1459. if( $i == $fnd );
  1460. }
  1461. $thread->{value} = $value;
  1462. $thread->{task} = OWXSWITCH_PT_SetState($hash,$thread->{value});
  1463. PT_WAIT_THREAD($thread->{task});
  1464. die $thread->{task}->PT_CAUSE() if ($thread->{task}->PT_STATE() == PT_ERROR);
  1465. $ret = $thread->{task}->PT_RETVAL();
  1466. die $ret if $ret;
  1467. PT_END;
  1468. });
  1469. }
  1470. 1;
  1471. =pod
  1472. =begin html
  1473. <a name="OWSWITCH"></a>
  1474. <h3>OWSWITCH</h3>
  1475. <p>FHEM module to commmunicate with 1-Wire Programmable Switches <br />
  1476. <br />This 1-Wire module works with the OWX interface module or with the OWServer interface module
  1477. (prerequisite: Add this module's name to the list of clients in OWServer).
  1478. Please define an <a href="#OWX">OWX</a> device or <a href="#OWServer">OWServer</a> device first.</p>
  1479. <h4>Example</h4>
  1480. <p>
  1481. <code>define OWX_S OWSWITCH DS2413 B5D502000000 60</code>
  1482. <br />
  1483. <code>attr OWX_S AName light-a|la</code>
  1484. <br />
  1485. <code>attr OWX_S AUnit AN|AUS</code>
  1486. </p>
  1487. <a name="OWSWITCHdefine"></a>
  1488. <h4>Define</h4>
  1489. <p>
  1490. <code>define &lt;name&gt; OWSWITCH [&lt;model&gt;] &lt;id&gt; [&lt;interval&gt;]</code> or <br/>
  1491. <code>define &lt;name&gt; OWSWITCH &lt;fam&gt;.&lt;id&gt; [&lt;interval&gt;]</code>
  1492. <br /><br /> Define a 1-Wire switch.<br /><br />
  1493. <ul>
  1494. <li>
  1495. <code>[&lt;model&gt;]</code><br /> Defines the switch model (and thus 1-Wire family
  1496. id), currently the following values are permitted: <ul>
  1497. <li>model DS2413 with family id 3A (default if the model parameter is omitted).
  1498. 2 Channel switch with onboard memory</li>
  1499. <li>model DS2406 with family id 12. 2 Channel switch </li>
  1500. <li>model DS2408 with family id 29. 8 Channel switch</li>
  1501. </ul>
  1502. </li>
  1503. <li>
  1504. <code>&lt;fam&gt;</code>
  1505. <br />2-character unique family id, see above
  1506. </li>
  1507. <li>
  1508. <code>&lt;id&gt;</code>
  1509. <br />12-character unique ROM id of the device without family id and CRC
  1510. code </li>
  1511. <li>
  1512. <code>&lt;interval&gt;</code>
  1513. <br />Measurement interval in seconds. The default is 300 seconds. </li>
  1514. </ul>
  1515. <a name="OWSWITCHset"></a>
  1516. <h4>Set</h4>
  1517. <ul>
  1518. <li><a name="owswitch_interval">
  1519. <code>set &lt;name&gt; interval &lt;int&gt;</code></a><br /> Measurement
  1520. interval in seconds. The default is 300 seconds. </li>
  1521. <li><a name="owswitch_output">
  1522. <code>set &lt;name&gt; output &lt;channel-name&gt; on | off | on-for-timer &lt;time&gt; | off-for-timer &lt;time&gt;</code>
  1523. </a><br />Set
  1524. value for channel (A,B,... or defined channel name). 1 = off, 0 = on in normal
  1525. usage. See also the note above.<br/>
  1526. on-for-timer/off-for-timer will set the desired value only for the given time,
  1527. either given as hh:mm:ss or as integers seconds
  1528. and then will return to the opposite value.</li>
  1529. <li><a name="owswitch_gpio">
  1530. <code>set &lt;name&gt; gpio &lt;value&gt;</code></a><br />Set values for
  1531. channels (For 2 channels: 3 = A and B off, 1 = B on 2 = A on 0 = both on)</li>
  1532. <li><a name="owswitch_init">
  1533. <code>set &lt;name&gt; init yes</code></a><br /> Re-initialize the device</li>
  1534. </ul>
  1535. <a name="OWSWITCHget"></a>
  1536. <h4>Get</h4>
  1537. <ul>
  1538. <li><a name="owswitch_id">
  1539. <code>get &lt;name&gt; id</code></a>
  1540. <br /> Returns the full 1-Wire device id OW_FAMILY.ROM_ID.CRC </li>
  1541. <li><a name="owswitch_present">
  1542. <code>get &lt;name&gt; present</code>
  1543. </a>
  1544. <br /> Returns 1 if this 1-Wire device is present, otherwise 0. </li>
  1545. <li><a name="owswitch_interval2">
  1546. <code>get &lt;name&gt; interval</code></a><br />Measurement interval in
  1547. seconds. </li>
  1548. <li><a name="owswitch_input">
  1549. <code>get &lt;name&gt; input &lt;channel-name&gt;</code></a><br /> state for
  1550. channel (A,B, ... or defined channel name) This value reflects the measured value,
  1551. not necessarily the one set as output state, because the output transistors are open
  1552. collector switches. A measured state of 1 = OFF therefore corresponds to an output
  1553. state of 1 = OFF, but a measured state of 0 = ON can also be due to an external
  1554. shortening of the output, it will be signaled by appending the value of the attribute stateS to the reading.</li>
  1555. <li><a name="owswitch_gpio">
  1556. <code>get &lt;name&gt; gpio</code></a><br />Obtain state of all channels</li>
  1557. </ul>
  1558. <a name="OWSWITCHattr"></a>
  1559. <h4>Attributes</h4> For each of the following attributes, the channel identification A,B,...
  1560. may be used. <ul>
  1561. <li><a name="owswitch_states"><code>&lt;name&gt; stateS &lt;string&gt;</code></a>
  1562. <br/> character string denoting external shortening condition (default is X, set to "none" for empty).</li>
  1563. <li><a name="owswitch_cname"><code>attr &lt;name&gt; &lt;channel&gt;Name
  1564. &lt;string&gt;[|&lt;string&gt;]</code></a>
  1565. <br />name for the channel [|short name used in state reading] </li>
  1566. <li><a name="owswitch_cunit"><code>attr &lt;name&gt; &lt;channel&gt;Unit
  1567. &lt;string&gt;|&lt;string&gt;</code></a>
  1568. <br />display for on | off condition </li>
  1569. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  1570. </ul>
  1571. =end html
  1572. =cut