21_OWSWITCH.pm 59 KB

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