98_autocreate.pm 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. ##############################################
  2. # $Id: 98_autocreate.pm 15620 2017-12-16 18:10:36Z rudolfkoenig $
  3. package main;
  4. use strict;
  5. use warnings;
  6. sub resolveSymLink($);
  7. # Problems:
  8. # - Not all CUL_EM devices return a power
  9. # - Not all CUL_WS devices return a temperature
  10. # - No plot files for BS/CUL_FHTTK/USF1000/X10/WS300
  11. # - check "UNDEFINED" parameters for BS/USF1000/X10
  12. my %flogpar = (
  13. # Oregon sensors:
  14. # * temperature
  15. "(THR128|THWR288A|THN132N|THGR132N).*"
  16. => { GPLOT => "temp4:Temp,", FILTER => "%NAME" },
  17. # * temperature, humidity
  18. "(THGR228N|THGR810|THGR918|THGR328N|RTGR328N|WTGR800_T|WT450H).*"
  19. => { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
  20. # * temperature, humidity, pressure
  21. "(BTHR918N|BTHR918|BTHR918N).*"
  22. => { GPLOT => "rain4press4:Temp/Press,temp4hum4:Temp/Hum,",
  23. FILTER => "%NAME" },
  24. # * anenometer
  25. "(WGR800|WGR918|WTGR800_A).*"
  26. => { GPLOT => "wind4windDir4:WindDir/WindSpeed,", FILTER => "%NAME" },
  27. # * Oregon sensors: Rain gauge
  28. "(PCR800|RGR918).*"
  29. => { GPLOT => "rain4:RainRate", FILTER => "%NAME" },
  30. # X10 sensors received by RFXCOM
  31. "(RFXX10SEC|TRX_DS10A).*"
  32. => { GPLOT => "fht80tf:Window,", FILTER => "%NAME" },
  33. # X10 Window sensors received by RFXTRX
  34. "TRX_DS10A.*"
  35. => { GPLOT => "fht80tf:Window,", FILTER => "%NAME" },
  36. # TX3 temperature sensors received by RFXTRX
  37. "TX3.*"
  38. => { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
  39. # USB-WDE1
  40. "USBWX_[0-8]"
  41. => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME" },
  42. "USBWX_ks300"
  43. => { GPLOT => "temp4hum6:Temp/Hum,temp4rain10:Temp/Rain,hum6wind8:Wind/Hum,",
  44. FILTER => "%NAME:T:.*" },
  45. # HomeMatic
  46. "CUL_HM_THSensor.*"
  47. => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME:T:.*" },
  48. "CUL_HM_KS550.*"
  49. => { GPLOT => "temp4rain10:Temp/Rain,hum6wind8:Wind/Hum,",
  50. FILTER => "%NAME:T:.*" },
  51. "CUL_HM_HM-CC-TC.*"
  52. => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME:T:.*" },
  53. );
  54. #####################################
  55. sub
  56. autocreate_Initialize($)
  57. {
  58. my ($hash) = @_;
  59. $hash->{DefFn} = "autocreate_Define";
  60. $hash->{NotifyFn} = "autocreate_Notify";
  61. $hash->{AttrFn} = "autocreate_Attr";
  62. $hash->{AttrList}= "autosave filelog device_room weblink weblink_room " .
  63. "disable ignoreTypes autocreateThreshold";
  64. my %ahash = ( Fn=>"CommandCreateLog",
  65. Hlp=>"<device>,create log/weblink for <device>",
  66. ModuleName => "autocreate" );
  67. $cmds{createlog} = \%ahash;
  68. my %bhash = ( Fn=>"CommandUsb",
  69. Hlp=>"[scan|create],display or create fhem-entries for USB devices",
  70. ModuleName => "autocreate" );
  71. $cmds{usb} = \%bhash;
  72. }
  73. #####################################
  74. sub
  75. autocreate_Define($$)
  76. {
  77. my ($hash, $def) = @_;
  78. my $name = $hash->{NAME};
  79. $hash->{STATE} = "active";
  80. $hash->{NOTIFYDEV} = "global";
  81. $attr{global}{autoload_undefined_devices} = 1; # Make sure we work correctly
  82. return undef;
  83. }
  84. sub
  85. replace_wildcards($$)
  86. {
  87. my ($hash, $str) = @_;
  88. return "" if(!$str);
  89. my $t = $hash->{TYPE}; $str =~ s/[%\$]TYPE/$t/g;
  90. my $n = $hash->{NAME}; $str =~ s/[%\$]NAME/$n/g;
  91. return $str;
  92. }
  93. #####################################
  94. sub
  95. autocreate_Notify($$)
  96. {
  97. my ($ntfy, $dev) = @_;
  98. my $me = $ntfy->{NAME};
  99. my $max = int(@{$dev->{CHANGED}});
  100. my $ret = "";
  101. my $nrcreated;
  102. for (my $i = 0; $i < $max; $i++) {
  103. my $s = $dev->{CHANGED}[$i];
  104. $s = "" if(!defined($s));
  105. my $temporary;
  106. ################
  107. # Special for EnOcean. DO NOT use it elsewhere
  108. if($s =~ m/^UNDEFINED -temporary/) {
  109. $temporary = 1;
  110. $s =~ s/ -temporary//;
  111. }
  112. if($s =~ m/^UNDEFINED ([^ ]*) ([^ ]*) (.*)$/) {
  113. my ($name, $type, $arg) = ($1, $2, $3);
  114. next if(AttrVal($me, "disable", undef));
  115. my $it = AttrVal($me, "ignoreTypes", undef);
  116. $it = "^$it\$" if($featurelevel > 5.8); # Forum #80775
  117. next if($it && $name =~ m/$it/i);
  118. my $at = AttrVal($me, "autocreateThreshold", undef);
  119. LoadModule($type) if( !$at );
  120. if( $at || $modules{$type}{AutoCreate} ) {
  121. my @at = split( '[, ]', $at?$at:"" );
  122. my $hash = $defs{$me};
  123. my $now = gettimeofday();
  124. #remove old events
  125. foreach my $t (keys %{$hash->{received}}) {
  126. my @v = grep { my $l = $_;
  127. $l =~ s/:.*//;
  128. ($t=~ m/^$l$/) ? $_ : undef} @at;
  129. my (undef,undef,$interval) = split( ':', $v[0]?$v[0]:"" );
  130. if( !@v ) {
  131. if( my $fp = $modules{$t}{AutoCreate} ) {
  132. foreach my $k (keys %{$fp}) {
  133. next if($name !~ m/^$k$/ || !$fp->{$k}{autocreateThreshold});
  134. (undef, $interval) = split( ':',$fp->{$k}{autocreateThreshold});
  135. last;
  136. }
  137. }
  138. }
  139. $interval = 60 if( !$interval );
  140. foreach my $a (keys %{$hash->{received}{$t}}) {
  141. foreach my $time (keys %{$hash->{received}{$t}{$a}}) {
  142. if( $time < $now - $interval ) {
  143. #Log3 $me, 5,
  144. # "autocreate: removed event for '$t $a' with timestamp $time";
  145. delete( $hash->{received}{$t}{$a}{$time} );
  146. }
  147. }
  148. delete($hash->{received}{$t}{$a}) if(!%{$hash->{received}{$t}{$a}});
  149. }
  150. delete( $hash->{received}{$t} ) if( !%{$hash->{received}{$t}} );
  151. }
  152. my @v = grep { my $l = $_;
  153. $l =~ s/:.*//;
  154. ($type=~ m/^$l$/) ? $_ : undef} @at;
  155. #if there is an entry for this type
  156. if( @v || $modules{$type}{AutoCreate} ) {
  157. my( undef, $min_count, $interval ) = split( ':', $v[0]?$v[0]:"" );
  158. my $found;
  159. if( !@v ) {
  160. if( my $fp = $modules{$type}{AutoCreate} ) {
  161. foreach my $k (keys %{$fp}) {
  162. next if($name !~ m/^$k$/ || !$fp->{$k}{autocreateThreshold});
  163. ($min_count, $interval) =
  164. split(':', $fp->{$k}{autocreateThreshold});
  165. $found = 1;
  166. last;
  167. }
  168. }
  169. }
  170. if( @v || $found ) {
  171. $min_count = 2 if( !$min_count );
  172. $interval = 60 if( !$interval );
  173. #add this event
  174. $hash->{received}{$type}{$arg}{$now} = 1;
  175. my $count = keys %{$hash->{received}{$type}{$arg}};
  176. Log3 $me, 4, "autocreate: received $count event(s) for ".
  177. "'$type $arg' during the last $interval seconds";
  178. if( $count < $min_count ) {
  179. Log3 $me, 4, "autocreate: ignoring event for ".
  180. "'$type $arg': at least $min_count needed";
  181. next;
  182. }
  183. }
  184. #forget entries for this type
  185. delete( $hash->{received}{$type}{$arg} );
  186. delete( $hash->{received}{$type} ) if( !%{$hash->{received}{$type}} );
  187. }
  188. }
  189. my ($cmd, $ret);
  190. my $hash = $defs{$name}; # Called from createlog
  191. ####################
  192. if(!$hash) {
  193. $cmd = "$name $type $arg";
  194. $cmd = "-temporary $name $type $arg" if($temporary);
  195. Log3 $me, 2, "autocreate: define $cmd";
  196. $ret = CommandDefine(undef, $cmd);
  197. if($ret) {
  198. Log3 $me, 1, "ERROR: $ret";
  199. last;
  200. }
  201. }
  202. $hash = $defs{$name};
  203. $nrcreated++;
  204. my $room = replace_wildcards($hash, AttrVal($me, "device_room", "%TYPE"));
  205. # preserve room for createlog
  206. $room = $attr{$name}{room} if($attr{$name} && $attr{$name}{room});
  207. $attr{$name}{room} = $room if($room);
  208. $nrcreated = 0 if($temporary); # do not save
  209. next if($modules{$hash->{TYPE}}{noAutocreatedFilelog} || $temporary);
  210. ####################
  211. my $fl = replace_wildcards($hash, AttrVal($me, "filelog", ""));
  212. my $flname = "FileLog_$name";
  213. delete($defs{$flname}) if($fl); # If we are re-creating it with createlog.
  214. my ($gplot, $filter, $devattr) = ("", $name, "");
  215. my $fp = $modules{$hash->{TYPE}}{AutoCreate};
  216. $fp = \%flogpar if(!$fp);
  217. foreach my $k (keys %{$fp}) {
  218. next if($name !~ m/^$k$/);
  219. $gplot = $fp->{$k}{GPLOT};
  220. $filter = replace_wildcards($hash, $fp->{$k}{FILTER});
  221. $devattr = $fp->{$k}{ATTR};
  222. last;
  223. }
  224. if($fl) {
  225. $cmd = "$flname FileLog $fl $filter";
  226. Log3 $me, 2, "autocreate: define $cmd";
  227. $ret = CommandDefine(undef, $cmd);
  228. if($ret) {
  229. Log3 $me, 1, "ERROR: $ret";
  230. last;
  231. }
  232. $attr{$flname}{room} = $room if($room);
  233. $attr{$flname}{logtype} = "${gplot}text";
  234. }
  235. if($devattr) {
  236. foreach my $attrNV (split(" ", $devattr)) {
  237. my ($an, $av) = split(":", $attrNV, 2);
  238. CommandAttr(undef, "$name $an $av");
  239. }
  240. }
  241. ####################
  242. next if(!AttrVal($me, "weblink", 1) || !$gplot || !$fl);
  243. $room = replace_wildcards($hash, AttrVal($me, "weblink_room", "Plots"));
  244. my $wnr = 1;
  245. foreach my $wdef (split(/,/, $gplot)) {
  246. next if(!$wdef);
  247. my ($gplotfile, $stuff) = split(/:/, $wdef);
  248. next if(!$gplotfile);
  249. my $wlname = "SVG_$name";
  250. $wlname .= "_$wnr" if($wnr > 1);
  251. $wnr++;
  252. delete($defs{$wlname}); # If we are re-creating it with createlog.
  253. $cmd = "$wlname SVG $flname:$gplotfile:CURRENT";
  254. Log3 $me, 2, "autocreate: define $cmd";
  255. $ret = CommandDefine(undef, $cmd);
  256. if($ret) {
  257. Log3 $me, 1, "ERROR: define $cmd: $ret";
  258. last;
  259. }
  260. $attr{$wlname}{room} = $room if($room);
  261. $attr{$wlname}{label} = '"' . $name .
  262. ' Min $data{min1}, Max $data{max1}, Last $data{currval1}"';
  263. $ret = CommandSet(undef, "$wlname copyGplotFile");
  264. if($ret) {
  265. Log3 $me, 1, "ERROR: set $wlname copyGplotFile: $ret";
  266. last;
  267. }
  268. }
  269. }
  270. ################
  271. if($s =~ m/^RENAMED ([^ ]*) ([^ ]*)$/) {
  272. my ($old, $new) = ($1, $2);
  273. if($defs{"FileLog_$old"}) {
  274. CommandRename(undef, "FileLog_$old FileLog_$new");
  275. my $hash = $defs{"FileLog_$new"};
  276. my $oldfile = $hash->{currentlogfile};
  277. $hash->{DEF} =~ s/$old/$new/g;
  278. $hash->{REGEXP} =~ s/$old/$new/g;
  279. $hash->{logfile} =~ s/$old/$new/g;
  280. $hash->{currentlogfile} =~ s/$old/$new/g;
  281. Log3 $me, 2, "autocreate: renamed FileLog_$old to FileLog_$new";
  282. $nrcreated++;
  283. notifyRegexpChanged($hash, $hash->{REGEXP});
  284. # Content
  285. if($oldfile ne $hash->{currentlogfile} &&
  286. open(IN, $oldfile) && open(OUT, ">".$hash->{currentlogfile})) {
  287. while(my $l = <IN>) {
  288. $l =~ s/$old/$new/;
  289. syswrite(OUT, $l);
  290. }
  291. close(IN); close(OUT);
  292. unlink($oldfile);
  293. my $fh = new IO::File ">>$hash->{currentlogfile}";
  294. $hash->{FH} = $fh;
  295. } else {
  296. Log 1, "$oldfile or $hash->{currentlogfile}: $!";
  297. close(IN);
  298. }
  299. }
  300. if($defs{"SVG_$old"}) {
  301. CommandRename(undef, "SVG_$old SVG_$new");
  302. my $hash = $defs{"SVG_$new"};
  303. my $oldfile = $hash->{GPLOTFILE};
  304. $hash->{DEF} =~ s/$old/$new/g;
  305. $hash->{GPLOTFILE} =~ s/$old/$new/g;
  306. $hash->{LOGDEVICE} =~ s/$old/$new/g;
  307. $attr{"SVG_$new"}{label} =~ s/$old/$new/g;
  308. Log3 $me, 2, "autocreate: renamed SVG_$old to SVG_$new";
  309. use vars qw($FW_gplotdir);# gplot directory
  310. if($oldfile ne $hash->{GPLOTFILE} && $FW_gplotdir) {
  311. $oldfile = $FW_gplotdir."/".$oldfile.".gplot";
  312. my $newfile = $FW_gplotdir."/".$hash->{GPLOTFILE}.".gplot";
  313. if(open(IN, $oldfile) && open(OUT, ">$newfile")) {
  314. while(my $l = <IN>) {
  315. $l =~ s/$old/$new/;
  316. syswrite(OUT, $l);
  317. }
  318. close(IN); close(OUT);
  319. unlink($oldfile);
  320. } else {
  321. Log 1, "$oldfile or $newfile: $!";
  322. close(IN);
  323. }
  324. }
  325. $nrcreated++;
  326. }
  327. }
  328. }
  329. CommandSave(undef, undef) if(!$ret && $nrcreated &&
  330. AttrVal($me,"autosave", 1));
  331. return $ret;
  332. }
  333. # TODO: fix it if the device is renamed.
  334. sub
  335. CommandCreateLog($$)
  336. {
  337. my ($cl, $n) = @_;
  338. my $ac;
  339. foreach my $d (keys %defs) {
  340. next if($defs{$d}{TYPE} ne "autocreate");
  341. $ac = $d;
  342. last;
  343. }
  344. return "Please define an autocreate device with attributes first " .
  345. "(it may be disabled)" if(!$ac);
  346. return "No device named $n found" if(!$defs{$n});
  347. my $acd = $defs{$ac};
  348. my $disabled = AttrVal($ac, "disable", undef);
  349. delete $attr{$ac}{disable} if($disabled);
  350. $acd->{CHANGED}[0] = "UNDEFINED $n $defs{$n}{TYPE} none";
  351. autocreate_Notify($acd, $acd);
  352. delete $acd->{CHANGED};
  353. $attr{$ac}{disable} = 1 if($disabled);
  354. }
  355. my %ac_links=();
  356. # Optimized for linux /dev/serial/by-path/... links
  357. sub
  358. resolveSymLink($)
  359. {
  360. my ($name) = @_;
  361. return $ac_links{$name} if($ac_links{$name});
  362. return $name if($^O =~ m/Win/ || !-l $name);
  363. my $link = readlink($name);
  364. return $name if(!$link);
  365. my @p = split("/", $name);
  366. pop(@p);
  367. foreach my $l (split("/", $link)) {
  368. next if($l eq ".");
  369. if($l ne "..") {
  370. push(@p, $l); next;
  371. }
  372. pop(@p);
  373. push(@p,"") if(@p == 0); # root directory
  374. }
  375. $link = resolveSymLink(join("/", @p));
  376. $ac_links{$name} = $link;
  377. return $link;
  378. }
  379. ##########################
  380. # Table for automatically creating IO devices
  381. # PARAM in define will be replaced with the $1 from matchList
  382. my @usbtable = (
  383. { NAME => "CUL",
  384. matchList => ['cu.usbmodem.*(.)$', 'ttyACM.*(.)$'],
  385. DeviceName=> "DEVICE\@9600",
  386. flush => "\n",
  387. request => "V\n",
  388. response => "^V .* CU.*",
  389. define => "CUL_PARAM CUL DEVICE\@9600 1PARAM34", },
  390. { NAME => "CUL", # TuxRadio/RPi: CSM, SCC
  391. matchList => ["ttySP(.+)", "ttyAMA(.+)", "ttyS(.)" ],
  392. DeviceName=> "DEVICE\@38400",
  393. flush => "\n",
  394. request => "V\n",
  395. response => "^V .* CSM.*",
  396. define => "CUL_PARAM CUL DEVICE\@38400 1PARAM34", },
  397. { NAME => "TCM_ESP3",
  398. matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)",
  399. "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"],
  400. DeviceName=> "DEVICE\@57600",
  401. request => pack("H*", "5500010005700838"), # get idbase
  402. response => "^\x55\x00\x05\x01",
  403. define => "TCM_ESP3_PARAM TCM ESP3 DEVICE\@57600", },
  404. { NAME => "TCM_ESP2",
  405. matchList => ["ttyUSB(.*)"],
  406. DeviceName=> "DEVICE\@9600",
  407. request => pack("H*", "A55AAB5800000000000000000003"), # get idbase
  408. response => "^\xA5\x5A............",
  409. define => "TCM_ESP2_PARAM TCM ESP2 DEVICE\@9600", },
  410. { NAME => "FHZ",
  411. matchList => ["cu.usbserial(.*)", "ttyUSB(.*)"],
  412. DeviceName=> "DEVICE\@9600",
  413. request => pack("H*", "8105044fc90185"), # get fhtbuf
  414. response => "^\x81........",
  415. define => "FHZ_PARAM FHZ DEVICE", },
  416. { NAME => "TRX",
  417. matchList => ["cu.usbserial(.*)", "ttyUSB(.*)"],
  418. DeviceName=> "DEVICE\@38400",
  419. init => pack("H*", "0D00000000000000000000000000"), # Reset
  420. request => pack("H*", "0D00000102000000000000000000"), # GetStatus
  421. response => "^\x0d\x01\x00...........",
  422. define => "TRX_PARAM TRX DEVICE\@38400", },
  423. { NAME => "ZWDongle",
  424. matchList => ["cu.PL2303-0000(.*)", "cu.usbmodem(.*)",
  425. "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)" ],
  426. DeviceName=> "DEVICE\@115200",
  427. request => pack("H*", "01030020dc06"), # GetStatus +ACK
  428. response => "^\x06.*",
  429. define => "ZWDongle_PARAM ZWDongle DEVICE\@115200", },
  430. { NAME => "FRM",
  431. matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)",
  432. "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"],
  433. DeviceName=> "DEVICE\@57600",
  434. init => pack("H*", "F9"), # Reset
  435. timeout => 5.0, # StandardFirmata blink takes time
  436. request => pack("H*", "F079F7"), # Query firmware version and filename START_SYSEX (0xF0), queryFirmware (0x79), END_SYSEX (0xF7)
  437. response => "^\xF0\x79(.*)\xF7", # Response Sysex xF0 x78 (2 Byte version) (n Byte filename) Endsysex xF7
  438. define => "FRM_PARAM FRM DEVICE\@57600", },
  439. );
  440. sub
  441. CommandUsb($$)
  442. {
  443. my ($cl, $n) = @_;
  444. return "Usage: usb [scan|create]" if("$n" !~ m/^(scan|create)$/);
  445. my $scan = 1 if($n eq "scan");
  446. my $ret = "";
  447. my $msg;
  448. my $dir = "/dev";
  449. if($^O =~ m/Win/) {
  450. return "This command is not yet supported on windows";
  451. }
  452. require "$attr{global}{modpath}/FHEM/DevIo.pm";
  453. Log3 undef, 1, "usb $n starting";
  454. ################
  455. # First try to flash unflashed CULs
  456. if($^O eq "linux") {
  457. # One device at a time to avoid endless loop
  458. my $lsusb = `lsusb`;
  459. if($lsusb) {
  460. my $culType;
  461. $culType = "CUL_V4" if($lsusb =~ m/VID=03eb.PID=2ff0/s); # FritzBox
  462. $culType = "CUL_V3" if($lsusb =~ m/VID=03eb.PID=2ff4/s); # FritzBox
  463. $culType = "CUL_V2" if($lsusb =~ m/VID=03eb.PID=2ffa/s); # FritzBox
  464. $culType = "CUL_V4" if($lsusb =~ m/03eb:2ff0/);
  465. $culType = "CUL_V3" if($lsusb =~ m/03eb:2ff4/);
  466. $culType = "CUL_V2" if($lsusb =~ m/03eb:2ffa/);
  467. if($culType) {
  468. $msg = "$culType: flash it with: CULflash none $culType";
  469. Log3 undef, 2, $msg; $ret .= $msg . "\n";
  470. if(!$scan) {
  471. AnalyzeCommand(undef, "culflash none $culType"); # Enable autoload
  472. sleep(4); # Leave time for linux to load th drivers
  473. }
  474. }
  475. }
  476. }
  477. ################
  478. # Now the /dev scan
  479. foreach my $dev (sort split("\n", `ls $dir`)) {
  480. foreach my $thash (@usbtable) {
  481. foreach my $ml (@{$thash->{matchList}}) {
  482. if($dev =~ m/$ml/) {
  483. my $PARAM = $1;
  484. $PARAM =~ s/[^A-Za-z0-9]//g;
  485. my $name = $thash->{NAME};
  486. $msg = "### $dev: checking if it is a $name";
  487. Log3 undef, 4, $msg; $ret .= $msg . "\n";
  488. # Check if it already used
  489. foreach my $d (keys %defs) {
  490. if($defs{$d}{DeviceName}) {
  491. my $dn = $defs{$d}{DeviceName};
  492. $dn =~ s/@.*//;
  493. if(resolveSymLink($dn) eq resolveSymLink("/dev/$dev")) {
  494. $msg = "$dev is already used by the fhem device $d";
  495. Log3 undef, 4, $msg; $ret .= $msg . "\n";
  496. goto NEXTDEVICE;
  497. }
  498. }
  499. }
  500. # Open the device
  501. my $dname = $thash->{DeviceName};
  502. $dname =~ s,DEVICE,$dir/$dev,g;
  503. my $hash = { NAME=>$name, DeviceName=>$dname, DevioText=>"Probing" };
  504. DevIo_OpenDev($hash, 0, 0);
  505. if(!defined($hash->{USBDev})) {
  506. DevIo_CloseDev($hash); # remove the ReadyFn loop
  507. $msg = "cannot open the device";
  508. Log3 undef, 4, $msg; $ret .= $msg . "\n";
  509. goto NEXTDEVICE;
  510. }
  511. # Send reset (optional)
  512. if(defined($thash->{init})) {
  513. DevIo_SimpleWrite($hash, $thash->{init}, 0);
  514. DevIo_TimeoutRead($hash, $thash->{timeout} ? $thash->{timeout}:0.5);
  515. }
  516. # Clear the USB buffer
  517. DevIo_SimpleWrite($hash, $thash->{flush}, 0) if($thash->{flush});
  518. DevIo_TimeoutRead($hash, 0.1);
  519. DevIo_SimpleWrite($hash, $thash->{request}, 0);
  520. my $answer = DevIo_TimeoutRead($hash, 0.1);
  521. DevIo_CloseDev($hash);
  522. if($answer !~ m/$thash->{response}/) {
  523. $msg = "got wrong answer for a $name";
  524. Log3 undef, 4, $msg; $ret .= $msg . "\n";
  525. next;
  526. }
  527. my $define = $thash->{define};
  528. $define =~ s/PARAM/$PARAM/g;
  529. $define =~ s,DEVICE,$dir/$dev,g;
  530. $msg = "create as a fhem device with: define $define";
  531. Log3 undef, 4, $msg; $ret .= $msg . "\n";
  532. if(!$scan) {
  533. Log3 undef, 1, "define $define";
  534. my $lret = CommandDefine($cl, $define);
  535. CommandSave(undef, undef)
  536. if(!$lret && AttrVal("global","autosave",1));
  537. }
  538. goto NEXTDEVICE;
  539. }
  540. }
  541. }
  542. NEXTDEVICE:
  543. }
  544. Log3 undef, 1, "usb $n end";
  545. return ($scan ? $ret : undef);
  546. }
  547. ###################################
  548. sub
  549. autocreate_Attr(@)
  550. {
  551. my @a = @_;
  552. my $do = 0;
  553. if($a[0] eq "set" && $a[2] eq "disable") {
  554. $do = (!defined($a[3]) || $a[3]) ? 1 : 2;
  555. }
  556. $do = 2 if($a[0] eq "del" && (!$a[2] || $a[2] eq "disable"));
  557. return if(!$do);
  558. $defs{$a[1]}{STATE} = ($do == 1 ? "disabled" : "active");
  559. return undef;
  560. }
  561. 1;
  562. =pod
  563. =item helper
  564. =item summary automatically create not yet defined FHEM devices
  565. =item summary_DE Erzeugt FHEM-Ger&auml;te automatisch
  566. =begin html
  567. <a name="autocreate"></a>
  568. <h3>autocreate</h3>
  569. <ul>
  570. Automatically create not yet defined FHEM devices upon reception of a message
  571. generated by this device. Note: devices which are polled (like the EMEM/EMWZ
  572. accessed through the EM1010PC) will NOT be automatically created.
  573. <br>
  574. <a name="autocreatedefine"></a>
  575. <b>Define</b>
  576. <ul>
  577. <code>define &lt;name&gt; autocreate</code><br>
  578. <br>
  579. <ul>
  580. By defining an instance, the global attribute <a href=
  581. "#autoload_undefined_devices">autoload_undefined_devices</a>
  582. is set, so that modules for unknnown devices are automatically loaded.
  583. The autocreate module intercepts the UNDEFINED event generated by each
  584. module, creates a device and optionally also FileLog and SVG
  585. entries.<br>
  586. <b>Note 1:</b> devices will be created with a unique name, which contains
  587. the type and a unique id for this type. When <a href="#rename">renaming
  588. </a> the device, the automatically created filelog and SVG devices
  589. will also be renamed.<br>
  590. <b>Note 2:</b> you can disable the automatic creation by setting the
  591. <a href="#disable">disable</a> attribute, in this case only the rename
  592. hook is active, and you can use the <a href="#createlog">createlog</a>
  593. command to add FileLog and SVG to an already defined device.
  594. <b>Note 3:</b> It makes no sense to create more than one instance of this
  595. module.
  596. </ul>
  597. <br>
  598. Example:<PRE>
  599. define autocreate autocreate
  600. attr autocreate autosave
  601. attr autocreate device_room %TYPE
  602. attr autocreate filelog test2/log/%NAME-%Y.log
  603. attr autocreate weblink
  604. attr autocreate weblink_room Plots
  605. </PRE>
  606. </ul>
  607. <a name="autocreateset"></a>
  608. <b>Set</b> <ul>N/A</ul><br>
  609. <a name="autocreateget"></a>
  610. <b>Get</b> <ul>N/A</ul><br>
  611. <a name="autocreateattr"></a>
  612. <b>Attributes</b>
  613. <ul>
  614. <a name="autosave"></a>
  615. <li>autosave<br>
  616. After creating a device, automatically save the config file with the
  617. command <a href="#save">save</a> command. Default is 1 (i.e. on), set
  618. it to 0 to switch it off.<br>
  619. <b>Note</b>: this attribute is deprecated, use the global autosave
  620. attribute instead.
  621. </li><br>
  622. <a name="device_room"></a>
  623. <li>device_room<br>
  624. "Put" the newly created device in this room. The name can contain the
  625. wildcards %TYPE and %NAME, see the example above.</li><br>
  626. <a name="filelogattr"></a>
  627. <li>filelog<br>
  628. Create a filelog associated with the device. The filename can contain
  629. the wildcards %TYPE and %NAME, see the example above. The filelog will
  630. be "put" in the same room as the device.</li><br>
  631. <a name="weblinkattr"></a>
  632. <li>weblink<br>
  633. Create an SVG associated with the device/filelog.</li><br>
  634. <a name="weblink_room"></a>
  635. <li>weblink_room<br>
  636. "Put" the newly created SVG in this room. The name can contain the
  637. wildcards %TYPE and %NAME, see the example above.</li><br>
  638. <li><a href="#disable">disable</a></li>
  639. <br>
  640. <a name="ignoreTypes"></a>
  641. <li>ignoreTypes<br>
  642. This is a regexp, to ignore certain devices, e.g. the neighbours FHT.
  643. You can specify more than one, with usual regexp syntax, e.g.<br>
  644. attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)<br>
  645. The word "Types" is somehow misleading, as it actually checks the
  646. generated device name.<br>
  647. <b>Note</b>: starting with featurelevel 5.9 the regexp is automatically
  648. extended with ^ and $, so that it must match the whole name (same
  649. procedure as in notify and FileLog).
  650. </li><br>
  651. <a name="autocreateThreshold"></a>
  652. <li>autocreateThreshold<br>
  653. A list of &lt;type&gt;:&lt;count&gt;:&lt;interval&gt; triplets. A new
  654. device is only created if there have been at least <code>count</code>
  655. events of TYPE <code>type</code> in the last <code>interval</code>
  656. seconds.<br> <code>attr autocreateThreshold
  657. LaCrosse:2:30,EMT7110:2:60</code>
  658. </li>
  659. </ul>
  660. <br>
  661. <a name="createlog"></a>
  662. <b>createlog</b>
  663. <ul>
  664. Use this command to manually add a FileLog and an SVG to an existing
  665. device.
  666. This command is part of the autocreate module.
  667. </ul>
  668. <br>
  669. <a name="usb"></a>
  670. <b>usb</b>
  671. <ul>
  672. Usage:
  673. <ul><code>
  674. usb scan<br>
  675. usb create<br>
  676. </code></ul>
  677. This command will scan the /dev directory for attached USB devices, and
  678. will try to identify them. With the argument scan you'll get back a list
  679. of FHEM commands to execute, with the argument create there will be no
  680. feedback, and the devices will be created instead.<br><br>
  681. Note that switching a CUL to HomeMatic mode is still has to be done
  682. manually.<br><br>
  683. On Linux it will also check with the lsusb command, if unflashed CULs are
  684. attached. If this is the case, it will call CULflash with the appropriate
  685. parameters (or display the CULflash command if scan is specified). The
  686. usb command will only flash one device per call.<br><br>
  687. This command is part of the autocreate module.
  688. </ul>
  689. </ul>
  690. <br>
  691. =end html
  692. =begin html_DE
  693. <a name="autocreate"></a>
  694. <h3>autocreate</h3>
  695. <ul>
  696. Erzeugt f&uuml;r noch nicht definierte FHEM-Ger&auml;te automatisch die
  697. geignete Definition (define). Diese Definition wird aus einer Nachricht
  698. gewonnen, die von diesen neuen Ger&auml;ten empfangen wurde. Hinweis:
  699. Ger&auml;te, die mit Polling arbeiten (wie z.B. der Zugriff auf EMEM/EMWZ
  700. &uuml;ber EM1010PC) werden NICHT automatisch erzeugt.
  701. <br><br>
  702. <a name="autocreatedefine"></a>
  703. <b>Define</b>
  704. <ul>
  705. <code>define &lt;name&gt; autocreate</code><br>
  706. <br>
  707. <ul>
  708. Durch die Definition dieser Instanz wird das globale Attribut <a
  709. href="#autoload_undefined_devices">autoload_undefined_devices</a>
  710. gesetzt, sodass die Module f&uuml;r unbekannte Ger&auml;te automatisch
  711. nachgeladen werden. Das autocreate-Modul interpretiert das
  712. UNDEFINED-event, welches von jedem Modul gestartet wird, erzeugt ein
  713. Ger&auml;t (device) und bei Bedarf ein FileLog sowie
  714. SVG-Eintr&auml;ge.<br>
  715. <b>Hinweis 1:</b> Ger&auml;te werden mit einem eindeutigen Namen erzeugt,
  716. der den Typ und eine individuelle ID f&uuml;r diesen Typ enth&auml;lt.
  717. Wird ein Ger&auml;t umbenannt (<a href="#rename">rename</a>), wird
  718. gleichzeitig das automatisch erzeugte FileLog und die SVG Ger&auml;te
  719. unbenannt.<br>
  720. <b>Hinweis 2:</b> Durch das Setzen des <a
  721. href="#disable">disable</a>-Attributes kann die automatische Erzeugung
  722. ausgeschaltet werden. In diesem Fall ist ausschlie&szlig;lich die oben
  723. erl&auml;uterte Umbenennung aktiv. Der <a
  724. href="#createlog">createlog</a>-Befehl kann zum Hinzuf&uuml;gen von
  725. FileLog und SVG eines bereits definierten Ger&auml;tes benutzt werden.
  726. <br>
  727. <b>Hinweis 3:</b>Es macht keinen Sinn, die Instanz dieses Moduls mehrmals
  728. zu erzeugen.
  729. </ul>
  730. <br>
  731. Beispiel:<PRE>
  732. define autocreate autocreate
  733. attr autocreate autosave
  734. attr autocreate device_room %TYPE
  735. attr autocreate filelog test2/log/%NAME-%Y.log
  736. attr autocreate weblink
  737. attr autocreate weblink_room Plots
  738. </PRE>
  739. </ul>
  740. <a name="autocreateset"></a>
  741. <b>Set</b> <ul>N/A</ul><br>
  742. <a name="autocreateget"></a>
  743. <b>Get</b> <ul>N/A</ul><br>
  744. <a name="autocreateattr"></a>
  745. <b>Attribute</b>
  746. <ul>
  747. <a name="autosave"></a>
  748. <li>autosave<br>
  749. Nach der Erzeugung eines neuen Ger&auml;tes wird automatisch die
  750. Konfigurationsdatei mit dem Befehl <a href="#save">save</a>
  751. gespeichert. Der Standardwert ist 1 (d.h. aktiviert), eine 0 schaltet
  752. die automatische Speicherung aus.<br>
  753. <b>Achtung:</b> Dieses Attribut ist unerw&uuml;nscht, bitte stattdessen
  754. das global autosave Attribut verwenden.
  755. </li><br>
  756. <a name="device_room"></a>
  757. <li>device_room<br>
  758. "Schiebt" das neu erstellte Ger&auml;t in diesen Raum. Der Name kann
  759. die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes
  760. Beispiel.</li><br>
  761. <a name="filelogattr"></a>
  762. <li>filelog<br>
  763. Erstellt ein Filelog welches zu einem Ger&auml;t geh&ouml;rt. Der
  764. Dateiname darf die Wildcards %NAME und %TYPE enthalten, siehe oben
  765. stehendes Beispiel. Das Filelog wird in den gleichen Raum "geschoben"
  766. wie das zugeh&ouml;rige Ger&auml;t.</li><br>
  767. <a name="weblinkattr"></a>
  768. <li>weblink<br>
  769. Erzeugt ein SVG, welches mit dem Ger&auml;t/Filelog verkn&uuml;pft
  770. ist.</li><br>
  771. <a name="weblink_room"></a>
  772. <li>weblink_room<br>
  773. "Schiebt" das neu erstellte SVG in den bezeichneten Raum. Der Name kann
  774. die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes
  775. Beispiel.</li><br>
  776. <li><a href="#disable">disable</a></li>
  777. <br>
  778. <a name="ignoreTypes"></a>
  779. <li>ignoreTypes<br>
  780. Dies ist ein Regexp, um bestimmte Ger&auml;te zu ignorieren, z.b. der
  781. Funk-Heizungsthermostat (FHT) des Nachbarn. In dem Ausdruck k&ouml;nnen
  782. mehr als ein Ger&auml;t &uuml;ber die normale Regexp-Syntax angegeben
  783. werden. Beispiel:<br>
  784. attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)<br>
  785. Das Wort "Types" ist etwas irref&uuml;hrend, da der Ger&auml;tename
  786. gepr&uuml;ft wird, und nicht der Typ.<br>
  787. <b>Achtung</b>: ab featurelevel 5.9 wird der Regexp automatisch mit
  788. ^ und $ erg&auml;nzt, muss also den kompletten Namen matchen (genau wie
  789. bei notify und FileLog).
  790. </li><br>
  791. <a name="autocreateThreshold"></a>
  792. <li>autocreateThreshold<br>
  793. Eine Liste of &lt;type&gt;:&lt;count&gt;:&lt;interval&gt; tripeln. Ein
  794. neues Device wird nur dann erzeugt wenn es mindestens <code>count</code>
  795. Events f&uuml;r den TYPE <code>type</code> in den letzten
  796. <code>interval</code> Sekunden gegeben hat.<br>
  797. Beispiel:<br>
  798. <code>attr autocreateThreshold LaCrosse:2:30,EMT7110:2:60</code>
  799. </li>
  800. </ul>
  801. <br>
  802. <a name="createlog"></a>
  803. <b>createlog</b>
  804. <ul>
  805. Dieser Befehl wird f&uuml;r ein manuelles Hinzuf&uuml;gen eines Logfile
  806. oder eines SVG zu einem vorhandenen Ger&auml;t verwendet.
  807. <br><br>
  808. Dieser Befehl ist Bestandteilteil des autocreate-Modules.
  809. </ul>
  810. <br>
  811. <a name="usb"></a>
  812. <b>usb</b>
  813. <ul>
  814. Verwendung:
  815. <ul><code>
  816. usb scan<br>
  817. usb create<br>
  818. </code></ul>
  819. Dieser Befehl durchsucht das /dev-Verzeichnis nach angeschlossenen
  820. USB-Ger&auml;ten und versucht gleichzeitig sie zu identifizieren. Mit dem
  821. Argument scan wird eine Liste von ausf&uuml;hrbaren FHEM-Befehlen
  822. zur&uuml;ckgegeben. Das Argument create gibt keine Liste o.&auml;.
  823. zur&uuml;ck, die Ger&auml;te werden stattdessen erzeugt.<br><br>
  824. Es ist zu beachten, dass ein CUL immer noch manuell in den
  825. HomeMatic-Modus umgeschaltet werden muss. <br><br>
  826. Unter Linux wird gleichzeitig mit dem lsusb-befehl &uuml;berpr&uuml;ft,
  827. ob nichtgeflashte CULs angeschlossen sind. Ist dies der Fall, ruft Linux
  828. CULflash mit den geeigneten Parametern auf (oder zeigt den
  829. CULflash-Befehl an, falls scan aufgef&uuml;hrt wurde).
  830. Pro usb Befehl wird nur ein Ger&auml;t geflasht.<br><br>
  831. Dieser Befehl ist Bestandteilteil des autocreate-Modules.
  832. </ul>
  833. </ul> <!-- End of autocreate -->
  834. <br>
  835. =end html_DE
  836. =cut