############################################## # $Id$ package main; use strict; use warnings; use DevIo; 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=>",create log/weblink for ", 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 $calledByCreatelog; my $ret = ""; my $nrcreated; $calledByCreatelog = ($dev && $me eq $dev->{NAME}); 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", ""); $it = "^$it\$" if($featurelevel > 5.8); # Forum #80775 next if($it && $name =~ m/$it/i); next if($it && "$type:$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 (hopefully) from createlog if($hash && $hash->{TYPE} ne $type) { Log 1, "autocreate: refusing to create $type:$name, ". "as $hash->{TYPE}:$name already exists"; return; } #################### 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($temporary); #################### my $fl = replace_wildcards($hash, AttrVal($me, "filelog", "")); $fl = undef if($modules{$hash->{TYPE}}{noAutocreatedFilelog} && !$calledByCreatelog); 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 = ) { $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 = ) { $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(.+)", "serial(.+)", "ttyAMA(.+)" ], DeviceName=> "DEVICE\@115200", request => pack("H*", "01030020dc06"), # GetStatus +ACK response => "^\x06.*", define => "ZWDongle_PARAM ZWDongle DEVICE\@115200", }, { NAME => "SIGNALDuino", matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"], DeviceName=> "DEVICE\@57600", flush => "\n", request => "V\n", # request firmware version response => "^;S.*", define => "SIGNALDUINO_PARAM SIGNALduino DEVICE\@57600", }, { NAME => "MYSENSORS", matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"], DeviceName=> "DEVICE\@115200", flush => "\n", request => "0;255;3;0;18\n", # send heartbeat request response => "^0;255;3;0;22.*", # heartbeat response define => "MYSENSORS_PARAM MYSENSORS DEVICE\@115200", }, { NAME => "ArduCounter", matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"], DeviceName=> "DEVICE\@38400", flush => "\n", request => "h\n", # send firmware version request response => "^ArduCounter V.*", # response is two lines define => "ArduCounter_PARAM ArduCounter DEVICE\@38400", }, { NAME => "ElsnerWS", matchList => ["cu.usbserial(.*)", "cu.usbmodem(.*)", "ttyUSB(.*)", "ttyACM(.*)", "ttyAMA(.*)"], DeviceName=> "DEVICE\@19200", timeout => 1.0, # msg every second maxLen => 127, # max packet ist 64 bytes response => "[GW][+-][0-9]{2}\.[0-9]{7}[JN][0-9]{5}". "\.[0-9][JN].*[0-9]{4}\x03", define => "ElsnerWS_PARAM ElsnerWS comtype=rs485 ". "devicename=DEVICE\@19200", }, { 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 = ($n eq "scan"); my $ret = ""; my $msg; my $dir = "/dev"; if($^O =~ m/Win/) { return "This command is not yet supported on windows"; } 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 = "Probing $name device $dev"; $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_SimpleReadWithTimeout($hash, $thash->{timeout} ? $thash->{timeout}:0.5); } # Clear the USB buffer if($thash->{flush}) { DevIo_SimpleWrite($hash, $thash->{flush}, 0); DevIo_TimeoutRead($hash, 0.1); } my $answer=""; if($thash->{request}) { DevIo_SimpleWrite($hash, $thash->{request}, 0); $answer = DevIo_TimeoutRead($hash, 0.1); } elsif($thash->{timeout} && $thash->{maxLen}) { $answer = DevIo_TimeoutRead($hash, $thash->{timeout}, $thash->{maxLen}, $thash->{response}); } if(AttrVal("global", "verbose", 0) >= 5) { my $aTxt = $answer; $aTxt =~ s/([^ -~])/"(".ord($1).")"/ge; $aTxt = (substr($aTxt,0,60)."...") if(length($aTxt) > 63); Log3 undef, 5, " answer: $aTxt"; } DevIo_CloseDev($hash); if($answer !~ m/$thash->{response}/) { $msg = " wrong answer"; Log3 undef, 4, $msg; $ret .= $msg . "\n"; next; } my $define = $thash->{define}; $define =~ s/PARAM/$PARAM/g; $define =~ s,DEVICE,$dir/$dev,g; $msg = " matching answer, create it 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

