2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-07 12:58:13 +00:00

98_HTTPMOD: little bugfixes and source character encoding

git-svn-id: https://svn.fhem.de/fhem/trunk@14231 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
StefanStrobel 2017-05-09 19:09:53 +00:00
parent 5018289892
commit 8fc8d5cb51

View File

@ -1,6 +1,6 @@
#########################################################################
# $Id$
# fhem Modul für Geräte mit Web-Oberfläche / Webservices
# fhem Modul für Geräte mit Web-Oberfläche / Webservices
#
# This file is part of fhem.
#
@ -32,7 +32,7 @@
# 2014-11-17 added queueing for requests, fixed timeout
# 2014-11-30 fixed race condition, added ignoreRedirects
# an neues HttpUtils angepasst
# 2014-12-05 definierte Attribute werden zu userattr der Instanz hinzugefügt
# 2014-12-05 definierte Attribute werden zu userattr der Instanz hinzugefügt
# use $hash->{HTTPHEADER} or $hash->{httpheader}
# 2014-12-22 Warnung in Set korrigiert
# 2015-02-11 added attributes for a generic get feature, new get function, attributes "map" for readings,
@ -86,7 +86,7 @@
# instead of ignoring everything related
# 2016-02-05 fixed a warning caused by missing initialisation of .setList internal
# 2016-02-07 allowed more regular expression modifiers in RegOpt, added IMap / OMap / IExpr / OExpr
# 2016-02-13 enable sslVersion attribute für HttpUtils and httpVersion
# 2016-02-13 enable sslVersion attribute für HttpUtils and httpVersion
# 2016-02-14 add sslArgs attribute - e.g. as attr myDevice sslArgs SSL_verify_mode,SSL_VERIFY_NONE
# Log old attrs and offer set upgradeAttributes
# 2016-02-15 added replacement type key and set storeKeyValue
@ -138,12 +138,15 @@
# catch warnings in evals - to be finished (drop subroutine and add inline)
# 2017-03-16 Log line removed in JsonFlatter (creates warning if $value is not defined and it is not needed anyways)
# 2017-03-23 new attribute removeBuf
# 2017-05-07 fixed typo in documentation
# 2017-05-08 optimized warning signal handling
# 2017-05-09 fixed character encoding of source file for documentation
#
#
# Todo:
# get after set um readings zu aktualisieren
# definierbarer prefix oder Suffix für Readingsnamen wenn sie von unterschiedlichen gets über readingXY erzeugt werden
# definierbarer prefix oder Suffix für Readingsnamen wenn sie von unterschiedlichen gets über readingXY erzeugt werden
#
# named groups im regexes [?<name>. )
# you can refer to them by absolute number (using "$1" instead of "\g1" , etc)
@ -151,7 +154,7 @@
# -> if named groups exist -
# reading mit Status je get (error, no match, ...) oder reading zum nachverfolgen der schritte, fehler, auth etc.
#
# In _Attr bei Prüfungen auf get auch set berücksichtigen wo nötig, ebenso in der Attr Liste (oft fehlt set)
# In _Attr bei Prüfungen auf get auch set berücksichtigen wo nötig, ebenso in der Attr Liste (oft fehlt set)
# featureAttrs aus hash verarbeiten
#
# Implement IMap und IExpr for get
@ -159,7 +162,7 @@
# replacement scope attribute?
# make axtracting the sid after a get / update an attribute / option?
# multi page log extraction?
# Profiling von Modbus übernehmen?
# Profiling von Modbus übernehmen?
# extend httpmod to support simple tcp connections aver devio instead of HttpUtils?
# extend devio for non blocking connect like httputils?
#
@ -168,9 +171,9 @@
# verwendung von defptr:
# $hash->{defptr}{readingBase}{$reading} gibt zu einem Reading-Namen den Ursprung an, z.B. get oder reading
# readingNum die zugehörige Nummer, z.B. 01
# readingNum die zugehörige Nummer, z.B. 01
# readingSubNum ggf. eine Unternummer (bei reading01-001)
# wird von MaxAge verwendet um schnell zu einem Reading die zugehörige MaxAge Definition finden zu können
# wird von MaxAge verwendet um schnell zu einem Reading die zugehörige MaxAge Definition finden zu können
#
# $hash->{defptr}{requestReadings}{$reqType}{$baseReading}
# wird von DeleteOnError und DeleteIfUnmatched verwendet.
@ -179,7 +182,7 @@
# aber ohne eventuelle Extension bei mehreren Matches.
# Liefert "$context $num", also z.B. get 1 - dort wird nach DeleteOn.. gesucht
# wichtig um z.B. von reqType "get01" baseReading "Temperatur" auf reading 02 zu kommen
# falls get01 keine eigenen parsing definitions enthält
# falls get01 keine eigenen parsing definitions enthält
# DeleteOn... wird dann beim reading 02 etc. spezifiziert.
#
@ -204,7 +207,7 @@ sub HTTPMOD_AddToQueue($$$$$;$$$$);
sub HTTPMOD_JsonFlatter($$;$);
sub HTTPMOD_ExtractReading($$$$$);
my $HTTPMOD_Version = '3.3.9 - 23.3.2017';
my $HTTPMOD_Version = '3.3.11 - 8.5.2017';
#
# FHEM module intitialisation
@ -289,9 +292,9 @@ sub HTTPMOD_Initialize($)
"get[0-9]*PullToFile " .
"get[0-9]*PullIterate " .
"set[0-9]+Min " . # todo: min, max und hint auch für get, Schreibweise der Liste auf (get|set) vereinheitlichen
"set[0-9]+Min " . # todo: min, max und hint auch für get, Schreibweise der Liste auf (get|set) vereinheitlichen
"set[0-9]+Max " .
"set[0-9]+Hint " . # Direkte Fhem-spezifische Syntax für's GUI, z.B. "6,10,14" bzw. slider etc.
"set[0-9]+Hint " . # Direkte Fhem-spezifische Syntax für's GUI, z.B. "6,10,14" bzw. slider etc.
"set[0-9]*NoArg:0,1 " . # don't expect a value - for set on / off and similar. (default for get)
"[gs]et[0-9]*TextArg:0,1 " . # just pass on a raw text value without validation / further conversion
"set[0-9]*ParseResponse:0,1 " . # parse response to set as if it was a get
@ -326,7 +329,7 @@ sub HTTPMOD_Initialize($)
"replacement[0-9]+Regex " .
"replacement[0-9]+Mode:reading,internal,text,expression,key " . # defaults to text
"replacement[0-9]+Value " . # device:reading, device:internal, text, replacement expression
"[gs]et[0-9]*Replacement[0-9]+Value " . # can overwrite a global replacement value - todo: auch für auth?
"[gs]et[0-9]*Replacement[0-9]+Value " . # can overwrite a global replacement value - todo: auch für auth?
"do_not_notify:1,0 " .
"disable:0,1 " .
@ -470,9 +473,10 @@ sub HTTPMOD_Attr(@)
if ($cmd eq "set") {
if ($aName =~ /Regex/) { # catch all Regex like attributes
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: set attr $aName $aVal created warning: @_"; };
eval {qr/$aVal/};
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: Attr with invalid regex in attr $name $aName $aVal: $@";
return "Invalid Regex $aVal";
@ -500,9 +504,10 @@ sub HTTPMOD_Attr(@)
my $timeDiff = 0;
my @matchlist = ();
no warnings qw(uninitialized);
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: set attr $aName $aVal created warning: @_"; };
eval $aVal;
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: Attr with invalid Expression in attr $name $aName $aVal: $@";
return "Invalid Expression $aVal";
@ -536,9 +541,10 @@ sub HTTPMOD_Attr(@)
Log3 $name, 5, "$name: validating attr $name $aName $aVal";
if (AttrVal($name, "replacement${2}Mode", "text") eq "expression") {
no warnings qw(uninitialized);
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: set attr $aName $aVal created warning: @_"; };
eval $aVal;
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: Attr with invalid Expression (mode is expression) in attr $name $aName $aVal: $@";
return "Attr with invalid Expression (mode is expression) in attr $name $aName $aVal: $@";
@ -628,7 +634,7 @@ sub HTTPMOD_Attr(@)
my $vgl = $1; # attribute name in list - probably a regex
my $opt = $2; # attribute hint in list
if ($aName =~ $vgl) { # yes - the name in the list now matches as regex
# $aName ist eine Ausprägung eines wildcard attrs
# $aName ist eine Ausprägung eines wildcard attrs
addToDevAttrList($name, "$aName" . $opt); # create userattr with hint to allow changing by click in fhemweb
if ($opt) {
# remove old entries without hint
@ -939,11 +945,11 @@ sub HTTPMOD_ReadKeyValue($$)
}
return $dec;
}
else {
} else {
Log3 $name, 4, "$name: ReadKeyValue could not find key $kName in file";
return undef;
}
return;
}
@ -976,10 +982,10 @@ sub HTTPMOD_Replace($$$)
# value can be specific for a get / set / auth step
my $value = "";
if ($context && defined ($attr{$name}{"${type}Replacement${rNum}Value"})) {
# get / set / auth mit individuellem Replacement für z.B. get01
# get / set / auth mit individuellem Replacement für z.B. get01
$value = $attr{$name}{"${type}Replacement${rNum}Value"};
} elsif ($context && defined ($attr{$name}{"${context}Replacement${rNum}Value"})) {
# get / set / auth mit generischem Replacement für alle gets / sets
# get / set / auth mit generischem Replacement für alle gets / sets
$value = $attr{$name}{"${context}Replacement${rNum}Value"};
} elsif (defined ($attr{$name}{"replacement${rNum}Value"})) {
# ganz generisches Replacement
@ -1016,9 +1022,10 @@ sub HTTPMOD_Replace($$$)
$match = 1;
}
} elsif ($mode eq 'expression') {
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: Replacement $rNum with expression $value created warning: @_"; };
$match = eval {$string =~ s/$regex/$value/gee};
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: Replace: invalid regex / expression: /$regex/$value/gee - $@";
}
@ -1043,10 +1050,11 @@ sub HTTPMOD_ModifyWithExpr($$$$$)
my ($name, $context, $num, $attr, $text) = @_;
my $exp = AttrVal($name, "${context}${num}${attr}", undef);
if ($exp) {
my $old = $text;
my $old = $text;
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: ModifyWithExpr ${context}${num}${attr} created warning: @_"; };
$text = eval($exp);
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: error in $attr for $context $num: $@";
}
@ -1129,7 +1137,7 @@ sub HTTPMOD_Auth($@)
}
$hash->{LastAuthTry} = FmtDateTime(gettimeofday());
HTTPMOD_HandleSendQueue("direct:".$name); # AddToQueue with prio did not call this.
return undef;
return;
}
@ -1168,11 +1176,11 @@ sub HTTPMOD_UpdateHintList($)
} elsif (AttrVal($name, "${context}${num}NoArg", undef)) { # NoArg explicitely specified for a set?
$opt = $oName . ":noArg";
} else {
$opt = $oName; # nur den Namen für opt verwenden.
$opt = $oName; # nur den Namen für opt verwenden.
}
} elsif ($context eq "get") {
if (AttrVal($name, "${context}${num}TextArg", undef)) { # TextArg explicitely specified for a get?
$opt = $oName; # nur den Namen für opt verwenden.
$opt = $oName; # nur den Namen für opt verwenden.
} else {
$opt = $oName . ":noArg"; # sonst noArg bei get
}
@ -1185,6 +1193,7 @@ sub HTTPMOD_UpdateHintList($)
delete $hash->{".updateHintList"};
Log3 $name, 5, "$name: UpdateHintList: setlist = " . $hash->{".setList"};
Log3 $name, 5, "$name: UpdateHintList: getlist = " . $hash->{".getList"};
return;
}
@ -1268,6 +1277,7 @@ sub HTTPMOD_UpdateRequestHash($)
}
}
delete $hash->{".updateRequestHash"};
return;
}
@ -1354,7 +1364,7 @@ sub HTTPMOD_Set($@)
}
# Vorbereitung:
# suche den übergebenen setName in den Attributen und setze setNum
# suche den übergebenen setName in den Attributen und setze setNum
foreach my $aName (keys %{$attr{$name}}) {
if ($aName =~ /^set([0-9]+)Name$/) { # ist das Attribut ein "setXName" ?
@ -1364,15 +1374,15 @@ sub HTTPMOD_Set($@)
}
}
# gültiger set Aufruf? ($setNum oben schon gesetzt?)
# gültiger set Aufruf? ($setNum oben schon gesetzt?)
if(!defined ($setNum)) {
HTTPMOD_UpdateHintList($hash) if ($hash->{".updateHintList"});
return "Unknown argument $setName, choose one of " . $hash->{".setList"};
}
Log3 $name, 5, "$name: set found option $setName in attribute set${setNum}Name";
if (!AttrVal($name, "set${setNum}NoArg", undef)) { # soll überhaupt ein Wert übergeben werden?
if (!defined($setVal)) { # Ist ein Wert übergeben?
if (!AttrVal($name, "set${setNum}NoArg", undef)) { # soll überhaupt ein Wert übergeben werden?
if (!defined($setVal)) { # Ist ein Wert übergeben?
Log3 $name, 3, "$name: set without value given for $setName";
return "no value given to set $setName";
}
@ -1391,8 +1401,8 @@ sub HTTPMOD_Set($@)
%rmap = split (/, *|:/, $rm); # reverse hash aus dem reverse string
if (defined($rmap{$setVal})) { # Eintrag für den übergebenen Wert in der Map?
$rawVal = $rmap{$setVal}; # entsprechender Raw-Wert für das Gerät
if (defined($rmap{$setVal})) { # Eintrag für den übergebenen Wert in der Map?
$rawVal = $rmap{$setVal}; # entsprechender Raw-Wert für das Gerät
Log3 $name, 5, "$name: set found $setVal in rmap and converted to $rawVal";
} else {
Log3 $name, 3, "$name: set value $setVal did not match defined map";
@ -1411,14 +1421,14 @@ sub HTTPMOD_Set($@)
# kein TextArg?
if (!AttrVal($name, "set${setNum}TextArg", undef)) {
# prüfe Min
# prüfe Min
if (AttrVal($name, "set${setNum}Min", undef)) {
my $min = AttrVal($name, "set${setNum}Min", undef);
Log3 $name, 5, "$name: is checking value $rawVal against min $min";
return "set value $rawVal is smaller than Min ($min)"
if ($rawVal < $min);
}
# Prüfe Max
# Prüfe Max
if (AttrVal($name, "set${setNum}Max", undef)) {
my $max = AttrVal($name, "set${setNum}Max", undef);
Log3 $name, 5, "$name: set is checking value $rawVal against max $max";
@ -1432,9 +1442,10 @@ sub HTTPMOD_Set($@)
$exp = AttrVal($name, "set${setNum}IExpr", ""); # new syntax overrides old one
if ($exp) {
my $val = $rawVal;
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: Set IExpr $exp created warning: @_"; };
$rawVal = eval($exp);
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: Set error in setExpr $exp: $@";
} else {
@ -1480,7 +1491,7 @@ sub HTTPMOD_Get($@)
Log3 $name, 5, "$name: get called with $getName " if ($getName ne "?");
# Vorbereitung:
# suche den übergebenen getName in den Attributen, setze getNum falls gefunden
# suche den übergebenen getName in den Attributen, setze getNum falls gefunden
foreach my $aName (keys %{$attr{$name}}) {
if ($aName =~ /^get([0-9]+)Name$/) { # ist das Attribut ein "getXName" ?
if ($getName eq $attr{$name}{$aName}) { # ist es der im konkreten get verwendete getName?
@ -1489,7 +1500,7 @@ sub HTTPMOD_Get($@)
}
}
# gültiger get Aufruf? ($getNum oben schon gesetzt?)
# gültiger get Aufruf? ($getNum oben schon gesetzt?)
if(!defined ($getNum)) {
HTTPMOD_UpdateHintList($hash) if ($hash->{".updateHintList"});
return "Unknown argument $getName, choose one of " . $hash->{".getList"};
@ -1681,10 +1692,11 @@ sub HTTPMOD_FormatReading($$$$$)
my $timeStr = ReadingsTimestamp($name, $reading, 0);
$timeDiff = ($now - time_str2num($timeStr)) if ($timeStr);
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: FormatReadig OExpr $expr created warning: @_"; };
$val = eval $expr;
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: FormatReading error, context $context, expression $expr: $@";
}
@ -1694,8 +1706,8 @@ sub HTTPMOD_FormatReading($$$$$)
if ($map) { # gibt es eine Map?
my %map = split (/, +|:/, $map); # hash aus dem map string
if (defined($map{$val})) { # Eintrag für den gelesenen Wert in der Map?
my $nVal = $map{$val}; # entsprechender sprechender Wert für den rohen Wert aus dem Gerät
if (defined($map{$val})) { # Eintrag für den gelesenen Wert in der Map?
my $nVal = $map{$val}; # entsprechender sprechender Wert für den rohen Wert aus dem Gerät
Log3 $name, 5, "$name: FormatReading found $val in map and converted to $nVal";
$val = $nVal;
} else {
@ -1827,9 +1839,10 @@ sub HTTPMOD_ExtractReading($$$$$)
if ($recomb) {
Log3 $name, 5, "$name: ExtractReading is recombining $match matches with expression $recomb";
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: RecombineExpr $recomb created warning: @_"; };
my $val = (eval $recomb);
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: ExtractReading error in RecombineExpr: $@";
}
@ -1899,9 +1912,10 @@ sub HTTPMOD_PullToFile($$$$)
while ($buffer =~ /$regex/g) {
$matches++;
no warnings qw(uninitialized);
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: RecombineExpr $recombine created warning: @_"; };
my $val = eval($recombine);
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if ($@) {
Log3 $name, 3, "$name: PullToFile error in RecombineExpr $recombine: $@";
} else {
@ -1996,9 +2010,10 @@ sub HTTPMOD_DoMaxAge($)
if ($mode eq "expression") {
Log3 $name, 4, "$name: MaxAge: reading $reading too old - using Perl expression as MaxAge replacement: $rep";
my $val = ReadingsVal($name, $reading, "");
my $oldSig = ($SIG{__WARN__} ? $SIG{__WARN__} : 'DEFAULT');
$SIG{__WARN__} = sub { Log3 $name, 3, "$name: MaxAge replacement expr $rep created warning: @_"; };
$rep = eval($rep);
$SIG{__WARN__} = 'DEFAULT';
$SIG{__WARN__} = $oldSig;
if($@) {
Log3 $name, 3, "$name: MaxAge: error in replacement expression $1: $@";
$rep = "error in replacement expression";
@ -2682,7 +2697,7 @@ HTTPMOD_AddToQueue($$$$$;$$$$){
=pod
=item device
=item summary retrieves readings from devices with an HTTP Interface
=item summary_DE fragt Readings von Geräten mit HTTP-Interface ab
=item summary_DE fragt Readings von Geräten mit HTTP-Interface ab
=begin html
<a name="HTTPMOD"></a>
@ -3504,7 +3519,7 @@ HTTPMOD_AddToQueue($$$$$;$$$$){
that contains the error message of the last error returned from HttpUtils.
<li><b>removeBuf</b></li>
if set to 1 then HTTPMOD removes the internal named buf when a HTTP-response has been
received. $hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception because it contains a vers long response which looks ugly in Fhemweb.
received. $hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception because it contains a very long response which looks ugly in Fhemweb.
<li><b>timeout</b></li>
time in seconds to wait for an answer. Default value is 2