From f26213c2f0eefc5d9bbe98e4442d816a56bcc7bb Mon Sep 17 00:00:00 2001 From: HCS <> Date: Sat, 25 Feb 2017 17:49:30 +0000 Subject: [PATCH] 36_LaCrosseGateway: flash and nextion upload non blocking git-svn-id: https://svn.fhem.de/fhem/trunk@13515 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/36_LaCrosseGateway.pm | 370 +++++++++++++++++++++----------- 1 file changed, 248 insertions(+), 122 deletions(-) diff --git a/fhem/FHEM/36_LaCrosseGateway.pm b/fhem/FHEM/36_LaCrosseGateway.pm index 71e0855f2..4e5c2d6e6 100644 --- a/fhem/FHEM/36_LaCrosseGateway.pm +++ b/fhem/FHEM/36_LaCrosseGateway.pm @@ -43,6 +43,7 @@ sub LaCrosseGateway_Initialize($) { ." ownSensors:dispatch,readings,both" ." mode:USB,WiFi,Cable" ." usbFlashCommand" + ." filter" ." $readingFnAttributes"; } @@ -92,6 +93,8 @@ sub LaCrosseGateway_Undef($$) { my ($hash, $arg) = @_; my $name = $hash->{NAME}; + BlockingKill($hash->{helper}{RUNNING_PID}) if(defined($hash->{helper}{RUNNING_PID})); + foreach my $d (sort keys %defs) { if(defined($defs{$d}) && defined($defs{$d}{IODev}) && $defs{$d}{IODev} == $hash) { my $lev = ($reread_active ? 4 : 2); @@ -111,6 +114,209 @@ sub LaCrosseGateway_RemoveLaCrossePair($) { delete($hash->{LaCrossePair}); } +#======================================================================================= +sub LaCrosseGateway_LogOTA($) { + my($text) = @_; + BlockingInformParent("DoTrigger", ["global", " $text"], 0); +} + +#======================================================================================= +sub LaCrosseGateway_StartUpload($) { + my ($string) = @_; + my ($name, $argument) = split("\\|", $string); + my $hash = $defs{$name}; + + sleep(2); + LaCrosseGateway_LogOTA("Started not blocking"); + + my @deviceName = split('@', $hash->{DeviceName}); + my $port = $deviceName[0]; + my $logFile = AttrVal("global", "logdir", "./log") . "/LaCrosseGatewayFlash.log"; + my $hexFile = "./FHEM/firmware/JeeLink_LaCrosseGateway.bin"; + + if(!-e $hexFile) { + LaCrosseGateway_LogOTA("The file '$hexFile' does not exist"); + return $name; + } + + LaCrosseGateway_LogOTA("flashing LaCrosseGateway $name"); + LaCrosseGateway_LogOTA("hex file: $hexFile"); + + if(AttrVal($name, "mode", "WiFi") eq "WiFi") { + eval "use LWP::UserAgent"; + if($@) { + LaCrosseGateway_LogOTA("ERROR: Please install LWP::UserAgent"); + return $name; + } + eval "use HTTP::Request::Common"; + if($@) { + LaCrosseGateway_LogOTA("ERROR: Please install HTTP::Request::Common"); + return $name; + } + + LaCrosseGateway_LogOTA("Mode is LaCrosseGateway OTA-update"); + DevIo_CloseDev($hash); + readingsSingleUpdate($hash, "state", "disconnected", 1); + LaCrosseGateway_LogOTA("$name closed"); + + my @spl = split(':', $hash->{DeviceName}); + my $targetIP = $spl[0]; + my $targetURL = "http://" . $targetIP . "/ota/firmware.bin"; + LaCrosseGateway_LogOTA("target: $targetURL"); + + my $request = POST($targetURL, Content_Type => 'multipart/form-data', Content => [ file => [$hexFile, "firmware.bin"] ]); + my $userAgent = LWP::UserAgent->new; + $userAgent->timeout(120); + LaCrosseGateway_LogOTA("Upload started, please wait a minute or two ..."); + my $response = $userAgent->request($request); + if ($response->is_success) { + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("--- LGW reports ---------------------------------------------------------------------------"); + my @lines = split /\r\n|\n|\r/, $response->decoded_content; + foreach (@lines) { + LaCrosseGateway_LogOTA($_); + } + LaCrosseGateway_LogOTA("----------------------------------------------------------------------------------------------------"); + + } + else { + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("ERROR: " . $response->code); + my @lines = split /\r\n|\n|\r/, $response->decoded_content; + foreach (@lines) { + LaCrosseGateway_LogOTA($_); + } + } + } + else { + LaCrosseGateway_LogOTA("Mode is LaCrosseGateway USB-update"); + my $usbFlashCommand = AttrVal($name, "usbFlashCommand", ""); + + if ($usbFlashCommand ne "") { + my $command = $usbFlashCommand; + $command =~ s/\Q[PORT]\E/$port/g; + $command =~ s/\Q[BINFILE]\E/$hexFile/g; + $command =~ s/\Q[LOGFILE]\E/$logFile/g; + + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("Upload started, please wait a minute or two ..."); + `$command`; + + if (-e $logFile) { + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("--- esptool ---------------------------------------------------------------------------------"); + local $/ = undef; + open FILE, $logFile; + my $content = ; + my @lines = split /\r\n|\n|\r/, $content; + foreach (@lines) { + LaCrosseGateway_LogOTA($_); + } + LaCrosseGateway_LogOTA("--- esptool ---------------------------------------------------------------------------------"); + LaCrosseGateway_LogOTA(""); + } + else { + LaCrosseGateway_LogOTA("WARNING: esptool created no log file"); + } + } + else { + LaCrosseGateway_LogOTA("No usbFlashCommand found. Please define this attribute."); + } + } + + return $name; +} + +#======================================================================================= +sub LaCrosseGateway_UploadDone($) { + my ($name) = @_; + return unless(defined($name)); + my $hash = $defs{$name}; + delete($hash->{helper}{RUNNING_PID}); + delete($hash->{helper}{FLASHING}); + + LaCrosseGateway_Connect($hash); + LaCrosseGateway_LogOTA("$name opened"); + + LaCrosseGateway_LogOTA("Finshed"); +} + +#======================================================================================= +sub LaCrosseGateway_UploadError($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + delete($hash->{helper}{RUNNING_PID}); + delete($hash->{helper}{FLASHING}); + LaCrosseGateway_LogOTA("Upload failed"); + LaCrosseGateway_Connect($hash); + LaCrosseGateway_LogOTA("$name opened"); +} + +#======================================================================================= +sub LaCrosseGateway_StartNextion($) { + my ($string) = @_; + my ($name, $argument) = split("\\|", $string); + my $hash = $defs{$name}; + + sleep(2); + LaCrosseGateway_LogOTA("Started not blocking"); + + 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"); + + if(!-e $tftFile) { + LaCrosseGateway_LogOTA("The file '$tftFile' does not exist"); + return $name; + } + + LaCrosseGateway_LogOTA("upload Nextion firmware to $name"); + LaCrosseGateway_LogOTA("tft file: $tftFile"); + + eval "use LWP::UserAgent"; + if($@) { + LaCrosseGateway_LogOTA("ERROR: Please install LWP::UserAgent"); + return $name; + } + eval "use HTTP::Request::Common"; + if($@) { + LaCrosseGateway_LogOTA("ERROR: Please install HTTP::Request::Common"); + return $name; + } + + my @spl = split(':', $hash->{DeviceName}); + my $targetIP = $spl[0]; + my $targetURL = "http://" . $targetIP . "/ota/nextion"; + LaCrosseGateway_LogOTA("target: $targetURL"); + + my $request = POST($targetURL, Content_Type => 'multipart/form-data', Content => [ file => [$tftFile, "nextion.tft"] ]); + my $userAgent = LWP::UserAgent->new; + $userAgent->timeout(900); + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("Upload started, this can take 10 minutes or more ..."); + my $response = $userAgent->request($request); + if ($response->is_success) { + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("--- LGW reports ---------------------------------------------------------------------------"); + my @lines = split /\r\n|\n|\r/, $response->decoded_content; + foreach (@lines) { + LaCrosseGateway_LogOTA($_); + } + LaCrosseGateway_LogOTA("----------------------------------------------------------------------------------------------------"); + } + else { + LaCrosseGateway_LogOTA(""); + LaCrosseGateway_LogOTA("ERROR: " . $response->code); + my @lines = split /\r\n|\n|\r/, $response->decoded_content; + foreach (@lines) { + LaCrosseGateway_LogOTA($_); + } + } + + return $name; +} + #======================================================================================= sub LaCrosseGateway_Set($@) { my ($hash, @a) = @_; @@ -126,123 +332,20 @@ sub LaCrosseGateway_Set($@) { LaCrosseGateway_SimpleWrite($hash, $arg); } elsif ($cmd eq "flash") { - my @args = split(' ', $arg); - my $log = ""; - my @deviceName = split('@', $hash->{DeviceName}); - my $port = $deviceName[0]; - my $logFile = AttrVal("global", "logdir", "./log") . "/LaCrosseGatewayFlash.log"; - my $hexFile = "./FHEM/firmware/JeeLink_LaCrosseGateway.bin"; - - return "The file '$hexFile' does not exist" if(!-e $hexFile); - - $log .= "flashing LaCrosseGateway $name\n"; - $log .= "hex file: $hexFile\n"; - - if(AttrVal($name, "mode", "WiFi") eq "WiFi") { - eval "use LWP::UserAgent"; - return "\nERROR: Please install LWP::UserAgent" if($@); - - eval "use HTTP::Request::Common"; - return "\nERROR: Please install HTTP::Request::Common" if($@); - - $log .= "Mode is LaCrosseGateway OTA-update\n"; - DevIo_CloseDev($hash); - readingsSingleUpdate($hash, "state", "disconnected", 1); - $log .= "$name closed\n"; - - my @spl = split(':', $hash->{DeviceName}); - my $targetIP = $spl[0]; - my $targetURL = "http://" . $targetIP . "/ota/firmware.bin"; - $log .= "target: $targetURL\n"; - - my $request = POST($targetURL, Content_Type => 'multipart/form-data', Content => [ file => [$hexFile, "firmware.bin"] ]); - my $userAgent = LWP::UserAgent->new; - $userAgent->timeout(60); - my $response = $userAgent->request($request); - if ($response->is_success) { - $log .= "\n\nSketch reports:\n"; - $log .= $response->decoded_content; - } - else { - $log .= "\nERROR: " . $response->code . " " . $response->decoded_content; - } - } - else { - $log .= "Mode is LaCrosseGateway USB-update\n"; - my $usbFlashCommand = AttrVal($name, "usbFlashCommand", ""); - - if ($usbFlashCommand ne "") { - if (-e $logFile) { - unlink $logFile; - } - - my $command = $usbFlashCommand; - $command =~ s/\Q[PORT]\E/$port/g; - $command =~ s/\Q[BINFILE]\E/$hexFile/g; - $command =~ s/\Q[LOGFILE]\E/$logFile/g; - - $log .= "command: $command\n\n"; - `$command`; - - local $/ = undef; - if (-e $logFile) { - open FILE, $logFile; - my $logText = ; - close FILE; - $log .= "--- esptool ---------------------------------------------------------------------------------\n"; - $log .= $logText; - $log .= "--- esptool ---------------------------------------------------------------------------------\n\n"; - } - else { - $log .= "WARNING: esptool created no log file\n\n"; - } - } - else { - $log .= "\n\nNo usbFlashCommand found. Please define this attribute.\n\n"; - } - } - - LaCrosseGateway_Connect($hash); - $log .= "$name opened\n"; - - return $log; + CallFn("WEB", "ActivateInformFn", $hash, "global"); + DevIo_CloseDev($hash); + readingsSingleUpdate($hash, "state", "disconnected", 1); + $hash->{helper}{FLASHING} = 1; + $hash->{helper}{RUNNING_PID} = BlockingCall("LaCrosseGateway_StartUpload", $name . "|" . $arg, "LaCrosseGateway_UploadDone", 300, "LaCrosseGateway_UploadError", $hash); + return undef; } 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; + CallFn("WEB", "ActivateInformFn", $hash, "global"); + DevIo_CloseDev($hash); + readingsSingleUpdate($hash, "state", "disconnected", 1); + $hash->{helper}{FLASHING} = 1; + $hash->{helper}{RUNNING_PID} = BlockingCall("LaCrosseGateway_StartNextion", $name . "|" . $arg, "LaCrosseGateway_UploadDone", 1200, "LaCrosseGateway_UploadError", $hash); + return undef; } elsif ($cmd eq "LaCrossePairForSec") { my @args = split(' ', $arg); @@ -267,8 +370,7 @@ sub LaCrosseGateway_Set($@) { $po->rts_active(1); $po->dtr_active(1); } - - + LaCrosseGateway_Connect($hash); } elsif ($cmd eq "parse") { LaCrosseGateway_Parse($hash, $hash, $name, $arg); @@ -293,7 +395,7 @@ sub LaCrosseGateway_DoInit($) { my $hash = shift; my $name = $hash->{NAME}; - my $enabled = AttrVal($name, "disable", "0") != "1"; + my $enabled = AttrVal($name, "disable", "0") != "1" && !defined($hash->{helper}{FLASHING}); if($enabled) { readingsSingleUpdate($hash, "state", "opened", 1); if(AttrVal($name, "mode", "") ne "USB") { @@ -377,6 +479,15 @@ sub LaCrosseGateway_HandleKVP($$) { if($kvp =~ m/FramesPerMinute=(.*?)(\,|\ ,)/) { readingsBulkUpdate($hash, "FramesPerMinute", $1); } + if($kvp =~ m/ReceivedFrames=(.*?)(\,|\ ,)/) { + readingsBulkUpdate($hash, "ReceivedFrames", $1); + } + if($kvp =~ m/FreeHeap=(.*?)(\,|\ ,)/) { + readingsBulkUpdate($hash, "FreeHeap", $1); + } + if($kvp =~ m/OLED=(.*?)(\,|\ ,)/) { + readingsBulkUpdate($hash, "OLED", $1); + } readingsEndUpdate($hash, 1); } @@ -442,16 +553,19 @@ sub LaCrosseGateway_HandleAnalogData($$) { }} + #======================================================================================= sub LaCrosseGateway_Parse($$$$) { my ($hash, $iohash, $name, $msg) = @_; next if (!$msg || length($msg) < 1); return if ($msg =~ m/^\*\*\*CLEARLOG/); - return if ($msg =~ m/[^\x20-\x7E]/); - + my $filter = AttrVal($name, "filter", undef); + if(defined($filter)) { + return if ($msg =~ m/$filter/); + } if ($msg =~ m/^LGW/) { if ($msg =~ /ALIVE/) { @@ -550,7 +664,7 @@ sub LaCrosseGateway_Connect($;$) { my $name = $hash->{NAME}; $mode = 0 if!($mode); - my $enabled = AttrVal($name, "disable", "0") != "1"; + my $enabled = AttrVal($name, "disable", "0") != "1" && !defined($hash->{helper}{FLASHING}); if($enabled) { my $ret = DevIo_OpenDev($hash, $mode, "LaCrosseGateway_DoInit"); return $ret; @@ -590,7 +704,7 @@ sub LaCrosseGateway_OnConnectTimer($) { InternalTimer(gettimeofday() + $interval, "LaCrosseGateway_OnConnectTimer", $hash, 0); - if(AttrVal($name, "disable", "0") != "1") { + if(AttrVal($name, "disable", "0") != "1" && !defined($hash->{helper}{FLASHING})) { my ($date, $time, $year, $month, $day, $hour, $min, $sec, $timestamp, $alive); if($useOldMethod) { $alive = InternalVal($name, "${name}_TIME", "2000-01-01 00:00:00"); @@ -819,6 +933,18 @@ sub LaCrosseGateway_Attr(@) {
  • tftFile
    defines the .tft file that shall be used by the Nextion firmware upload (set nextionUpload)

  • + +
  • filter
    + defines a filter (regular expression) that is applied to the incoming data. If the regex matches, the data will be discarded.
    + This allows to suppress sensors, for example those of the neighbour.
    + The data of different kinds of sensors starts with (where xx is the ID):
    + LaCrosse sensor: OK 9 xx
    + EnergyCount 3000: OK 22 xx xx
    + EMT7110: OK EMT7110 xx xx
    + LevelSender: OK LS xx
    + Example: set lgw filter ^OK 22 117 196|^OK 9 49
    + will filter the LaCrosse sensor with ID "49" and the EC3000 with ID "117 196" +