autocreate

    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.
    Define
      define <name> autocreate

        By defining an instance, the global attribute autoload_undefined_devices 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.
        Note 1: devices will be created with a unique name, which contains the type and a unique id for this type. When renaming the device, the automatically created filelog and SVG devices will also be renamed.
        Note 2: you can disable the automatic creation by setting the disable attribute, in this case only the rename hook is active, and you can use the createlog command to add FileLog and SVG to an already defined device. Note 3: It makes no sense to create more than one instance of this module.

      Example:
          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
          
    Set
      N/A

    Get
      N/A

    Attributes
    • autosave
      After creating a device, automatically save the config file with the command save command. Default is 1 (i.e. on), set it to 0 to switch it off.
      Note: this attribute is deprecated, use the global autosave attribute instead.

    • device_room
      "Put" the newly created device in this room. The name can contain the wildcards %TYPE and %NAME, see the example above.

    • filelog
      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.

    • weblink
      Create an SVG associated with the device/filelog.

    • weblink_room
      "Put" the newly created SVG in this room. The name can contain the wildcards %TYPE and %NAME, see the example above.

    • disable

    • ignoreTypes
      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.
      attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)
      The word "Types" is somehow misleading, as it first checks the generated device name, and then the type:name pair.
      Note: starting with featurelevel 5.8 the regexp is automatically extended with ^ and $, so that it must match the whole name or type:name (same procedure as in notify and FileLog).

    • autocreateThreshold
      A list of <type>:<count>:<interval> triplets. A new device is only created if there have been at least count events of TYPE type in the last interval seconds.
      attr autocreateThreshold LaCrosse:2:30,EMT7110:2:60

    createlog
      Use this command to manually add a FileLog and an SVG to an existing device. This command is part of the autocreate module.

    usb
      Usage:
        usb scan
        usb create
      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.

      Note that switching a CUL to HomeMatic mode is still has to be done manually.

      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.

      This command is part of the autocreate module.

=end html =begin html_DE

autocreate

    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.

    Define
      define <name> autocreate

        Durch die Definition dieser Instanz wird das globale Attribut autoload_undefined_devices 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.
        Hinweis 1: 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 (rename), wird gleichzeitig das automatisch erzeugte FileLog und die SVG Geräte unbenannt.
        Hinweis 2: Durch das Setzen des disable-Attributes kann die automatische Erzeugung ausgeschaltet werden. In diesem Fall ist ausschließlich die oben erläuterte Umbenennung aktiv. Der createlog-Befehl kann zum Hinzufügen von FileLog und SVG eines bereits definierten Gerätes benutzt werden.
        Hinweis 3:Es macht keinen Sinn, die Instanz dieses Moduls mehrmals zu erzeugen.

      Beispiel:
          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
          
    Set
      N/A

    Get
      N/A

    Attribute
    • autosave
      Nach der Erzeugung eines neuen Gerätes wird automatisch die Konfigurationsdatei mit dem Befehl save gespeichert. Der Standardwert ist 1 (d.h. aktiviert), eine 0 schaltet die automatische Speicherung aus.
      Achtung: Dieses Attribut ist unerwünscht, bitte stattdessen das global autosave Attribut verwenden.

    • device_room
      "Schiebt" das neu erstellte Gerät in diesen Raum. Der Name kann die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes Beispiel.

    • filelog
      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.

    • weblink
      Erzeugt ein SVG, welches mit dem Gerät/Filelog verknüpft ist.

    • weblink_room
      "Schiebt" das neu erstellte SVG in den bezeichneten Raum. Der Name kann die Wildcards %NAME und %TYPE enthalten, siehe oben stehendes Beispiel.

    • disable

    • ignoreTypes
      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:
      attr autocreate ignoreTypes (CUL_HOERMANN.*|FHT_1234|CUL_WS_7)
      Das Wort "Types" ist etwas irreführend, da erst der Gerätename geprüft wird, und dann der Konstrukt Typ:Gerätename.
      Achtung: ab featurelevel 5.8 wird der Regexp automatisch mit ^ und $ ergänzt, muss also den kompletten Namen matchen (genau wie bei notify und FileLog).

    • autocreateThreshold
      Eine Liste of <type>:<count>:<interval> tripeln. Ein neues Device wird nur dann erzeugt wenn es mindestens count Events für den TYPE type in den letzten interval Sekunden gegeben hat.
      Beispiel:
      attr autocreateThreshold LaCrosse:2:30,EMT7110:2:60

    createlog
      Dieser Befehl wird für ein manuelles Hinzufügen eines Logfile oder eines SVG zu einem vorhandenen Gerät verwendet.

      Dieser Befehl ist Bestandteilteil des autocreate-Modules.

    usb
      Verwendung:
        usb scan
        usb create
      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.

      Es ist zu beachten, dass ein CUL immer noch manuell in den HomeMatic-Modus umgeschaltet werden muss.

      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.

      Dieser Befehl ist Bestandteilteil des autocreate-Modules.

=end html_DE =cut