diff --git a/fhem/FHEM/36_JeeLink.pm b/fhem/FHEM/36_JeeLink.pm index 2f8fd964b..2f2431778 100644 --- a/fhem/FHEM/36_JeeLink.pm +++ b/fhem/FHEM/36_JeeLink.pm @@ -78,12 +78,12 @@ JeeLink_Initialize($) $hash->{AttrList} = "Clients MatchList" ." hexFile" ." initCommands" + ." flashCommand" ." DebounceTime BeepLong BeepShort BeepDelay" ." tune " . join(" ", map { "tune_$_" } keys %RxListJeeLink) ." $readingFnAttributes"; $hash->{ShutdownFn} = "JeeLink_Shutdown"; - } sub JeeLink_Fingerprint($$) @@ -115,6 +115,10 @@ JeeLink_Define($$) $hash->{Clients} = $clientsJeeLink; $hash->{MatchList} = \%matchListPCA301; + if( !defined( $attr{$name}{flashCommand} ) ) { + $attr{$name}{flashCommand} = "avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]" + } + $hash->{DeviceName} = $dev; my $ret = DevIo_OpenDev($hash, 0, "JeeLink_DoInit"); @@ -200,14 +204,15 @@ JeeLink_Set($@) } } elsif( $cmd eq "flash" ) { - my @args = split(' ', $arg); + my @args = split(' ', $arg); my $log = ""; my $hexFile = ""; - my @deviceName = split('@', $hash->{DeviceName}); + my @deviceName = split('@', $hash->{DeviceName}); my $port = $deviceName[0]; - my $logFile = "./log/JeeLinkFlash.log"; my $defaultHexFile = "./hexfiles/$hash->{TYPE}-LaCrosseITPlusReader10.hex"; - + my $logFile = AttrVal("global", "logdir", "./log") . "/JeeLinkFlash.log"; + + if(!$arg || $args[0] !~ m/^(\w|\/|.)+$/) { $hexFile = AttrVal($name, "hexFile", ""); if ($hexFile eq "") { @@ -217,89 +222,115 @@ JeeLink_Set($@) else { $hexFile = $args[0]; } - + return "Usage: set $name flash [filename]\n\nor use the hexFile attribute" if($hexFile !~ m/^(\w|\/|.)+$/); - + $log .= "flashing JeeLink $name\n"; $log .= "hex file: $hexFile\n"; $log .= "port: $port\n"; $log .= "log file: $logFile\n"; - - DevIo_CloseDev($hash); - $hash->{STATE} = "disconnected"; - $log .= "$name closed\n"; - - my $avrdude = "avrdude -p atmega328P -c arduino -P $port -D -U flash:w:$hexFile 2>$logFile"; - $log .= "command: $avrdude\n\n"; - `$avrdude`; - - local $/=undef; - open FILE, $logFile or die "Couldn't open file: $!"; - my $logText = ; - close FILE; - $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n"; - $log .= $logText; - $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n\n"; - + + my $flashCommand = AttrVal($name, "flashCommand", ""); + + if($flashCommand ne "") { + if (-e $logFile) { + unlink $logFile; + } + + DevIo_CloseDev($hash); + $hash->{STATE} = "disconnected"; + $log .= "$name closed\n"; + + my $avrdude = $flashCommand; + $avrdude =~ s/\Q[PORT]\E/$port/g; + $avrdude =~ s/\Q[HEXFILE]\E/$hexFile/g; + $avrdude =~ s/\Q[LOGFILE]\E/$logFile/g; + + $log .= "command: $avrdude\n\n"; + `$avrdude`; + + local $/=undef; + if (-e $logFile) { + open FILE, $logFile; + my $logText = ; + close FILE; + $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n"; + $log .= $logText; + $log .= "--- AVRDUDE ---------------------------------------------------------------------------------\n\n"; + } + else { + $log .= "WARNING: avrdude created no log file\n\n"; + } + + } + else { + $log .= "\n\nNo flashCommand found. Please define this attribute.\n\n"; + } + DevIo_OpenDev($hash, 0, "JeeLink_DoInit"); - $hash->{STATE} = "Opened"; $log .= "$name opened\n"; - - return $log; + + return $log; } - + elsif( $cmd eq "LaCrossePairForSec" ) { - my @args = split(' ', $arg); + my @args = split(' ', $arg); - return "Usage: set $name LaCrossePairForSec [ignore_battery]" if(!$arg || $args[0] !~ m/^\d+$/ || ($args[1] && $args[1] ne "ignore_battery") ); - $hash->{LaCrossePair} = $args[1]?2:1; - InternalTimer(gettimeofday()+$args[0], "JeeLink_RemoveLaCrossePair", $hash, 0); + return "Usage: set $name LaCrossePairForSec [ignore_battery]" if(!$arg || $args[0] !~ m/^\d+$/ || ($args[1] && $args[1] ne "ignore_battery") ); + $hash->{LaCrossePair} = $args[1]?2:1; + InternalTimer(gettimeofday()+$args[0], "JeeLink_RemoveLaCrossePair", $hash, 0); - } elsif( $cmd eq "setReceiverMode" ) { + } elsif( $cmd eq "setReceiverMode" ) { + return "Usage: set $name setReceiverMode (LaCrosse,HX2272,FS20)" if($arg !~ m/^(LaCrosse|HX2272|FS20)$/); - return "Usage: set $name setReceiverMode (LaCrosse,HX2272,FS20)" if($arg !~ m/^(LaCrosse|HX2272|FS20)$/); + #Get tune values of Transceiver if needed (TX+RX) + my $TuneStr = undef; + my $AttrStr = AttrVal($name, "tune_" . $arg, undef); + $AttrStr = AttrVal($name, "tune", undef) if(!(defined $AttrStr)); + $TuneStr = JeeLink_CalcTuneCmd($AttrStr) if(defined $AttrStr); - #Get tune values of Transceiver if needed (TX+RX) - my $TuneStr = undef; - my $AttrStr = AttrVal($name, "tune_" . $arg, undef); - $AttrStr = AttrVal($name, "tune", undef) if(!(defined $AttrStr)); - $TuneStr = JeeLink_CalcTuneCmd($AttrStr) if(defined $AttrStr); + JeeLink_Write($hash, $RxListJeeLink{$arg}); #set receiver + JeeLink_Write($hash, "t" . $TuneStr) if(defined $TuneStr); #set modified tune - JeeLink_Write($hash, $RxListJeeLink{$arg}); #set receiver - JeeLink_Write($hash, "t" . $TuneStr) if(defined $TuneStr); #set modified tune + #reset debounce time for OOK Signals + if($RxListJeeLink{$arg} =~ m/^O/) { + my $DebStr = AttrVal($name, "DebounceTime", undef); + JeeLink_Write($hash, "Od" . $DebStr) if(defined $DebStr); + } - #reset debounce time for OOK Signals - if($RxListJeeLink{$arg} =~ m/^O/) { - my $DebStr = AttrVal($name, "DebounceTime", undef); - JeeLink_Write($hash, "Od" . $DebStr) if(defined $DebStr); - } - - JeeLink_Write($hash, "f"); # update RFM configuration in FHEM (returns e.g. "FSK-868MHz") - - Log3 $name, 4, "set $name $cmd $arg"; - - } elsif ($cmd =~ m/^led$/i) { - - return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^(on|off)$/i); + JeeLink_Write($hash, "f"); # update RFM configuration in FHEM (returns e.g. "FSK-868MHz") Log3 $name, 4, "set $name $cmd $arg"; - JeeLink_Write($hash, "l" . ($arg eq "on" ? "1" : "0") ); + } elsif ($cmd =~ m/^led$/i) { + return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^(on|off)$/i); + + Log3 $name, 4, "set $name $cmd $arg"; + if($hash->{model} =~ m/LaCrosseITPlusReader./i ) { + JeeLink_Write($hash, ($arg eq "on" ? "1" : "0") ."a" ); + } + else { + JeeLink_Write($hash, "l" . ($arg eq "on" ? "1" : "0") ); + } } elsif ($cmd =~ m/led-on-for-timer/i) { + return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^[0-9]+$/i); - return "Unknown argument $cmd, choose one of $list" if($arg !~ m/^[0-9]+$/i); + #remove timer if there is one active + if($modules{JeeLink}{ldata}{$name}) { + CommandDelete(undef, $name . "_timer"); + delete $modules{JeeLink}{ldata}{$name}; + } - #remove timer if there is one active - if($modules{JeeLink}{ldata}{$name}) { - CommandDelete(undef, $name . "_timer"); - delete $modules{JeeLink}{ldata}{$name}; - } + Log3 $name, 4, "set $name on"; + if($hash->{model} =~ m/LaCrosseITPlusReader./i ) { + JeeLink_Write($hash, "1a"); + } + else { + JeeLink_Write($hash, "l" . "1"); + } - Log3 $name, 4, "set $name on"; - JeeLink_Write($hash, "l" . "1"); - - my $to = sprintf("%02d:%02d:%02d", $arg/3600, ($arg%3600)/60, $arg%60); - $modules{JeeLink}{ldata}{$name} = $to; + my $to = sprintf("%02d:%02d:%02d", $arg/3600, ($arg%3600)/60, $arg%60); + $modules{JeeLink}{ldata}{$name} = $to; Log3 $name, 4, "Follow: +$to setstate $name off"; CommandDefine(undef, $name."_timer at +$to {fhem(\"set $name led" ." off\")}"); @@ -323,10 +354,10 @@ JeeLink_Get($@) my $list = "devices:noArg initJeeLink:noArg RFMconfig:noArg updateAvailRam:noArg raw"; if( $cmd eq "devices" ) { - if($hash->{model} =~m/JeeNode -- HomeControl -/ ) { - JeeLink_SimpleWrite($hash, "h"); + if($hash->{model} =~m/JeeNode -- HomeControl -/ ) { + JeeLink_SimpleWrite($hash, "h"); } else { - JeeLink_SimpleWrite($hash, "l"); + JeeLink_SimpleWrite($hash, "l"); } } elsif( $cmd eq "initJeeLink" ) { @@ -388,8 +419,6 @@ JeeLink_DoInit($) delete($hash->{XMIT_TIME}); delete($hash->{NR_CMD_LAST_H}); - #JeeLink_SimpleWrite($hash, "v" ); - return undef; } @@ -629,10 +658,10 @@ JeeLink_Parse($$$$) JeeLink_SimpleWrite($hash, "0a" ); # led off JeeLink_SimpleWrite($hash, "l" ); # list known devices - } + } elsif( $dmsg =~m /LaCrosseITPlusReader/ ) { $hash->{MatchList} = \%matchListPCA301; - + } elsif( $dmsg =~m /ec3kSerial/ ) { $hash->{MatchList} = \%matchListPCA301; #JeeLink_SimpleWrite($hash, "ec", 1); @@ -662,13 +691,13 @@ JeeLink_Parse($$$$) } elsif( $dmsg =~ m/drecvintr exit/ ) { # command "ec" will not work with the EC3000, use reset instead - Log3 $hash, 0, "$name: drecvintr detected"; + Log3 $hash, 0, "$name: drecvintr detected"; JeeLink_ResetDevice($hash); #JeeLink_SimpleWrite($hash, "ec",1); } elsif( $dmsg =~ m/RFM12 hang/ ) { # EC3000 seems not to recover from an RFM12 hang, so do a reset - Log3 $hash, 0, "$name: RFM12 hang detected"; + Log3 $hash, 0, "$name: RFM12 hang detected"; JeeLink_ResetDevice($hash); return; @@ -816,8 +845,17 @@ JeeLink_Attr(@) $hash->{Clients} = $aVal; $hash->{Clients} = $clientsJeeLink if( !$hash->{Clients}) ; } elsif( $aName eq "MatchList" ) { - $hash->{MatchList} = $aVal; - $hash->{MatchList} = \%matchListPCA301 if( !$hash->{MatchList} ); + my $match_list = eval $aVal; + if( $@ ) { + Log3 $name, 2, $name .": $aVal: ". $@; + } + + if( ref($match_list) eq 'HASH' ) { + $hash->{MatchList} = $match_list; + } else { + $hash->{MatchList} = \%matchListPCA301 if( !$hash->{MatchList} ); + Log3 $name, 2, $name .": $aVal: not a HASH"; + } } elsif($aName =~ m/^tune/i) { #tune attribute freq / rx:bWidth / rx:rAmpl / rx:sens / tx:deviation / tx:power # Frequenze: Fc =860+ F x0.0050MHz # LNA Gain [dB] = MAX -6, -14, -20 @@ -887,12 +925,18 @@ sub JeeLink_getIndexOfArray($@) { It is possible to attach more than one device in order to get better reception, fhem will filter out duplicate messages.

- This module provides the IODevice for the PCA301 modules that implements the PCA301 protocoll.

- In the future other RF devices like the Energy Controll 3000, JeeLabs room nodes, fs20 or kaku devices will be supportet.

+ This module provides the IODevice for: +
    +
  • PCA301 modules that implement the PCA301 protocol.
  • +
  • LaCrosse modules that implement the IT+ protocol (Sensors like TX29DTH, TX35, ...).
  • +
  • LevelSender for measuring tank levels
  • +
  • EMT7110 energy meter
  • +
  • Other Sensors like WT440XH (their protocol gets transformed to IT+)
  • +
- Note: this module may require the Device::SerialPort or Win32::SerialPort - module if you attach the device via USB and the OS sets strange default - parameters for serial devices. +
+ Note: this module may require the Device::SerialPort or Win32::SerialPort module if you attach the device via USB + and the OS sets strange default parameters for serial devices.

@@ -918,39 +962,99 @@ sub JeeLink_getIndexOfArray($@) { perl module Device::SerialPort is not needed, and fhem opens the device with simple file io. This might work if the operating system uses sane defaults for the serial parameters, e.g. some Linux distributions and - OSX.

+ OSX.

-
Set
    -
  • raw <datar>
    - send <data> as a raw message to the JeeLink to be transmitted over the RF link. -
  • +
  • raw <data>
    + send <data> to the JeeLink. Depending on the sketch running on the JeeLink, different commands are available. Most of the sketches support the v command to get the version info and the ? command to get the list of available commands. +

  • +
  • reset
    - force a device reset closing and reopening the device.
  • + force a device reset closing and reopening the device. +
    +
  • LaCrossePairForSec <sec> [ignore_battery]
    - enable autocreate of new LaCrosse sensors for <sec> seconds. if ignore_battery is not given only sensors + enable autocreate of new LaCrosse sensors for <sec> seconds. If ignore_battery is not given only sensors sending the 'new battery' flag will be created. -
  • +
    + +
  • flash [hexFile]
    + The JeeLink needs the right firmware to be able to receive and deliver the sensor data to fhem. In addition to the way using the + arduino IDE to flash the firmware into the JeeLink this provides a way to flash it directly from FHEM. + + There are some requirements: +
      +
    • avrdude must be installed on the host
      + On a Raspberry PI this can be done with: sudo apt-get install avrdude
    • +
    • the flashCommand attribute must be set.
      + This attribute defines the command, that gets sent to avrdude to flash the JeeLink.
      + The default is: avrdude -p atmega328P -c arduino -P [PORT] -D -U flash:w:[HEXFILE] 2>[LOGFILE]
      + It contains some place-holders that automatically get filled with the according values:
      +
        +
      • [PORT]
        + is the port the JeeLink is connectd to (e.g. /dev/ttyUSB0)
      • +
      • [HEXFILE]
        + is the .hex file that shall get flashed. There are three options (applied in this order):
        + - passed in set flash
        + - taken from the hexFile attribute
        + - the default value defined in the module
        +
      • +
      • [LOGFILE]
        + The logfile that collects information about the flash process. It gets displayed in FHEM after finishing the flash process
      • +
      +
    • +
    + +

  • + +
  • led <on|off>
    + Is used to disable the blue activity LED +

  • + +
  • beep
    + ... +

  • + +
  • setReceiverMode
    + ... +

  • +
Get
+
Attributes
    -
  • Clients
  • -
  • MatchList
  • +
  • Clients
    + The received data gets distributed to a client (e.g. LaCrosse, EMT7110, ...) that handles the data. + This attribute tells, which are the clients, that handle the data. If you add a new module to FHEM, that shall handle + data distributed by the JeeLink module, you must add it to the Clients attribute.
  • + +
  • MatchList
    + can be set to a perl expression that returns a hash that is used as the MatchList
    + attr myJeeling MatchList {'5:AliRF' => '^\\S+\\s+5 '}
  • +
  • initCommands
    - space separated list of commands to send for device initialization
  • + Space separated list of commands to send for device initialization.
    + This can be used e.g. to bring the LaCrosse Sketch into the data rate toggle mode. In this case initCommands would be: 30t + + +
  • flashCommand
    + See "Set flash" +

  • + +