10_OWServer.pm 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  1. # $Id: 10_OWServer.pm 16501 2018-03-27 11:27:13Z neubert $
  2. ################################################################
  3. #
  4. # Copyright notice
  5. #
  6. # (c) 2012 Copyright: Dr. Boris Neubert & Martin Fischer
  7. # e-mail: omega at online dot de
  8. # e-mail: m_fischer at gmx dot de
  9. #
  10. # This file is part of fhem.
  11. #
  12. # Fhem is free software: you can redistribute it and/or modify
  13. # it under the terms of the GNU General Public License as published by
  14. # the Free Software Foundation, either version 2 of the License, or
  15. # (at your option) any later version.
  16. #
  17. # Fhem is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. # GNU General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with fhem. If not, see <http://www.gnu.org/licenses/>.
  24. #
  25. ################################################################################
  26. package main;
  27. use strict;
  28. use warnings;
  29. # this must be the latest OWNet from
  30. # http://owfs.cvs.sourceforge.net/viewvc/owfs/owfs/module/ownet/perl5/OWNet/lib/OWNet.pm
  31. # the version at CPAN is outdated and malfunctioning as at 2012-12-19
  32. #use constant OWNet_version_default => "2.8p17";
  33. use constant OWNet_version_default => "3.1p5";
  34. use vars qw($OWNet_version);
  35. use vars qw(%owfamily);
  36. # 1-Wire devices (order by family code)
  37. # http://owfs.sourceforge.net/family.html
  38. %owfamily = (
  39. "01" => "DS2401 DS1990A",
  40. "05" => "DS2405",
  41. "10" => "DS18S20 DS1920",
  42. "12" => "DS2406 DS2507",
  43. "1B" => "DS2436",
  44. "1D" => "DS2423",
  45. "1F" => "DS2409",
  46. "20" => "DS2450",
  47. "22" => "DS1822",
  48. "23" => "DS2433",
  49. "24" => "DS2415 DS1904",
  50. "26" => "DS2438",
  51. "27" => "DS2417",
  52. "28" => "DS18B20",
  53. "29" => "DS2408",
  54. "3A" => "DS2413",
  55. "3B" => "DS1825",
  56. "7E" => "EDS000XX",
  57. "81" => "DS1420",
  58. "FF" => "LCD",
  59. );
  60. use vars qw(%gets %sets);
  61. %gets = (
  62. "/settings/timeout/directory" => "",
  63. "/settings/timeout/ftp" => "",
  64. "/settings/timeout/ha7" => "",
  65. "/settings/timeout/network" => "",
  66. "/settings/timeout/presence" => "",
  67. "/settings/timeout/serial" => "",
  68. "/settings/timeout/server" => "",
  69. "/settings/timeout/stable" => "",
  70. "/settings/timeout/uncached" => "",
  71. "/settings/timeout/usb" => "",
  72. "/settings/timeout/volatile" => "",
  73. "/settings/timeout/w1" => "",
  74. "/settings/units/pressure_scale" => "",
  75. "/settings/units/temperature_scale" => "",
  76. "/uncached/alarm" => "",
  77. );
  78. %sets = (
  79. "timeout/directory" => "",
  80. "timeout/ftp" => "",
  81. "timeout/ha7" => "",
  82. "timeout/network" => "",
  83. "timeout/presence" => "",
  84. "timeout/serial" => "",
  85. "timeout/server" => "",
  86. "timeout/stable" => "",
  87. "timeout/uncached" => "",
  88. "timeout/usb" => "",
  89. "timeout/volatile" => "",
  90. "timeout/w1" => "",
  91. "units/pressure_scale" => "",
  92. "units/temperature_scale" => "",
  93. );
  94. #####################################
  95. sub
  96. OWServer_Initialize($)
  97. {
  98. my ($hash) = @_;
  99. # Provider
  100. $hash->{WriteFn} = "OWServer_Write";
  101. $hash->{ReadFn} = "OWServer_Read";
  102. $hash->{DirFn} = "OWServer_Dir";
  103. $hash->{FindFn} = "OWServer_Find";
  104. $hash->{Clients} = ":OWDevice:OWAD:OWCOUNT:OWMULTI:OWSWITCH:OWTHERM:";
  105. # Consumer
  106. $hash->{DefFn} = "OWServer_Define";
  107. $hash->{NotifyFn}= "OWServer_Notify";
  108. $hash->{NotifyOrderPrefix}= "50a-";
  109. $hash->{UndefFn} = "OWServer_Undef";
  110. $hash->{GetFn} = "OWServer_Get";
  111. $hash->{SetFn} = "OWServer_Set";
  112. # $hash->{AttrFn} = "OWServer_Attr";
  113. $hash->{AttrList}= "nonblocking " . $readingFnAttributes;
  114. }
  115. #####################################
  116. sub
  117. OWServer_Define($$)
  118. {
  119. my ($hash, $def) = @_;
  120. my @a = split("[ \t]+", $def, 4);
  121. my $name = $a[0];
  122. if(@a < 3) {
  123. my $msg = "wrong syntax for $name: define <name> OWServer <protocol> [<version>]";
  124. Log 2, $msg;
  125. return $msg;
  126. }
  127. my $protocol = $a[2];
  128. $hash->{fhem}{protocol}= $protocol;
  129. my $version;
  130. if(@a==4) {
  131. $version= $a[3];
  132. Log3 $hash, 5, "$name: Suggesting OWNet version $version";
  133. if(!OWServer_hasOWNet($version)) {
  134. Log3 $hash, 2, "$name: Suggested OWNet version $version not available, falling back to default version "
  135. . OWNet_version_default;
  136. $version= OWNet_version_default;
  137. }
  138. } else {
  139. $version= OWNet_version_default;
  140. Log3 $hash, 5, "$name: Tentatively assuming OWNet version $version";
  141. }
  142. $hash->{OWNET_VERSION}= $version;
  143. $hash->{NOTIFYDEV} = "global";
  144. $hash->{OWNET_VERSION}= OWServer_loadOWNet($hash);
  145. if( $init_done ) {
  146. OWServer_OpenDev($hash);
  147. }
  148. return undef;
  149. }
  150. #####################################
  151. sub
  152. OWServer_Undef($$)
  153. {
  154. my ($hash, $arg) = @_;
  155. my $name = $hash->{NAME};
  156. foreach my $d (sort keys %defs) {
  157. if(defined($defs{$d}) &&
  158. defined($defs{$d}{IODev}) &&
  159. $defs{$d}{IODev} == $hash)
  160. {
  161. my $lev = ($reread_active ? 4 : 2);
  162. Log3 $name, $lev, "deleting OWServer for $d";
  163. delete $defs{$d}{IODev};
  164. }
  165. }
  166. OWServer_CloseDev($hash);
  167. return undef;
  168. }
  169. #####################################
  170. sub OWServer_getOWNetfilename($) {
  171. my ($v)= @_;
  172. return "lib/OWNet-$v.pm";
  173. }
  174. sub OWServer_hasOWNet($) {
  175. my ($v)= @_;
  176. my $filename= $attr{global}{modpath}."/FHEM/lib/OWNet-$v.pm";
  177. return -r $filename;
  178. }
  179. sub OWServer_loadOWNet($) {
  180. my ($hash) = @_;
  181. my $name = $hash->{NAME};
  182. if(defined($OWNet_version)) {
  183. Log3 $name, 3, "$name: owserver version not checked, using currently loaded OWNet version $OWNet_version";
  184. return $OWNet_version;
  185. }
  186. $OWNet_version= $hash->{OWNET_VERSION};
  187. my $libfilename= OWServer_getOWNetfilename($OWNet_version);
  188. Log3 $name, 5, "$name: Loading OWNet version $OWNet_version...";
  189. require $libfilename;
  190. Log3 $name, 3, "$name: OWNet version $OWNet_version loaded.";
  191. my $owserver= OWServer_TryOpenDev($hash);
  192. if(defined($owserver)) {
  193. my $version= $owserver->read("/system/configuration/version");
  194. if(defined($version)) {
  195. Log3 $name, 3, "$name: owserver version $version found.";
  196. $hash->{OWSERVER_VERSION}= $version;
  197. if($OWNet_version eq $version) {
  198. Log3 $name, 3, "$name: Matching OWNet version already loaded.";
  199. return $OWNet_version;
  200. }
  201. } else {
  202. Log3 $name, 2, "$name: Could not read owserver version, using OWNet version $OWNet_version.";
  203. return $OWNet_version;
  204. }
  205. my $libfilename= OWServer_getOWNetfilename($version);
  206. Log3 $name, 5, "$name: Looking for OWNet version $version in $libfilename...";
  207. if(OWServer_hasOWNet($version)) {
  208. # we temporarily disable the subroutine warning
  209. my $handler= $SIG{__WARN__};
  210. $SIG{__WARN__} = sub {
  211. my $warning= shift;
  212. warn $warning unless $warning =~ /Subroutine .* redefined at/;
  213. };
  214. Log3 $name, 5, "$name: Loading OWNet version $version...";
  215. require $libfilename;
  216. $SIG{__WARN__}= $handler;
  217. $OWNet_version= $version;
  218. Log3 $name, 3, "$name: OWNet version $OWNet_version loaded.";
  219. return $OWNet_version;
  220. } else {
  221. Log3 $name, 3, "$name: No matching OWNet version found, using OWNet version $OWNet_version.";
  222. }
  223. } else {
  224. Log3 $name, 2, "$name: Could not connect to owserver, using OWNet version $OWNet_version";
  225. return $OWNet_version;
  226. }
  227. # we should not get here
  228. return undef;
  229. }
  230. #####################################
  231. sub
  232. OWServer_CloseDev($)
  233. {
  234. my ($hash) = @_;
  235. my $name = $hash->{NAME};
  236. return unless(defined($hash->{fhem}{owserver}));
  237. delete $hash->{fhem}{owserver};
  238. readingsSingleUpdate($hash, "state", "DISCONNECTED", 1);
  239. }
  240. ########################
  241. sub
  242. OWServer_TryOpenDev($)
  243. {
  244. my ($hash) = @_;
  245. my $name = $hash->{NAME};
  246. OWServer_CloseDev($hash);
  247. my $protocol= $hash->{fhem}{protocol};
  248. Log3 $name, 3, "$name: Opening connection to OWServer $protocol...";
  249. my $owserver= OWNet->new($protocol);
  250. if($owserver) {
  251. Log3 $name, 3, "$name: Successfully connected to $protocol.";
  252. } else {
  253. Log3 $name, 2, "$name: Could not connect to $protocol.";
  254. }
  255. return $owserver
  256. }
  257. sub
  258. OWServer_OpenDev($)
  259. {
  260. my ($hash) = @_;
  261. my $owserver= OWServer_TryOpenDev($hash);
  262. if(defined($owserver)) {
  263. $hash->{fhem}{owserver}= $owserver;
  264. readingsSingleUpdate($hash, "state", "CONNECTED", 1);
  265. my $ret = OWServer_DoInit($hash);
  266. }
  267. return $owserver
  268. }
  269. #####################################
  270. sub
  271. OWServer_Notify($$)
  272. {
  273. my ($hash,$dev) = @_;
  274. my $name = $hash->{NAME};
  275. my $type = $hash->{TYPE};
  276. return if($dev->{NAME} ne "global");
  277. return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}));
  278. return if($attr{$name} && $attr{$name}{disable});
  279. OWServer_OpenDev($hash);
  280. return undef;
  281. }
  282. #####################################
  283. sub
  284. OWServer_DoInit($)
  285. {
  286. my $hash = shift;
  287. my $name = $hash->{NAME};
  288. my $owserver= $hash->{fhem}{owserver};
  289. foreach my $reading (sort keys %gets) {
  290. readingsBeginUpdate($hash);
  291. readingsBulkUpdate($hash,"$reading",$owserver->read("$reading"));
  292. readingsEndUpdate($hash,1);
  293. }
  294. readingsSingleUpdate($hash, "state", "Initialized", 1);
  295. OWServer_Autocreate($hash);
  296. return undef;
  297. }
  298. #####################################
  299. sub
  300. OWServer_Read($@)
  301. {
  302. my ($hash,$path)= @_;
  303. return undef unless(defined($hash->{fhem}{owserver}) || $hash->{LAST_READ_FAILED});
  304. my $ret= undef;
  305. if(AttrVal($hash->{NAME},"nonblocking",undef) && $init_done) {
  306. $hash->{".path"}= $path;
  307. pipe(READER,WRITER);
  308. #READER->autoflush(1);
  309. WRITER->autoflush(1);
  310. my $pid= fork;
  311. if(!defined($pid)) {
  312. Log3 $hash, 1, "OWServer: Cannot fork: $!";
  313. return undef;
  314. }
  315. InternalTimer(gettimeofday()+6, "OWServer_TimeoutChild", $pid, 0);
  316. if($pid == 0) {
  317. close READER;
  318. $ret= $hash->{fhem}{owserver}->read($path);
  319. $ret =~ s/^\s+//g if(defined($ret));
  320. my $r= defined($ret) ? $ret : "<undefined>";
  321. Log3 $hash, 5, "OWServer child read $path: $r";
  322. delete $hash->{".path"};
  323. print WRITER $ret if(defined($ret));
  324. close WRITER;
  325. # see http://forum.fhem.de/index.php?t=tree&goto=94670
  326. # changed from
  327. # exit 0;
  328. # to
  329. POSIX::_exit(0);
  330. }
  331. Log3 $hash, 5, "OWServer child ID for reading '$path' is $pid";
  332. close WRITER;
  333. # http://forum.fhem.de/index.php/topic,16945.0/topicseen.html#msg110673
  334. my ($rout,$rin, $eout,$ein) = ('','', '','');
  335. vec($rin, fileno(READER), 1) = 1;
  336. $ein = $rin;
  337. my $nfound = select($rout=$rin, undef, $eout=$ein, 4);
  338. if( $nfound ) {
  339. $ret= <READER>;
  340. if(defined($ret)) {
  341. chomp($ret) } else {
  342. Log3 $hash, 5, "OWServer: undefined response from child $pid";
  343. }
  344. RemoveInternalTimer($pid);
  345. OWServer_OpenDev($hash) if( $hash->{LAST_READ_FAILED} );
  346. $hash->{LAST_READ_FAILED} = 0;
  347. } else {
  348. Log3 undef, 1, "OWServer: read timeout for child $pid";
  349. $hash->{NR_READ_FAILED} = 0 if( !$hash->{NR_READ_FAILED} );
  350. $hash->{NR_READ_FAILED}++;
  351. OWServer_CloseDev($hash) if( !$hash->{LAST_READ_FAILED} );
  352. $hash->{LAST_READ_FAILED} = 1;
  353. }
  354. close READER;
  355. } else {
  356. $ret= $hash->{fhem}{owserver}->read($path);
  357. $ret =~ s/^\s+//g if(defined($ret));
  358. $hash->{LAST_READ_FAILED} = 0;
  359. }
  360. # if a device does not exist, the server returns undef
  361. # therefore it's not a good idea to blame the connection
  362. # and remove the server in such a case.
  363. #if(!defined($ret)) { OWServer_CloseDev($hash); }
  364. return $ret;
  365. }
  366. #####################################
  367. sub
  368. OWServer_TimeoutChild($)
  369. {
  370. my $pid= shift;
  371. Log3 undef, 1, "OWServer: Terminated child $pid" if($pid && kill(9, $pid));
  372. }
  373. #####################################
  374. sub
  375. OWServer_Write($@)
  376. {
  377. my ($hash,$path,$value)= @_;
  378. return undef if($hash->{LAST_READ_FAILED});
  379. return undef unless(defined($hash->{fhem}{owserver}));
  380. return $hash->{fhem}{owserver}->write($path,$value);
  381. }
  382. #####################################
  383. sub
  384. OWServer_Dir($@)
  385. {
  386. my ($hash,$path)= @_;
  387. return undef if($hash->{LAST_READ_FAILED});
  388. return undef unless(defined($hash->{fhem}{owserver}));
  389. $path= ($path) ? $path : "/";
  390. return $hash->{fhem}{owserver}->dir($path);
  391. }
  392. #####################################
  393. sub
  394. OWServer_Find($@)
  395. {
  396. my ($hash,$slave)= @_;
  397. return undef if($hash->{LAST_READ_FAILED});
  398. return undef unless(defined($hash->{fhem}{owserver}));
  399. my $owserver= $hash->{fhem}{owserver};
  400. my $fulldir= $owserver->dir("/");
  401. return undef unless(defined($fulldir));
  402. my @dir= split(",", $fulldir);
  403. my $path= undef;
  404. for my $entry (@dir) {
  405. $entry = substr($entry,1);
  406. next if($entry !~ m/^bus.\d+/m);
  407. my @busdir= split(",",$owserver->dir("/$entry"));
  408. $path= (grep { m/$slave/i } @busdir) ? $entry : undef;
  409. last if($path)
  410. }
  411. return $path;
  412. }
  413. #####################################
  414. sub
  415. OWServer_Autocreate($)
  416. {
  417. my ($hash)= @_;
  418. my $name = $hash->{NAME};
  419. my $acdname= "";
  420. foreach my $d (keys %defs) {
  421. next if($defs{$d}{TYPE} ne "autocreate");
  422. $acdname= $defs{$d}{NAME};
  423. return undef if(AttrVal($acdname,"disable",undef));
  424. }
  425. return undef unless($acdname ne "");
  426. my $owserver= $hash->{fhem}{owserver};
  427. my @dir= split(",", $owserver->dir("/"));
  428. my @devices= grep { m/^\/[0-9a-f]{2}.[0-9a-f]{12}$/i } @dir;
  429. my %defined = ();
  430. foreach my $d (keys %defs) {
  431. next if($defs{$d}{TYPE} !~ /^OW(Device|AD|ID|MULTI|COUNT|LCD|SWITCH|THERM)$/);
  432. if(defined($defs{$d}{fhem}) && defined($defs{$d}{fhem}{address})) {
  433. $defined{$defs{$d}{fhem}{address}} = $d;
  434. } elsif(defined($defs{$d}{OW_ID}) and defined($defs{$d}{OW_FAMILY})) {
  435. $defined{"$defs{$d}{OW_FAMILY}.$defs{$d}{OW_ID}"} = $d;
  436. }
  437. }
  438. my $created = 0;
  439. for my $device (@devices) {
  440. my $address= substr($device,1);
  441. my $family= substr($address,0,2);
  442. if(!exists $owfamily{$family}) {
  443. Log3 $name, 2, "$name: Autocreate: unknown familycode '$family' found. Please report this!";
  444. next;
  445. } else {
  446. my $type= $owserver->read($device . "/type");
  447. my $owtype= $owfamily{$family};
  448. if($owtype !~ m/$type/) {
  449. Log3 $name, 2, "$name: Autocreate: type '$type' not defined in familycode '$family'. Please report this!";
  450. next;
  451. } elsif( defined($defined{$address}) ) {
  452. Log3 $name, 5, "$name address '$address' already defined as '$defined{$address}'";
  453. next;
  454. } else {
  455. my $id= substr($address,3);
  456. my $devname= $type . "_" . $id;
  457. Log3 $name, 5, "$name create new device '$devname' for address '$address'";
  458. my $interval= ($family eq "81") ? "" : " 60";
  459. my $define= "$devname OWDevice $address" . $interval;
  460. my $cmdret;
  461. $cmdret= CommandDefine(undef,$define);
  462. if($cmdret) {
  463. Log3 $name, 1, "$name: Autocreate: An error occurred while creating device for address '$address': $cmdret";
  464. } else {
  465. $created++;
  466. $cmdret= CommandAttr(undef,"$devname room OWDevice");
  467. }
  468. }
  469. }
  470. }
  471. CommandSave(undef,undef) if( $created && AttrVal($acdname, "autosave", 1 ) );
  472. return undef;
  473. }
  474. #####################################
  475. sub
  476. OWServer_Get($@)
  477. {
  478. my ($hash, @a) = @_;
  479. my $name = $a[0];
  480. return "$name: get needs at least one parameter" if(@a < 2);
  481. my $cmd= $a[1];
  482. #my $arg = ($a[2] ? $a[2] : "");
  483. #my @args= @a; shift @args; shift @args;
  484. my $owserver= $hash->{fhem}{owserver};
  485. if($cmd eq "devices") {
  486. my @dir= split(",", $owserver->dir("/"));
  487. my @devices= grep { m/^\/[0-9a-f]{2}.[0-9a-f]{12}$/i } @dir;
  488. my $ret;
  489. for my $device (@devices) {
  490. my $name= "";
  491. my $address= substr($device,1);
  492. my $type= $owserver->read($device . "/type");
  493. foreach my $p (keys %defs) {
  494. $name= concatc(", ", $name, $p) if($defs{$p}{TYPE} eq "OWDevice" and $defs{$p}{fhem}{address} eq $address);
  495. }
  496. $ret .= sprintf("%s %10s %s\n", $address, $type, $name);
  497. }
  498. return $ret;
  499. } elsif($cmd eq "errors") {
  500. my $path= "statistics/errors";
  501. my @dir= split(",", $owserver->dir($path));
  502. my $wide= (reverse sort { $a <=> $b } map { length($_) } @dir)[0];
  503. $wide= $wide-length($path);
  504. my $ret= "=> $path:\n";
  505. for my $error (@dir) {
  506. my $stat= $owserver->read("$path/$error");
  507. my (undef, $str) = $error =~ m|^(.*[/\\])([^/\\]+?)$|;
  508. $str =~ s/_/ /g;
  509. $ret .= sprintf("%-*s %d\n",$wide,$str,($stat) ? $stat : 0);
  510. }
  511. return $ret;
  512. } elsif($cmd eq "/uncached/alarm") {
  513. # Oliver Vallant, 2017-04-17
  514. my $path= $cmd;
  515. my @devices= split(",", $owserver->dir($path));
  516. my $ret;
  517. for my $device (@devices) {
  518. my $name= "";
  519. my $address= substr($device, rindex($device, "/")+1);
  520. my $type= $owserver->read($device . "/type");
  521. foreach my $p (keys %defs) {
  522. $name= concatc(", ", $name, $p) if($defs{$p}{TYPE} eq "OWDevice" and $defs{$p}{fhem}{address} eq $address);
  523. }
  524. $ret .= sprintf("%s %10s %s\n", $address, $type, $name);
  525. }
  526. return $ret;
  527. } elsif(defined($gets{$cmd})) {
  528. my $ret;
  529. my $value= $owserver->read($cmd);
  530. readingsSingleUpdate($hash,$cmd,$value,1);
  531. return "$cmd => $value";
  532. } else {
  533. return "Unknown argument $cmd, choose one of devices ".join(" ", sort keys %gets);
  534. }
  535. }
  536. #####################################
  537. sub
  538. OWServer_Set($@)
  539. {
  540. my ($hash, @a) = @_;
  541. my $name = $a[0];
  542. # usage check
  543. #my $usage= "Usage: set $name classdef <classname> <filename> OR set $name reopen";
  544. my $usage= "Unknown argument $a[1], choose one of reopen ".join(" ", sort keys %sets);
  545. return $usage if($a[1] ne "reopen" && !defined($sets{$a[1]}));
  546. if((@a == 2) && ($a[1] eq "reopen")) {
  547. OWServer_OpenDev($hash);
  548. return undef;
  549. } elsif(@a == 3) {
  550. my $cmd= $a[1];
  551. my $value= $a[2];
  552. my $owserver= $hash->{fhem}{owserver};
  553. my $ret= $owserver->write("/settings/$cmd",$value);
  554. #return $ret if($ret);
  555. readingsSingleUpdate($hash,"/settings/$cmd",$value,1);
  556. }
  557. return undef;
  558. }
  559. #####################################
  560. 1;
  561. =pod
  562. =item device
  563. =item summary controls a One-Wire (1Wire) server instance
  564. =item summary_DE steuert eine Ausgabe eines One-Wire (1Wire) Servers
  565. =begin html
  566. <a name="OWServer"></a>
  567. <h3>OWServer</h3>
  568. <ul>
  569. <br>
  570. <a name="OWServerdefine"></a>
  571. <b>Define</b>
  572. <ul>
  573. <code>define &lt;name&gt; OWServer &lt;protocol&gt; [&lt;version&gt;]</code>
  574. <br><br>
  575. Defines a logical OWServer device which connects to an owserver.
  576. owserver is the server component of the
  577. <a href="http://owfs.org">owfs 1-Wire Filesystem</a>. It serves as abstraction layer
  578. for any 1-wire devices on a host. &lt;protocol&gt; has
  579. format &lt;hostname&gt;:&lt;port&gt;.
  580. For details see
  581. <a href="http://owfs.org/index.php?page=owserver_protocol">owserver documentation</a>.
  582. <p>
  583. The OWServer device uses
  584. <a href="http://owfs.cvs.sourceforge.net/viewvc/owfs/owfs/module/ownet/perl5/OWNet/lib/OWNet.pm">OWNet.pm from Sourceforge</a>
  585. to connect to the owserver.
  586. Currently, OWNet modules for versions 2.8p17 and 3.1p5 are deployed with FHEM.
  587. You can manually add more versions by extracting OWNet.pm from
  588. <a href="https://sourceforge.net/projects/owfs/files/owfs/">one of the
  589. available versions</a> and saving it as as
  590. <code>FHEM/lib/OWNet-&lt;version&gt.pm</code> in the FHEM directory
  591. structure.
  592. <p>
  593. The first connection to the owserver is made using version 3.1p5 unless
  594. you explicitely suggest another version using the optional
  595. <code>&lt;version&gt;</code> parameter. You should suggest a OWNet module
  596. version matching your actual owserver version if FHEM hangs after
  597. connecting to the owserver.
  598. <p>
  599. The OWServer device autodetects the owserver version and chooses a matching
  600. OWNet module from the list of available OWNet modules. If no matching OWNet
  601. module is found, the initially suggested version is used. The nightmare situation of two
  602. OWServer devices connecting to owserver instances with different versions is
  603. not handled correctly. The server and module versions are stored in the
  604. internals of the OWServer device for your reference.
  605. <p>
  606. The ow* version 3.1p5 packages provided with Debian Stretch and
  607. the ow* version 2.8p17 packages provided with Debian Jessie are fine.
  608. The ow* version 2.9 packages provided with Debian Jessie in combination with OWNet.pm as
  609. deployed with FHEM might have issues (feedback welcome).
  610. For Debian Jessie you could unzip
  611. <a href="http://forum.fhem.de/index.php?action=dlattach;topic=12219.0;attach=2463">owfs_2.8p17-1_all.zip</a> and install
  612. owserver, dependencies and what else you require with <code>dpkg -i &lt;package&gt;.deb</code>.
  613. <p>
  614. Please report issues and successes related to versions in the
  615. <a href="https://forum.fhem.de/index.php/board,26.0.html">1Wire board of the FHEM Forum</a>.
  616. <p>
  617. A typical working configuration file <code>/etc/owfs.conf</code> looks as follows:<p>
  618. <code>
  619. # server uses device /dev/onewire<br>
  620. server: device = /dev/onewire<br>
  621. # clients other than server use server<br>
  622. ! server: server = localhost:4304<br>
  623. # port<br>
  624. server: port = 4304<br>
  625. # owhttpd<br>
  626. http: port = 2121<br>
  627. # owftpd<br>
  628. ftp: port = 2120<br>
  629. </code>
  630. <p>
  631. The actual 1-wire devices are defined as <a href="#OWDevice">OWDevice</a> devices.
  632. If <a href="#autocreate">autocreate</a> is enabled, all the devices found are created at
  633. start of FHEM automatically.
  634. <br><br>
  635. This module is completely unrelated to the 1-wire modules with names all in uppercase.
  636. <br><br>
  637. Examples:
  638. <ul>
  639. <code>define myLocalOWServer OWServer localhost:4304</code><br>
  640. <code>define myRemoteOWServer OWServer raspi:4304 2.8p17</code><br>
  641. </ul>
  642. <br><br>
  643. Notice: if you get no devices add both <code>localhost</code> and the FQDN of your owserver as server directives
  644. to the owserver configuration file
  645. on the remote host.
  646. <br><br>
  647. </ul>
  648. <a name="OWServerset"></a>
  649. <b>Set</b>
  650. <ul>
  651. <code>set &lt;name&gt; &lt;value&gt;</code>
  652. <br><br>
  653. where <code>value</code> is one of<br><br>
  654. <li><code>reopen</code><br>
  655. Reopens the connection to the owserver.
  656. </li>
  657. <li>owserver (OWFS) specific settings:
  658. <ul>
  659. <li><code>timeout/directory</code></li>
  660. <li><code>timeout/ftp</code></li>
  661. <li><code>timeout/ha7</code></li>
  662. <li><code>timeout/network</code></li>
  663. <li><code>timeout/presence</code></li>
  664. <li><code>timeout/serial</code></li>
  665. <li><code>timeout/server</code></li>
  666. <li><code>timeout/stable</code></li>
  667. <li><code>timeout/uncached</code></li>
  668. <li><code>timeout/usb</code></li>
  669. <li><code>timeout/volatile</code></li>
  670. <li><code>timeout/w1</code></li>
  671. <li><code>units/pressure_scale</code></li>
  672. <li><code>units/temperature_scale</code></li>
  673. </ul>
  674. </li>
  675. For further informations have look on <a href="http://owfs.org/uploads/owserver.1.html#sect41">owserver manual</a>).
  676. <br>
  677. </ul>
  678. <br><br>
  679. <a name="OWServerget"></a>
  680. <b>Get</b>
  681. <ul>
  682. <code>get &lt;name&gt; &lt;value&gt;</code>
  683. <br><br>
  684. where <code>value</code> is one of<br><br>
  685. <li><code>devices</code><br>
  686. Lists the addresses and types of all 1-wire devices provided by the owserver. Also shows
  687. the corresponding <a href="#OWDevice">OWDevice</a> if one is defined for the respective 1-wire devices.
  688. </li>
  689. <li><code>errors</code><br>
  690. List a view of error statistics.</li>
  691. <li>owserver (OWFS) specific settings:
  692. <ul>
  693. <li><code>/settings/timeout/directory</code></li>
  694. <li><code>/settings/timeout/ftp</code></li>
  695. <li><code>/settings/timeout/ha7</code></li>
  696. <li><code>/settings/timeout/network</code></li>
  697. <li><code>/settings/timeout/presence</code></li>
  698. <li><code>/settings/timeout/serial</code></li>
  699. <li><code>/settings/timeout/server</code></li>
  700. <li><code>/settings/timeout/stable</code></li>
  701. <li><code>/settings/timeout/uncached</code></li>
  702. <li><code>/settings/timeout/usb</code></li>
  703. <li><code>/settings/timeout/volatile</code></li>
  704. <li><code>/settings/timeout/w1</code></li>
  705. <li><code>/settings/units/pressure_scale</code></li>
  706. <li><code>/settings/units/temperature_scale</code></li>
  707. <li><code>/uncached/alarm</code></li>
  708. </ul>
  709. </li>
  710. For further informations have look on <a href="http://owfs.org/uploads/owserver.1.html#sect41">owserver manual</a>).
  711. <br>
  712. </ul>
  713. <br><br>
  714. <a name="OWServerattr"></a>
  715. <b>Attributes</b>
  716. <ul>
  717. <li>nonblocking<br>
  718. Get all readings (OWServer / <a href="#OWDevice">OWDevice</a>) via a child process. This ensures, that FHEM
  719. is not blocked during communicating with the owserver.<br>
  720. Example:<br>
  721. <code> attr &lt;name&gt; nonblocking 1</code>
  722. </li>
  723. <li><a href="#eventMap">eventMap</a></li>
  724. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  725. </ul>
  726. <br><br>
  727. Note: unset <code>nonblocking</code> if you experience lockups of FHEM.
  728. </ul>
  729. =end html
  730. =begin html_DE
  731. <a name="OWServer"></a>
  732. <h3>OWServer</h3>
  733. <ul>
  734. <br>
  735. <a name="OWServerdefine"></a>
  736. <b>Definition</b>
  737. <ul>
  738. <code>define &lt;name&gt; OWServer &lt;protocol&gt; [&lt;version&gt;]</code>
  739. <br><br>
  740. Definiert eine logische OWServer-Instanz, die sich mit einem owserver
  741. verbindet. owserver ist die Serverkomponente des
  742. <a href="http://owfs.org">1-Wire Dateisystems</a>. Sie ermöglicht den Zugriff auf
  743. alle 1-Wire-Busteilnehmer eines Systems.
  744. &lt;protocol&gt; hat das Format &lt;hostname&gt;:&lt;port&gt;.
  745. Nähere Informationen dazu gibt es in
  746. der <a href="http://owfs.org/index.php?page=owserver_protocol">owserver Dokumentation</a>.
  747. <p>
  748. Die OWServer-Instanz verwendet
  749. <a href="http://owfs.cvs.sourceforge.net/viewvc/owfs/owfs/module/ownet/perl5/OWNet/lib/OWNet.pm">OWNet.pm von Sourceforge</a>,
  750. um sich mit dem owserver zu verbinden.
  751. Gegenw&auml;rtig werden OWNet-Module f&uuml;r die Versionen 2.8p17 and 3.1p5
  752. mit FHEM verteilt. Man kann manuell weitere Versionen hinzuf&uuml;gen,
  753. indem man OWNet.pm aus
  754. <a href="https://sourceforge.net/projects/owfs/files/owfs/">einer der
  755. verf&uuml;gbaren Versionen</a> extrahiert und als
  756. <code>FHEM/lib/OWNet-&lt;version&gt.pm</code> in der FHEM-Verzeichnisstruktur
  757. speichert.
  758. <p>
  759. Die erste Verbindung mit dem owserver wird mit der Version 3.1p5 aufgebaut,
  760. es sei denn, dass man ausdr&uuml;cklich eine andere Version mit dem
  761. optionalen Parameter
  762. <code>&lt;version&gt;</code> vorschl&auml;gt. Man sollte eine
  763. OWNet-Modulversion vorschlagen, die der tats&auml;chlichen Version von
  764. owserver entspricht, falls FHEM nach dem Verbindungsaufbau zum owserver
  765. h&auml;ngt.
  766. <p>
  767. Die OWServer-Instanz erkennt die Version von owserver automatisch und
  768. w&auml;hlt das passende OWNet-Modul aus der Liste der verf&uuml;gbaren
  769. OWNet-Module aus. Wenn kein passendes OWNet-Modul gefunden wird, wird die
  770. urspr&uuml;nglich vorgeschlagene Version verwendet. Die alptraumhafte Situation
  771. mit zwei OWServer-Instanzen, die sich mit owserver-Instanzen in
  772. unterschiedlichen Versionen verbinden, wird nicht korrekt gehandhabt.
  773. Die Versionen von Server und Modul werden zum Nachschauen in den Internals der
  774. OWServer-Instanz gespeichert.
  775. <p>
  776. Die ow*-Pakete in der Version 3.1p5 bei Debian Stretch und
  777. die ow*-Pakete in der Version 2.8p17 bei Debian Jessie sind gut.
  778. Die ow*-Pakete in der Version 2.9 bei Debian Jessie in Kombination mit den
  779. OWNet-Modulen bei FHEM k&ouml;nnen Auff&auml;lligkeiten zeigen (R&uuml;ckmeldung
  780. willkommen). F&uuml;r
  781. Debian Jessie kann man
  782. <a href="http://forum.fhem.de/index.php?action=dlattach;topic=12219.0;attach=2463">owfs_2.8p17-1_all.zip</a>
  783. auspacken und owserver, Abh&auml;ngigkeiten und was man sonst so braucht
  784. mittels <code>dpkg -i &lt;package&gt;.deb</code> installieren.
  785. <p>
  786. Bitte Auff&auml;lligkeiten und Erfolgsmeldungen zu Versionen im
  787. <a href="https://forum.fhem.de/index.php/board,26.0.html">1Wire-Board des FHEM-Forums</a> berichten.
  788. <p>
  789. Eine typische funktionierende Konfigurationsdatei <code>/etc/owfs.conf</code> sieht so aus:<p>
  790. <code>
  791. # server uses device /dev/onewire<br>
  792. server: device = /dev/onewire<br>
  793. # clients other than server use server<br>
  794. ! server: server = localhost:4304<br>
  795. # port<br>
  796. server: port = 4304<br>
  797. # owhttpd<br>
  798. http: port = 2121<br>
  799. # owftpd<br>
  800. ftp: port = 2120<br>
  801. </code>
  802. <p>
  803. Die vorhandenen 1-Wire- Busteilnehmer werden als <a href="#OWDevice">OWDevice</a> -Geräte definiert.
  804. Wenn <a href="#autocreate">autocreate</a> aktiviert ist, werden beim Start von FHEM alle Geräte automatisch erkannt und eingerichtet.
  805. <br><br>
  806. <b>Achtung: Dieses Modul ist weder verwandt noch verwendbar mit den 1-Wire Modulen, deren Namen nur aus Großbuchstaben bestehen!</b>
  807. <br><br>
  808. Beispiele für die Einrichtung:
  809. <ul>
  810. <code>define myLocalOWServer OWServer localhost:4304</code><br>
  811. <code>define myRemoteOWServer OWServer 192.168.1.100:4304</code><br>
  812. <code>define myRemoteOWServer OWServer raspi:4304</code><br>
  813. </ul>
  814. <br>
  815. Hinweis: Sollten keine Geräte erkannt werden, kann man versuchen in der owserver- Konfigurationsdatei (owfs.conf) zwei Servereinträge anzulegen:
  816. Einen mit <code>localhost</code> und einen mit dem "FQDN", bzw. dem Hostnamen, oder der IP-Adresse des Computers, auf dem die Software "owserver" läuft.
  817. <br><br>
  818. </ul>
  819. <a name="OWServerset"></a>
  820. <b>Set- Befehle</b>
  821. <ul>
  822. <code>set &lt;name&gt; &lt;value&gt;</code>
  823. <br><br>
  824. wobei <code>value</code> für einen der folgenden Befehle steht:<br><br>
  825. <li><code>reopen</code><br>
  826. Erneuert die Verbindung zum owserver.
  827. </li>
  828. <li>owserver (OWFS) -spezifische Einstellungen:
  829. <ul>
  830. <li><code>timeout/directory</code></li>
  831. <li><code>timeout/ftp</code></li>
  832. <li><code>timeout/ha7</code></li>
  833. <li><code>timeout/network</code></li>
  834. <li><code>timeout/presence</code></li>
  835. <li><code>timeout/serial</code></li>
  836. <li><code>timeout/server</code></li>
  837. <li><code>timeout/stable</code></li>
  838. <li><code>timeout/uncached</code></li>
  839. <li><code>timeout/usb</code></li>
  840. <li><code>timeout/volatile</code></li>
  841. <li><code>timeout/w1</code></li>
  842. <li><code>units/pressure_scale</code></li>
  843. <li><code>units/temperature_scale</code></li>
  844. </ul>
  845. </li>
  846. Nähere Informationen zu diesen Einstellungen gibt es im <a href="http://owfs.org/uploads/owserver.1.html#sect41">owserver- Manual</a>.
  847. <br>
  848. </ul>
  849. <br><br>
  850. <a name="OWServerget"></a>
  851. <b>Get- Befehle</b>
  852. <ul>
  853. <code>get &lt;name&gt; &lt;value&gt;</code>
  854. <br><br>
  855. wobei <code>value</code> für einen der folgenden Befehle steht:<br><br>
  856. <li><code>devices</code><br>
  857. Gibt eine Liste der Adressen und Typen aller von owserver erkannten Geräte aus. Außerdem
  858. werden die entsprechenden <a href="#OWDevice">OWDevice-</a> Namen angezeigt, soweit sie bereits definiert sind.
  859. </li>
  860. <li><code>errors</code><br>
  861. Liefert eine Fehlerstatistik zurück.</li>
  862. <li>owserver (OWFS) -spezifische Einstellungen:
  863. <ul>
  864. <li><code>/settings/timeout/directory</code></li>
  865. <li><code>/settings/timeout/ftp</code></li>
  866. <li><code>/settings/timeout/ha7</code></li>
  867. <li><code>/settings/timeout/network</code></li>
  868. <li><code>/settings/timeout/presence</code></li>
  869. <li><code>/settings/timeout/serial</code></li>
  870. <li><code>/settings/timeout/server</code></li>
  871. <li><code>/settings/timeout/stable</code></li>
  872. <li><code>/settings/timeout/uncached</code></li>
  873. <li><code>/settings/timeout/usb</code></li>
  874. <li><code>/settings/timeout/volatile</code></li>
  875. <li><code>/settings/timeout/w1</code></li>
  876. <li><code>/settings/units/pressure_scale</code></li>
  877. <li><code>/settings/units/temperature_scale</code></li>
  878. <li><code>/uncached/alarm</code></li>
  879. </ul>
  880. </li>
  881. Nähere Informationen zu diesen Einstellungen gibt es im <a href="http://owfs.org/uploads/owserver.1.html#sect41">owserver- Manual</a>.
  882. <br>
  883. </ul>
  884. <p>
  885. <a name="OWServerattr"></a>
  886. <b>Attribute</b>
  887. <ul>
  888. <li>nonblocking<br>
  889. Holt alle readings (OWServer / <a href="#OWDevice">OWDevice</a>) über einen Tochterprozess. Dieses Verfahren stellt sicher,
  890. dass FHEM während der Kommunikation mit owserver nicht angehalten wird.<br>
  891. Beispiel:<br>
  892. <code> attr &lt;name&gt; nonblocking 1</code>
  893. </li>
  894. <li><a href="#eventMap">eventMap</a></li>
  895. <li><a href="#readingFnAttributes">readingFnAttributes</a></li>
  896. </ul>
  897. <br>
  898. Hinweis: Falls in FHEM trotzdem ungewöhnliche Stillstände auftreten, sollte das Attribut <code>nonblocking</code> wieder deaktiviert werden.<br>
  899. </ul>
  900. =end html_DE
  901. =cut