| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- ##############################################
- # $Id: 98_autocreate.pm 15620 2017-12-16 18:10:36Z rudolfkoenig $
- package main;
- use strict;
- use warnings;
- sub resolveSymLink($);
- # Problems:
- # - Not all CUL_EM devices return a power
- # - Not all CUL_WS devices return a temperature
- # - No plot files for BS/CUL_FHTTK/USF1000/X10/WS300
- # - check "UNDEFINED" parameters for BS/USF1000/X10
- my %flogpar = (
- # Oregon sensors:
- # * temperature
- "(THR128|THWR288A|THN132N|THGR132N).*"
- => { GPLOT => "temp4:Temp,", FILTER => "%NAME" },
- # * temperature, humidity
- "(THGR228N|THGR810|THGR918|THGR328N|RTGR328N|WTGR800_T|WT450H).*"
- => { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
- # * temperature, humidity, pressure
- "(BTHR918N|BTHR918|BTHR918N).*"
- => { GPLOT => "rain4press4:Temp/Press,temp4hum4:Temp/Hum,",
- FILTER => "%NAME" },
- # * anenometer
- "(WGR800|WGR918|WTGR800_A).*"
- => { GPLOT => "wind4windDir4:WindDir/WindSpeed,", FILTER => "%NAME" },
- # * Oregon sensors: Rain gauge
- "(PCR800|RGR918).*"
- => { GPLOT => "rain4:RainRate", FILTER => "%NAME" },
- # X10 sensors received by RFXCOM
- "(RFXX10SEC|TRX_DS10A).*"
- => { GPLOT => "fht80tf:Window,", FILTER => "%NAME" },
- # X10 Window sensors received by RFXTRX
- "TRX_DS10A.*"
- => { GPLOT => "fht80tf:Window,", FILTER => "%NAME" },
- # TX3 temperature sensors received by RFXTRX
- "TX3.*"
- => { GPLOT => "temp4hum4:Temp/Hum,", FILTER => "%NAME" },
- # USB-WDE1
- "USBWX_[0-8]"
- => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME" },
- "USBWX_ks300"
- => { GPLOT => "temp4hum6:Temp/Hum,temp4rain10:Temp/Rain,hum6wind8:Wind/Hum,",
- FILTER => "%NAME:T:.*" },
- # HomeMatic
- "CUL_HM_THSensor.*"
- => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME:T:.*" },
- "CUL_HM_KS550.*"
- => { GPLOT => "temp4rain10:Temp/Rain,hum6wind8:Wind/Hum,",
- FILTER => "%NAME:T:.*" },
- "CUL_HM_HM-CC-TC.*"
- => { GPLOT => "temp4hum6:Temp/Hum,", FILTER => "%NAME:T:.*" },
- );
- #####################################
- sub
- autocreate_Initialize($)
- {
- my ($hash) = @_;
- $hash->{DefFn} = "autocreate_Define";
- $hash->{NotifyFn} = "autocreate_Notify";
- $hash->{AttrFn} = "autocreate_Attr";
- $hash->{AttrList}= "autosave filelog device_room weblink weblink_room " .
- "disable ignoreTypes autocreateThreshold";
- my %ahash = ( Fn=>"CommandCreateLog",
- Hlp=>"<device>,create log/weblink for <device>",
- ModuleName => "autocreate" );
- $cmds{createlog} = \%ahash;
- my %bhash = ( Fn=>"CommandUsb",
- Hlp=>"[scan|create],display or create fhem-entries for USB devices",
- ModuleName => "autocreate" );
- $cmds{usb} = \%bhash;
- }
- #####################################
- sub
- autocreate_Define($$)
- {
- my ($hash, $def) = @_;
- my $name = $hash->{NAME};
- $hash->{STATE} = "active";
- $hash->{NOTIFYDEV} = "global";
- $attr{global}{autoload_undefined_devices} = 1; # Make sure we work correctly
- return undef;
- }
- sub
- replace_wildcards($$)
- {
- my ($hash, $str) = @_;
- return "" if(!$str);
- my $t = $hash->{TYPE}; $str =~ s/[%\$]TYPE/$t/g;
- my $n = $hash->{NAME}; $str =~ s/[%\$]NAME/$n/g;
- return $str;
- }
- #####################################
- sub
- autocreate_Notify($$)
- {
- my ($ntfy, $dev) = @_;
- my $me = $ntfy->{NAME};
- my $max = int(@{$dev->{CHANGED}});
- my $ret = "";
- my $nrcreated;
- for (my $i = 0; $i < $max; $i++) {
- my $s = $dev->{CHANGED}[$i];
- $s = "" if(!defined($s));
- my $temporary;
- ################
- # Special for EnOcean. DO NOT use it elsewhere
- if($s =~ m/^UNDEFINED -temporary/) {
- $temporary = 1;
- $s =~ s/ -temporary//;
- }
- if($s =~ m/^UNDEFINED ([^ ]*) ([^ ]*) (.*)$/) {
- my ($name, $type, $arg) = ($1, $2, $3);
- next if(AttrVal($me, "disable", undef));
- my $it = AttrVal($me, "ignoreTypes", undef);
- $it = "^$it\$" if($featurelevel > 5.8); # Forum #80775
- next if($it && $name =~ m/$it/i);
- my $at = AttrVal($me, "autocreateThreshold", undef);
- LoadModule($type) if( !$at );
- if( $at || $modules{$type}{AutoCreate} ) {
- my @at = split( '[, ]', $at?$at:"" );
- my $hash = $defs{$me};
- my $now = gettimeofday();
- #remove old events
- foreach my $t (keys %{$hash->{received}}) {
- my @v = grep { my $l = $_;
- $l =~ s/:.*//;
- ($t=~ m/^$l$/) ? $_ : undef} @at;
- my (undef,undef,$interval) = split( ':', $v[0]?$v[0]:"" );
- if( !@v ) {
- if( my $fp = $modules{$t}{AutoCreate} ) {
- foreach my $k (keys %{$fp}) {
- next if($name !~ m/^$k$/ || !$fp->{$k}{autocreateThreshold});
- (undef, $interval) = split( ':',$fp->{$k}{autocreateThreshold});
- last;
- }
- }
- }
- $interval = 60 if( !$interval );
- foreach my $a (keys %{$hash->{received}{$t}}) {
- foreach my $time (keys %{$hash->{received}{$t}{$a}}) {
- if( $time < $now - $interval ) {
- #Log3 $me, 5,
- # "autocreate: removed event for '$t $a' with timestamp $time";
- delete( $hash->{received}{$t}{$a}{$time} );
- }
- }
- delete($hash->{received}{$t}{$a}) if(!%{$hash->{received}{$t}{$a}});
- }
- delete( $hash->{received}{$t} ) if( !%{$hash->{received}{$t}} );
- }
- my @v = grep { my $l = $_;
- $l =~ s/:.*//;
- ($type=~ m/^$l$/) ? $_ : undef} @at;
- #if there is an entry for this type
- if( @v || $modules{$type}{AutoCreate} ) {
- my( undef, $min_count, $interval ) = split( ':', $v[0]?$v[0]:"" );
- my $found;
- if( !@v ) {
- if( my $fp = $modules{$type}{AutoCreate} ) {
- foreach my $k (keys %{$fp}) {
- next if($name !~ m/^$k$/ || !$fp->{$k}{autocreateThreshold});
- ($min_count, $interval) =
- split(':', $fp->{$k}{autocreateThreshold});
- $found = 1;
- last;
- }
- }
- }
- if( @v || $found ) {
- $min_count = 2 if( !$min_count );
- $interval = 60 if( !$interval );
- #add this event
- $hash->{received}{$type}{$arg}{$now} = 1;
- my $count = keys %{$hash->{received}{$type}{$arg}};
- Log3 $me, 4, "autocreate: received $count event(s) for ".
- "'$type $arg' during the last $interval seconds";
- if( $count < $min_count ) {
- Log3 $me, 4, "autocreate: ignoring event for ".
- "'$type $arg': at least $min_count needed";
- next;
- }
- }
- #forget entries for this type
- delete( $hash->{received}{$type}{$arg} );
- delete( $hash->{received}{$type} ) if( !%{$hash->{received}{$type}} );
- }
- }
- my ($cmd, $ret);
- my $hash = $defs{$name}; # Called from createlog
- ####################
- if(!$hash) {
- $cmd = "$name $type $arg";
- $cmd = "-temporary $name $type $arg" if($temporary);
- Log3 $me, 2, "autocreate: define $cmd";
- $ret = CommandDefine(undef, $cmd);
- if($ret) {
- Log3 $me, 1, "ERROR: $ret";
- last;
- }
- }
- $hash = $defs{$name};
- $nrcreated++;
- my $room = replace_wildcards($hash, AttrVal($me, "device_room", "%TYPE"));
- # preserve room for createlog
- $room = $attr{$name}{room} if($attr{$name} && $attr{$name}{room});
- $attr{$name}{room} = $room if($room);
- $nrcreated = 0 if($temporary); # do not save
- next if($modules{$hash->{TYPE}}{noAutocreatedFilelog} || $temporary);
- ####################
- my $fl = replace_wildcards($hash, AttrVal($me, "filelog", ""));
- my $flname = "FileLog_$name";
- delete($defs{$flname}) if($fl); # If we are re-creating it with createlog.
- my ($gplot, $filter, $devattr) = ("", $name, "");
- my $fp = $modules{$hash->{TYPE}}{AutoCreate};
- $fp = \%flogpar if(!$fp);
-
- foreach my $k (keys %{$fp}) {
- next if($name !~ m/^$k$/);
- $gplot = $fp->{$k}{GPLOT};
- $filter = replace_wildcards($hash, $fp->{$k}{FILTER});
- $devattr = $fp->{$k}{ATTR};
- last;
- }
- if($fl) {
- $cmd = "$flname FileLog $fl $filter";
- Log3 $me, 2, "autocreate: define $cmd";
- $ret = CommandDefine(undef, $cmd);
- if($ret) {
- Log3 $me, 1, "ERROR: $ret";
- last;
- }
- $attr{$flname}{room} = $room if($room);
- $attr{$flname}{logtype} = "${gplot}text";
- }
- if($devattr) {
- foreach my $attrNV (split(" ", $devattr)) {
- my ($an, $av) = split(":", $attrNV, 2);
- CommandAttr(undef, "$name $an $av");
- }
- }
- ####################
- next if(!AttrVal($me, "weblink", 1) || !$gplot || !$fl);
- $room = replace_wildcards($hash, AttrVal($me, "weblink_room", "Plots"));
- my $wnr = 1;
- foreach my $wdef (split(/,/, $gplot)) {
- next if(!$wdef);
- my ($gplotfile, $stuff) = split(/:/, $wdef);
- next if(!$gplotfile);
- my $wlname = "SVG_$name";
- $wlname .= "_$wnr" if($wnr > 1);
- $wnr++;
- delete($defs{$wlname}); # If we are re-creating it with createlog.
- $cmd = "$wlname SVG $flname:$gplotfile:CURRENT";
- Log3 $me, 2, "autocreate: define $cmd";
- $ret = CommandDefine(undef, $cmd);
- if($ret) {
- Log3 $me, 1, "ERROR: define $cmd: $ret";
- last;
- }
- $attr{$wlname}{room} = $room if($room);
- $attr{$wlname}{label} = '"' . $name .
- ' Min $data{min1}, Max $data{max1}, Last $data{currval1}"';
- $ret = CommandSet(undef, "$wlname copyGplotFile");
- if($ret) {
- Log3 $me, 1, "ERROR: set $wlname copyGplotFile: $ret";
- last;
- }
- }
- }
- ################
- if($s =~ m/^RENAMED ([^ ]*) ([^ ]*)$/) {
- my ($old, $new) = ($1, $2);
- if($defs{"FileLog_$old"}) {
- CommandRename(undef, "FileLog_$old FileLog_$new");
- my $hash = $defs{"FileLog_$new"};
- my $oldfile = $hash->{currentlogfile};
- $hash->{DEF} =~ s/$old/$new/g;
- $hash->{REGEXP} =~ s/$old/$new/g;
- $hash->{logfile} =~ s/$old/$new/g;
- $hash->{currentlogfile} =~ s/$old/$new/g;
- Log3 $me, 2, "autocreate: renamed FileLog_$old to FileLog_$new";
- $nrcreated++;
- notifyRegexpChanged($hash, $hash->{REGEXP});
- # Content
- if($oldfile ne $hash->{currentlogfile} &&
- open(IN, $oldfile) && open(OUT, ">".$hash->{currentlogfile})) {
- while(my $l = <IN>) {
- $l =~ s/$old/$new/;
- syswrite(OUT, $l);
- }
- close(IN); close(OUT);
- unlink($oldfile);
- my $fh = new IO::File ">>$hash->{currentlogfile}";
- $hash->{FH} = $fh;
- } else {
- Log 1, "$oldfile or $hash->{currentlogfile}: $!";
- close(IN);
- }
- }
- if($defs{"SVG_$old"}) {
- CommandRename(undef, "SVG_$old SVG_$new");
- my $hash = $defs{"SVG_$new"};
- my $oldfile = $hash->{GPLOTFILE};
- $hash->{DEF} =~ s/$old/$new/g;
- $hash->{GPLOTFILE} =~ s/$old/$new/g;
- $hash->{LOGDEVICE} =~ s/$old/$new/g;
- $attr{"SVG_$new"}{label} =~ s/$old/$new/g;
- Log3 $me, 2, "autocreate: renamed SVG_$old to SVG_$new";
- use vars qw($FW_gplotdir);# gplot directory
- if($oldfile ne $hash->{GPLOTFILE} && $FW_gplotdir) {
- $oldfile = $FW_gplotdir."/".$oldfile.".gplot";
- my $newfile = $FW_gplotdir."/".$hash->{GPLOTFILE}.".gplot";
- if(open(IN, $oldfile) && open(OUT, ">$newfile")) {
- while(my $l = <IN>) {
- $l =~ s/$old/$new/;
- syswrite(OUT, $l);
- }
- close(IN); close(OUT);
- unlink($oldfile);
- } else {
- Log 1, "$oldfile or $newfile: $!";
- close(IN);
- }
- }
- $nrcreated++;
- }
- }
- }
- CommandSave(undef, undef) if(!$ret && $nrcreated &&
- AttrVal($me,"autosave", 1));
- return $ret;
- }
- # TODO: fix it if the device is renamed.
- sub
- CommandCreateLog($$)
- {
- my ($cl, $n) = @_;
- my $ac;
- foreach my $d (keys %defs) {
- next if($defs{$d}{TYPE} ne "autocreate");
- $ac = $d;
- last;
- }
- return "Please define an autocreate device with attributes first " .
- "(it may be disabled)" if(!$ac);
- return "No device named $n found" if(!$defs{$n});
- my $acd = $defs{$ac};
- my $disabled = AttrVal($ac, "disable", undef);
- delete $attr{$ac}{disable} if($disabled);
- $acd->{CHANGED}[0] = "UNDEFINED $n $defs{$n}{TYPE} none";
- autocreate_Notify($acd, $acd);
- delete $acd->{CHANGED};
- $attr{$ac}{disable} = 1 if($disabled);
- }
- my %ac_links=();
- # Optimized for linux /dev/serial/by-path/... links
- sub
- resolveSymLink($)
- {
- my ($name) = @_;
- return $ac_links{$name} if($ac_links{$name});
- return $name if($^O =~ m/Win/ || !-l $name);
- my $link = readlink($name);
- return $name if(!$link);
- my @p = split("/", $name);
- pop(@p);
- foreach my $l (split("/", $link)) {
- next if($l eq ".");
- if($l ne "..") {
- push(@p, $l); next;
- }
- pop(@p);
- push(@p,"") if(@p == 0); # root directory
- }
- $link = resolveSymLink(join("/", @p));
- $ac_links{$name} = $link;
- return $link;
- }
- ##########################
- # Table for automatically creating IO devices
- # PARAM in define will be replaced with the $1 from matchList
- my @usbtable = (
- { NAME => "CUL",
- matchList => ['cu.usbmodem.*(.)$', 'ttyACM.*(.)$'],
- DeviceName=> "DEVICE\@9600",
- flush => "\n",
- request => "V\n",
- response => "^V .* CU.*",
- define => "CUL_PARAM CUL DEVICE\@9600 1PARAM34", },
- { NAME => "CUL", # TuxRadio/RPi: CSM, SCC
- matchList => ["ttySP(.+)", "ttyAMA(.+)", "ttyS(.)" ],
- DeviceName=> "DEVICE\@38400",
- flush => "\n",
- request => "V\n",
- response => "^V .* CSM.*",
- define => "CUL_PARAM CUL DEVICE\@38400 1PARAM34", },
- { NAME => "TCM_ESP3",
- matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)",
- "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"],
- DeviceName=> "DEVICE\@57600",
- request => pack("H*", "5500010005700838"), # get idbase
- response => "^\x55\x00\x05\x01",
- define => "TCM_ESP3_PARAM TCM ESP3 DEVICE\@57600", },
- { NAME => "TCM_ESP2",
- matchList => ["ttyUSB(.*)"],
- DeviceName=> "DEVICE\@9600",
- request => pack("H*", "A55AAB5800000000000000000003"), # get idbase
- response => "^\xA5\x5A............",
- define => "TCM_ESP2_PARAM TCM ESP2 DEVICE\@9600", },
- { NAME => "FHZ",
- matchList => ["cu.usbserial(.*)", "ttyUSB(.*)"],
- DeviceName=> "DEVICE\@9600",
- request => pack("H*", "8105044fc90185"), # get fhtbuf
- response => "^\x81........",
- define => "FHZ_PARAM FHZ DEVICE", },
- { NAME => "TRX",
- matchList => ["cu.usbserial(.*)", "ttyUSB(.*)"],
- DeviceName=> "DEVICE\@38400",
- init => pack("H*", "0D00000000000000000000000000"), # Reset
- request => pack("H*", "0D00000102000000000000000000"), # GetStatus
- response => "^\x0d\x01\x00...........",
- define => "TRX_PARAM TRX DEVICE\@38400", },
- { NAME => "ZWDongle",
- matchList => ["cu.PL2303-0000(.*)", "cu.usbmodem(.*)",
- "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)" ],
- DeviceName=> "DEVICE\@115200",
- request => pack("H*", "01030020dc06"), # GetStatus +ACK
- response => "^\x06.*",
- define => "ZWDongle_PARAM ZWDongle DEVICE\@115200", },
- { NAME => "FRM",
- matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)",
- "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"],
- DeviceName=> "DEVICE\@57600",
- init => pack("H*", "F9"), # Reset
- timeout => 5.0, # StandardFirmata blink takes time
- request => pack("H*", "F079F7"), # Query firmware version and filename START_SYSEX (0xF0), queryFirmware (0x79), END_SYSEX (0xF7)
- response => "^\xF0\x79(.*)\xF7", # Response Sysex xF0 x78 (2 Byte version) (n Byte filename) Endsysex xF7
- define => "FRM_PARAM FRM DEVICE\@57600", },
- );
- sub
- CommandUsb($$)
- {
- my ($cl, $n) = @_;
- return "Usage: usb [scan|create]" if("$n" !~ m/^(scan|create)$/);
- my $scan = 1 if($n eq "scan");
- my $ret = "";
- my $msg;
- my $dir = "/dev";
- if($^O =~ m/Win/) {
- return "This command is not yet supported on windows";
- }
- require "$attr{global}{modpath}/FHEM/DevIo.pm";
- Log3 undef, 1, "usb $n starting";
- ################
- # First try to flash unflashed CULs
- if($^O eq "linux") {
- # One device at a time to avoid endless loop
- my $lsusb = `lsusb`;
- if($lsusb) {
- my $culType;
- $culType = "CUL_V4" if($lsusb =~ m/VID=03eb.PID=2ff0/s); # FritzBox
- $culType = "CUL_V3" if($lsusb =~ m/VID=03eb.PID=2ff4/s); # FritzBox
- $culType = "CUL_V2" if($lsusb =~ m/VID=03eb.PID=2ffa/s); # FritzBox
- $culType = "CUL_V4" if($lsusb =~ m/03eb:2ff0/);
- $culType = "CUL_V3" if($lsusb =~ m/03eb:2ff4/);
- $culType = "CUL_V2" if($lsusb =~ m/03eb:2ffa/);
- if($culType) {
- $msg = "$culType: flash it with: CULflash none $culType";
- Log3 undef, 2, $msg; $ret .= $msg . "\n";
- if(!$scan) {
- AnalyzeCommand(undef, "culflash none $culType"); # Enable autoload
- sleep(4); # Leave time for linux to load th drivers
- }
- }
- }
- }
- ################
- # Now the /dev scan
- foreach my $dev (sort split("\n", `ls $dir`)) {
- foreach my $thash (@usbtable) {
- foreach my $ml (@{$thash->{matchList}}) {
- if($dev =~ m/$ml/) {
- my $PARAM = $1;
- $PARAM =~ s/[^A-Za-z0-9]//g;
- my $name = $thash->{NAME};
- $msg = "### $dev: checking if it is a $name";
- Log3 undef, 4, $msg; $ret .= $msg . "\n";
- # Check if it already used
- foreach my $d (keys %defs) {
- if($defs{$d}{DeviceName}) {
- my $dn = $defs{$d}{DeviceName};
- $dn =~ s/@.*//;
- if(resolveSymLink($dn) eq resolveSymLink("/dev/$dev")) {
- $msg = "$dev is already used by the fhem device $d";
- Log3 undef, 4, $msg; $ret .= $msg . "\n";
- goto NEXTDEVICE;
- }
- }
- }
- # Open the device
- my $dname = $thash->{DeviceName};
- $dname =~ s,DEVICE,$dir/$dev,g;
- my $hash = { NAME=>$name, DeviceName=>$dname, DevioText=>"Probing" };
- DevIo_OpenDev($hash, 0, 0);
- if(!defined($hash->{USBDev})) {
- DevIo_CloseDev($hash); # remove the ReadyFn loop
- $msg = "cannot open the device";
- Log3 undef, 4, $msg; $ret .= $msg . "\n";
- goto NEXTDEVICE;
- }
- # Send reset (optional)
- if(defined($thash->{init})) {
- DevIo_SimpleWrite($hash, $thash->{init}, 0);
- DevIo_TimeoutRead($hash, $thash->{timeout} ? $thash->{timeout}:0.5);
- }
- # Clear the USB buffer
- DevIo_SimpleWrite($hash, $thash->{flush}, 0) if($thash->{flush});
- DevIo_TimeoutRead($hash, 0.1);
- DevIo_SimpleWrite($hash, $thash->{request}, 0);
- my $answer = DevIo_TimeoutRead($hash, 0.1);
- DevIo_CloseDev($hash);
- if($answer !~ m/$thash->{response}/) {
- $msg = "got wrong answer for a $name";
- Log3 undef, 4, $msg; $ret .= $msg . "\n";
- next;
- }
- my $define = $thash->{define};
- $define =~ s/PARAM/$PARAM/g;
- $define =~ s,DEVICE,$dir/$dev,g;
- $msg = "create as a fhem device with: define $define";
- Log3 undef, 4, $msg; $ret .= $msg . "\n";
- if(!$scan) {
- Log3 undef, 1, "define $define";
- my $lret = CommandDefine($cl, $define);
- CommandSave(undef, undef)
- if(!$lret && AttrVal("global","autosave",1));
- }
- goto NEXTDEVICE;
- }
- }
- }
- NEXTDEVICE:
- }
- Log3 undef, 1, "usb $n end";
- return ($scan ? $ret : undef);
- }
- ###################################
- sub
- autocreate_Attr(@)
- {
- my @a = @_;
- my $do = 0;
- if($a[0] eq "set" && $a[2] eq "disable") {
- $do = (!defined($a[3]) || $a[3]) ? 1 : 2;
- }
- $do = 2 if($a[0] eq "del" && (!$a[2] || $a[2] eq "disable"));
- return if(!$do);
- $defs{$a[1]}{STATE} = ($do == 1 ? "disabled" : "active");
- return undef;
- }
- 1;
- =pod
- =item helper
- =item summary automatically create not yet defined FHEM devices
- =item summary_DE Erzeugt FHEM-Geräte automatisch
- =begin html
- <a name="autocreate"></a>
- <h3>autocreate</h3>
- <ul>
- Automatically create not yet defined FHEM devices upon reception of a message
- generated by this device. Note: devices which are polled (like the EMEM/EMWZ
- accessed through the EM1010PC) will NOT be automatically created.
- <br>
- <a name="autocreatedefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> autocreate</code><br>
- <br>
- <ul>
- By defining an instance, the global attribute <a href=
- "#autoload_undefined_devices">autoload_undefined_devices</a>
- is set, so that modules for unknnown devices are automatically loaded.
- The autocreate module intercepts the UNDEFINED event generated by each
- module, creates a device and optionally also FileLog and SVG
- entries.<br>
- <b>Note 1:</b> devices will be created with a unique name, which contains
- the type and a unique id for this type. When <a href="#rename">renaming
- </a> the device, the automatically created filelog and SVG devices
- will also be renamed.<br>
- <b>Note 2:</b> you can disable the automatic creation by setting the
- <a href="#disable">disable</a> attribute, in this case only the rename
- hook is active, and you can use the <a href="#createlog">createlog</a>
- command to add FileLog and SVG to an already defined device.
- <b>Note 3:</b> It makes no sense to create more than one instance of this
- module.
- </ul>
- <br>
- Example:<PRE>
- define autocreate autocreate
- attr autocreate autosave
- attr autocreate device_room %TYPE
- attr autocreate filelog test2/log/%NAME-%Y.log
- attr autocreate weblink
- attr autocreate weblink_room Plots
- </PRE>
- </ul>
- <a name="autocreateset"></a>
- <b>Set</b> <ul>N/A</ul><br>
- <a name="autocreateget"></a>
- <b>Get</b> <ul>N/A</ul><br>
- <a name="autocreateattr"></a>
- <b>Attributes</b>
- <ul>
- <a name="autosave"></a>
- <li>autosave<br>
- After creating a device, automatically save the config file with the
- command <a href="#save">save</a> command. Default is 1 (i.e. on), set
- it to 0 to switch it off.<br>
- <b>Note</b>: this attribute is deprecated, use the global autosave
- attribute instead.
- </li><br>
- <a name="device_room"></a>
- <li>device_room<br>
- "Put" the newly created device in this room. The name can contain the
- wildcards %TYPE and %NAME, see the example above.</li><br>
- <a name="filelogattr"></a>
- <li>filelog<br>
- Create a filelog associated with the device. The filename can contain
- the wildcards %TYPE and %NAME, see the example above. The filelog will
- be "put" in the same room as the device.</li><br>
- <a name="weblinkattr"></a>
- <li>weblink<br>
- Create an SVG associated with the device/filelog.</li><br>
- <a name="weblink_room"></a>
- <li>weblink_room<br>
- "Put" the newly created SVG in this room. The name can contain the
- wildcards %TYPE and %NAME, see the example above.</li><br>
- <li><a href="#disable">disable</a></li>
- <br>
- <a name="ignoreTypes"></a>
- <li>ignoreTypes<br>
- This is a regexp, to ignore certain devices, e.g. the neighbours FHT.
- You can specify more than one, with usual regexp syntax, e.g.<br>
- attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)<br>
- The word "Types" is somehow misleading, as it actually checks the
- generated device name.<br>
- <b>Note</b>: starting with featurelevel 5.9 the regexp is automatically
- extended with ^ and $, so that it must match the whole name (same
- procedure as in notify and FileLog).
- </li><br>
- <a name="autocreateThreshold"></a>
- <li>autocreateThreshold<br>
- A list of <type>:<count>:<interval> triplets. A new
- device is only created if there have been at least <code>count</code>
- events of TYPE <code>type</code> in the last <code>interval</code>
- seconds.<br> <code>attr autocreateThreshold
- LaCrosse:2:30,EMT7110:2:60</code>
- </li>
- </ul>
- <br>
- <a name="createlog"></a>
- <b>createlog</b>
- <ul>
- Use this command to manually add a FileLog and an SVG to an existing
- device.
- This command is part of the autocreate module.
- </ul>
- <br>
- <a name="usb"></a>
- <b>usb</b>
- <ul>
- Usage:
- <ul><code>
- usb scan<br>
- usb create<br>
- </code></ul>
- This command will scan the /dev directory for attached USB devices, and
- will try to identify them. With the argument scan you'll get back a list
- of FHEM commands to execute, with the argument create there will be no
- feedback, and the devices will be created instead.<br><br>
- Note that switching a CUL to HomeMatic mode is still has to be done
- manually.<br><br>
- On Linux it will also check with the lsusb command, if unflashed CULs are
- attached. If this is the case, it will call CULflash with the appropriate
- parameters (or display the CULflash command if scan is specified). The
- usb command will only flash one device per call.<br><br>
- This command is part of the autocreate module.
- </ul>
- </ul>
- <br>
- =end html
- =begin html_DE
- <a name="autocreate"></a>
- <h3>autocreate</h3>
- <ul>
- Erzeugt für noch nicht definierte FHEM-Geräte automatisch die
- geignete Definition (define). Diese Definition wird aus einer Nachricht
- gewonnen, die von diesen neuen Geräten empfangen wurde. Hinweis:
- Geräte, die mit Polling arbeiten (wie z.B. der Zugriff auf EMEM/EMWZ
- über EM1010PC) werden NICHT automatisch erzeugt.
- <br><br>
- <a name="autocreatedefine"></a>
- <b>Define</b>
- <ul>
- <code>define <name> autocreate</code><br>
- <br>
- <ul>
- Durch die Definition dieser Instanz wird das globale Attribut <a
- href="#autoload_undefined_devices">autoload_undefined_devices</a>
- gesetzt, sodass die Module für unbekannte Geräte automatisch
- nachgeladen werden. Das autocreate-Modul interpretiert das
- UNDEFINED-event, welches von jedem Modul gestartet wird, erzeugt ein
- Gerät (device) und bei Bedarf ein FileLog sowie
- SVG-Einträge.<br>
- <b>Hinweis 1:</b> Geräte werden mit einem eindeutigen Namen erzeugt,
- der den Typ und eine individuelle ID für diesen Typ enthält.
- Wird ein Gerät umbenannt (<a href="#rename">rename</a>), wird
- gleichzeitig das automatisch erzeugte FileLog und die SVG Geräte
- unbenannt.<br>
- <b>Hinweis 2:</b> Durch das Setzen des <a
- href="#disable">disable</a>-Attributes kann die automatische Erzeugung
- ausgeschaltet werden. In diesem Fall ist ausschließlich die oben
- erläuterte Umbenennung aktiv. Der <a
- href="#createlog">createlog</a>-Befehl kann zum Hinzufügen von
- FileLog und SVG eines bereits definierten Gerätes benutzt werden.
- <br>
- <b>Hinweis 3:</b>Es macht keinen Sinn, die Instanz dieses Moduls mehrmals
- zu erzeugen.
- </ul>
- <br>
- Beispiel:<PRE>
- define autocreate autocreate
- attr autocreate autosave
- attr autocreate device_room %TYPE
- attr autocreate filelog test2/log/%NAME-%Y.log
- attr autocreate weblink
- attr autocreate weblink_room Plots
- </PRE>
- </ul>
- <a name="autocreateset"></a>
- <b>Set</b> <ul>N/A</ul><br>
- <a name="autocreateget"></a>
- <b>Get</b> <ul>N/A</ul><br>
- <a name="autocreateattr"></a>
- <b>Attribute</b>
- <ul>
- <a name="autosave"></a>
- <li>autosave<br>
- Nach der Erzeugung eines neuen Gerätes wird automatisch die
- Konfigurationsdatei mit dem Befehl <a href="#save">save</a>
- gespeichert. Der Standardwert ist 1 (d.h. aktiviert), eine 0 schaltet
- die automatische Speicherung aus.<br>
- <b>Achtung:</b> Dieses Attribut ist unerwünscht, bitte stattdessen
- das global autosave Attribut verwenden.
- </li><br>
- <a name="device_room"></a>
- <li>device_room<br>
- "Schiebt" das neu erstellte Gerät in diesen Raum. Der Name kann
- die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes
- Beispiel.</li><br>
- <a name="filelogattr"></a>
- <li>filelog<br>
- Erstellt ein Filelog welches zu einem Gerät gehört. Der
- Dateiname darf die Wildcards %NAME und %TYPE enthalten, siehe oben
- stehendes Beispiel. Das Filelog wird in den gleichen Raum "geschoben"
- wie das zugehörige Gerät.</li><br>
- <a name="weblinkattr"></a>
- <li>weblink<br>
- Erzeugt ein SVG, welches mit dem Gerät/Filelog verknüpft
- ist.</li><br>
- <a name="weblink_room"></a>
- <li>weblink_room<br>
- "Schiebt" das neu erstellte SVG in den bezeichneten Raum. Der Name kann
- die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes
- Beispiel.</li><br>
- <li><a href="#disable">disable</a></li>
- <br>
- <a name="ignoreTypes"></a>
- <li>ignoreTypes<br>
- Dies ist ein Regexp, um bestimmte Geräte zu ignorieren, z.b. der
- Funk-Heizungsthermostat (FHT) des Nachbarn. In dem Ausdruck können
- mehr als ein Gerät über die normale Regexp-Syntax angegeben
- werden. Beispiel:<br>
- attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)<br>
- Das Wort "Types" ist etwas irreführend, da der Gerätename
- geprüft wird, und nicht der Typ.<br>
- <b>Achtung</b>: ab featurelevel 5.9 wird der Regexp automatisch mit
- ^ und $ ergänzt, muss also den kompletten Namen matchen (genau wie
- bei notify und FileLog).
- </li><br>
- <a name="autocreateThreshold"></a>
- <li>autocreateThreshold<br>
- Eine Liste of <type>:<count>:<interval> tripeln. Ein
- neues Device wird nur dann erzeugt wenn es mindestens <code>count</code>
- Events für den TYPE <code>type</code> in den letzten
- <code>interval</code> Sekunden gegeben hat.<br>
- Beispiel:<br>
- <code>attr autocreateThreshold LaCrosse:2:30,EMT7110:2:60</code>
- </li>
- </ul>
- <br>
- <a name="createlog"></a>
- <b>createlog</b>
- <ul>
- Dieser Befehl wird für ein manuelles Hinzufügen eines Logfile
- oder eines SVG zu einem vorhandenen Gerät verwendet.
- <br><br>
- Dieser Befehl ist Bestandteilteil des autocreate-Modules.
- </ul>
- <br>
- <a name="usb"></a>
- <b>usb</b>
- <ul>
- Verwendung:
- <ul><code>
- usb scan<br>
- usb create<br>
- </code></ul>
- Dieser Befehl durchsucht das /dev-Verzeichnis nach angeschlossenen
- USB-Geräten und versucht gleichzeitig sie zu identifizieren. Mit dem
- Argument scan wird eine Liste von ausführbaren FHEM-Befehlen
- zurückgegeben. Das Argument create gibt keine Liste o.ä.
- zurück, die Geräte werden stattdessen erzeugt.<br><br>
- Es ist zu beachten, dass ein CUL immer noch manuell in den
- HomeMatic-Modus umgeschaltet werden muss. <br><br>
- Unter Linux wird gleichzeitig mit dem lsusb-befehl überprüft,
- ob nichtgeflashte CULs angeschlossen sind. Ist dies der Fall, ruft Linux
- CULflash mit den geeigneten Parametern auf (oder zeigt den
- CULflash-Befehl an, falls scan aufgeführt wurde).
- Pro usb Befehl wird nur ein Gerät geflasht.<br><br>
- Dieser Befehl ist Bestandteilteil des autocreate-Modules.
- </ul>
- </ul> <!-- End of autocreate -->
- <br>
- =end html_DE
- =cut
|