2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-09 20:57:11 +00:00

36_LaCrosseGateway: flash and nextion upload non blocking

git-svn-id: https://svn.fhem.de/fhem/trunk@13515 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
HCS 2017-02-25 17:49:30 +00:00
parent 44be045253
commit f26213c2f0

View File

@ -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 = <FILE>;
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 = <FILE>;
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(@) {
<li>tftFile<br>
defines the .tft file that shall be used by the Nextion firmware upload (set nextionUpload)
</li><br>
<li>filter<br>
defines a filter (regular expression) that is applied to the incoming data. If the regex matches, the data will be discarded.<br>
This allows to suppress sensors, for example those of the neighbour.<br>
The data of different kinds of sensors starts with (where xx is the ID):<br>
LaCrosse sensor: OK 9 xx<br>
EnergyCount 3000: OK 22 xx xx<br>
EMT7110: OK EMT7110 xx xx<br>
LevelSender: OK LS xx<br>
Example: set lgw filter ^OK 22 117 196|^OK 9 49<br>
will filter the LaCrosse sensor with ID "49" and the EC3000 with ID "117 196"
</li><br>
</ul>
<br>