From a3e56048f51695e32dccff82d00e209f50255b4c Mon Sep 17 00:00:00 2001 From: HCS <> Date: Mon, 26 Dec 2016 22:20:36 +0000 Subject: [PATCH] 36_LaCrosseGateway: analog, new timeout git-svn-id: https://svn.fhem.de/fhem/trunk@12881 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/36_LaCrosseGateway.pm | 181 +++++++++++++++++++++++++++----- 1 file changed, 157 insertions(+), 24 deletions(-) diff --git a/fhem/FHEM/36_LaCrosseGateway.pm b/fhem/FHEM/36_LaCrosseGateway.pm index fd47ab496..c11fdc7e9 100644 --- a/fhem/FHEM/36_LaCrosseGateway.pm +++ b/fhem/FHEM/36_LaCrosseGateway.pm @@ -36,7 +36,9 @@ sub LaCrosseGateway_Initialize($) { ." dummy" ." initCommands" ." timeout" + ." watchdog" ." disable:0,1" + ." tftFile" ." kvp:dispatch,readings,both" ." ownSensors:dispatch,readings,both" ." mode:USB,WiFi,Cable" @@ -111,7 +113,7 @@ sub LaCrosseGateway_Set($@) { my $cmd = shift @a; my $arg = join(" ", @a); - my $list = "raw connect LaCrossePairForSec flash parse reboot"; + my $list = "raw connect LaCrossePairForSec flash nextionUpload parse reboot"; return $list if( $cmd eq '?' || $cmd eq ''); if ($cmd eq "raw") { @@ -164,6 +166,43 @@ sub LaCrosseGateway_Set($@) { return $log; } + elsif ($cmd eq "nextionUpload") { + my $log = ""; + my @deviceName = split('@', $hash->{DeviceName}); + my $port = $deviceName[0]; + my $logFile = AttrVal("global", "logdir", "./log") . "/NextionUpload.log"; + my $tftFile = AttrVal($name, "tftFile", "./FHEM/firmware/nextion.tft"); + + return "The file '$tftFile' does not exist" if(!-e $tftFile); + + $log .= "upload Nextion firmware to $name\n"; + $log .= "tft file: $tftFile\n"; + + eval "use LWP::UserAgent"; + return "\nERROR: Please install LWP::UserAgent" if($@); + + eval "use HTTP::Request::Common"; + return "\nERROR: Please install HTTP::Request::Common" if($@); + + my @spl = split(':', $hash->{DeviceName}); + my $targetIP = $spl[0]; + my $targetURL = "http://" . $targetIP . "/ota/nextion"; + $log .= "target: $targetURL\n"; + + my $request = POST($targetURL, Content_Type => 'multipart/form-data', Content => [ file => [$tftFile, "nextion.tft"] ]); + my $userAgent = LWP::UserAgent->new; + $userAgent->timeout(300); + my $response = $userAgent->request($request); + if ($response->is_success) { + $log .= "\n\nLGW reports:\n"; + $log .= $response->decoded_content; + } + else { + $log .= "\nERROR: " . $response->code . " " . $response->decoded_content; + } + + return $log; + } elsif ($cmd eq "LaCrossePairForSec") { my @args = split(' ', $arg); @@ -333,16 +372,51 @@ sub LaCrosseGateway_HandleOwnSensors($$) { } +#======================================================================================= +sub LaCrosseGateway_HandleAnalogData($$) { + my ($hash, $data) = @_; + + if ($data =~ m/^LGW ANALOG /) { + readingsBeginUpdate($hash); + + my @bytes = split( ' ', substr($data, 10) ); + return "" if(@bytes < 2); + + my $value = $bytes[0]*256 + $bytes[1]; + readingsBulkUpdate($hash, "analog", $value); + + readingsEndUpdate($hash, 1); + +}} + #======================================================================================= sub LaCrosseGateway_Parse($$$$) { my ($hash, $iohash, $name, $msg) = @_; - next if(!$msg || length($msg) < 1); + next if (!$msg || length($msg) < 1); return if ($msg =~ m/^\*\*\*CLEARLOG/); + if ($msg =~ m/^LGW/) { + if ($msg =~ /ALIVE/) { + $hash->{Alive} = TimeNow(); + } + + LaCrosseGateway_HandleAnalogData($hash, $msg); + + return; + } + if($msg =~ m/^\[LaCrosseITPlusReader.Gateway/ ) { $hash->{model} = $msg; + my $attrVal = AttrVal($name, "timeout", undef); + if(defined($attrVal)) { + my ($timeout, $interval) = split(',', $attrVal); + if (!$interval) { + $hash->{Alive} = TimeNow(); + } + } + if (ReadingsVal($name, "state", "") eq "opened") { if (my $initCommandsString = AttrVal($name, "initCommands", undef)) { my @initCommands = split(' ', $initCommandsString); @@ -428,29 +502,61 @@ sub LaCrosseGateway_Connect($;$) { return undef; } +#======================================================================================= +sub LaCrosseGateway_TriggerWatchdog($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + my $watchDog = ""; + + my $watchDogAttribute = AttrVal($name, "watchdog", undef); + if($watchDogAttribute) { + $watchDog = "=$watchDogAttribute" + } + + my $command = "\"WATCHDOG Ping$watchDog\""; + + LaCrosseGateway_SimpleWrite($hash, $command); +} + #======================================================================================= sub LaCrosseGateway_OnConnectTimer($) { my ($hash) = @_; my $name = $hash->{NAME}; - + RemoveInternalTimer($hash, "LaCrosseGateway_OnConnectTimer"); my $attrVal = AttrVal($name, "timeout", undef); if(defined($attrVal)) { my ($timeout, $interval) = split(',', $attrVal); - my $LaCrosseGatewayTime = InternalVal($name, "${name}_TIME", "2000-01-01 00:00:00"); - my ($date, $time, $year, $month, $day, $hour, $min, $sec, $timestamp); - ($date, $time) = split( ' ', $LaCrosseGatewayTime); - ($year, $month, $day) = split( '-', $date); - ($hour, $min, $sec) = split( ':', $time); - $month -= 01; - $timestamp = timelocal($sec, $min, $hour, $day, $month, $year); + my $useOldMethod = $interval; + $interval = $timeout if !$interval; InternalTimer(gettimeofday() + $interval, "LaCrosseGateway_OnConnectTimer", $hash, 0); - - if (gettimeofday() - $timestamp > $timeout) { - return LaCrosseGateway_Connect($hash, 1); + + if(AttrVal($name, "disable", "0") != "1") { + my ($date, $time, $year, $month, $day, $hour, $min, $sec, $timestamp, $alive); + if($useOldMethod) { + $alive = InternalVal($name, "${name}_TIME", "2000-01-01 00:00:00"); + } + else { + LaCrosseGateway_TriggerWatchdog($hash); + $timeout += 5; + $alive = $hash->{Alive}; + $alive = "2000-01-01 00:00:00" if !$alive; + } + + ($date, $time) = split( ' ', $alive); + ($year, $month, $day) = split( '-', $date); + ($hour, $min, $sec) = split( ':', $time); + $month -= 01; + $timestamp = timelocal($sec, $min, $hour, $day, $month, $year); + + if (gettimeofday() - $timestamp > $timeout) { + return LaCrosseGateway_Connect($hash, 1); + } + } + } } @@ -464,14 +570,17 @@ sub LaCrosseGateway_Attr(@) { $hash->{Clients} = $clients if( !$hash->{Clients}); } elsif ($aName eq "timeout") { - return "Usage: attr $name $aName " if($aVal && $aVal !~ m/^[0-9]{1,6},[0-9]{1,6}$/); + return "Usage: attr $name $aName " if($aVal && $aVal !~ m/^[0-9]{1,6}(,[0-9]{1,6})*/); RemoveInternalTimer($hash, "LaCrosseGateway_OnConnectTimer"); if($aVal) { + LaCrosseGateway_TriggerWatchdog($hash); + my ($timeout, $interval) = split(',', $aVal); + $interval = $timeout if !$interval; InternalTimer(gettimeofday()+$interval, "LaCrosseGateway_OnConnectTimer", $hash, 0); } - + } elsif ($aName eq "disable") { if($aVal eq "1") { @@ -572,9 +681,16 @@ sub LaCrosseGateway_Attr(@) {
  • flash
    - The LaCrosseGateway needs the right firmware to be able to receive and deliver the sensor data to fhem. - This provides a way to flash it directly from FHEM.

    + The LaCrosseGateway needs the right firmware to be able to receive and deliver the sensor data to fhem.
    + This provides a way to flash it directly from FHEM.

  • + +
  • nextionUpload
    + Requires LaCrosseGateway V1.24 or newer.
    + Sends a Nextion firmware file (.tft) to the LaCrosseGateway. The LaCrosseGateway then distributes it to a connected Nextion display.
    + You can define the .tft file that shall be uploaded in the tftFile attribute. If this attribute does not exists, it will try to use FHEM/firmware/nextion.tft +

  • + @@ -594,32 +710,45 @@ sub LaCrosseGateway_Attr(@) {
  • MatchList
    - Can be set to a perl expression that returns a hash that is used as the MatchList
    + Can be set to a perl expression that returns a hash that is used as the MatchList

  • initCommands
    - Space separated list of commands to send for device initialization.
    + Space separated list of commands to send for device initialization.

  • timeout
    - format: <timeout, checkInterval> - Checks every 'checkInterval' seconds if the last data reception is longer than 'timout' seconds ago.
    + format: <timeout>
    + Asks the LaCrosseGateway every timeout seconds if it is still alive. If there is no response it reconnects to the LaCrosseGateway.
    + Can be combined with the watchdog attribute. If the watchdog attribute is set, the LaCrosseGateway also will check if it gets + a request within watchdog seconds and if not, it will reboot. + watchdog must be longer than timeout and does only work in combination with timeout.
    + Both should not be too short because the LaCrosseGateway needs enough time to boot before the next check.
    + Good values are: timeout 60 and watchdog 300
    + This mode needs LaCrosseGateway V1.24 or newer. +

    Old version (still working):
    + format: <timeout, checkInterval>
    + Checks every 'checkInterval' seconds if the last data reception is longer than 'timeout' seconds ago.
    If this is the case, a new connect will be tried.

  • +
  • watchdog
    + see timeout attribute. +

  • +
  • disable
    if disabled, it does not try to connect and does not dispatch data

  • kvp
    - defines how the incoming KVP-data of the LGW is handled
    + defines how the incoming KVP-data of the LaCrosseGateway is handled
    dispatch: (default) dispatch it to a KVP device
    readings: create readings (e.g. RSSI, ...) in this device
    both: dispatch and create readings

  • ownSensors
    - defines how the incoming data of the internal LGW sensors is handled
    + defines how the incoming data of the internal LaCrosseGateway sensors is handled
    dispatch: (default) dispatch it to a LaCrosse device
    readings: create readings (e.g. temperature, humidity, ...) in this device
    both: dispatch and create readings @@ -627,7 +756,11 @@ sub LaCrosseGateway_Attr(@) {
  • mode
    USB, WiFi or Cable
    - Depending on how the LGW ist connected, it must be handled differently (init, ...) + Depending on how the LaCrosseGateway is connected, it must be handled differently (init, ...) +

  • + +
  • tftFile
    + defines the .tft file that shall be used by the Nextion firmware upload (set nextionUpload)