2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-16 10:46:03 +00:00

98_HTTPMOD: new attr followGet to allow chaining of get commands

git-svn-id: https://svn.fhem.de/fhem/trunk@23641 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
StefanStrobel 2021-01-30 14:23:07 +00:00
parent b5e1929d4c
commit 6f5c922f36

View File

@ -21,7 +21,6 @@
# First version: 25.12.2013 # First version: 25.12.2013
# #
# Todo: # Todo:
# Attribute für Regex und LogLevel zum verstecken bestimmter Fehlermedungen von HttpUtils im ReadCallback
# setXYHintExpression zum dynamischen Ändern / Erweitern der Hints # setXYHintExpression zum dynamischen Ändern / Erweitern der Hints
# extractAllReadings mit Filter / Prefix # extractAllReadings mit Filter / Prefix
# get after set um readings zu aktualisieren # get after set um readings zu aktualisieren
@ -142,7 +141,7 @@ BEGIN {
)); ));
}; };
my $Module_Version = '4.0.17 - 31.12.2020'; my $Module_Version = '4.1.01 - 18.1.2021';
my $AttrList = join (' ', my $AttrList = join (' ',
'(reading|get|set)[0-9]+(-[0-9]+)?Name', '(reading|get|set)[0-9]+(-[0-9]+)?Name',
@ -212,6 +211,8 @@ my $AttrList = join (' ',
'[gs]et[0-9]*TextArg:0,1', # just pass on a raw text value without validation / further conversion '[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 'set[0-9]*ParseResponse:0,1', # parse response to set as if it was a get
'set[0-9]*Method:GET,POST,PUT', # select HTTP method for the set 'set[0-9]*Method:GET,POST,PUT', # select HTTP method for the set
'[gs]et[0-9]*FollowGet', # do a get after the set/get to update readings / create chains
'maxGetChain', # max length of chains
'reAuthRegex', 'reAuthRegex',
'reAuthAlways:0,1', 'reAuthAlways:0,1',
@ -972,11 +973,11 @@ sub DoAuth {
Log3 $name, 4, "$name: DoAuth called with Steps: " . join (" ", sort keys %steps); Log3 $name, 4, "$name: DoAuth called with Steps: " . join (" ", sort keys %steps);
$hash->{sid} = '' if AttrVal($name, "clearSIdBeforeAuth", 0); $hash->{sid} = '' if AttrVal($name, "clearSIdBeforeAuth", 0);
foreach my $step (sort {$b cmp $a} keys %steps) { # reverse sort foreach my $step (sort {$b cmp $a} keys %steps) { # reverse sort because requests are prepended
my $request = PrepareRequest($hash, "sid", $step); my $request = PrepareRequest($hash, "sid", $step);
if ($request->{'url'}) { if ($request->{'url'}) {
$request->{'ignoreRedirects'} = AttrVal($name, "sid${step}IgnoreRedirects", 0); $request->{'ignoreRedirects'} = AttrVal($name, "sid${step}IgnoreRedirects", 0);
$request->{'priority'} = 1; $request->{'priority'} = 1; # prepend at front of queue
AddToSendQueue($hash, $request); AddToSendQueue($hash, $request);
# todo: http method for sid steps? # todo: http method for sid steps?
} else { } else {
@ -1266,6 +1267,7 @@ sub SetFn {
} else { } else {
readingsSingleUpdate($hash, makeReadingName($setName), $rawVal, 0); readingsSingleUpdate($hash, makeReadingName($setName), $rawVal, 0);
} }
ChainGet($hash, 'set', $setNum);
return; return;
} }
@ -1315,10 +1317,35 @@ sub GetFn {
} else { } else {
Log3 $name, 3, "$name: no URL for Get $getNum"; Log3 $name, 3, "$name: no URL for Get $getNum";
} }
ChainGet($hash, 'get', $getNum);
return "$getName requested, watch readings"; return "$getName requested, watch readings";
} }
##########################################
# chain a get after a set or another get
# if specified by attr
sub ChainGet {
my $hash = shift;
my $type = shift;
my $num = shift;
my $name = $hash->{NAME};
my $get = AttrVal($name, "${type}${num}FollowGet", '');
if (!$get) {
delete $hash->{GetChainLength};
return;
}
$hash->{GetChainLength} = ($hash->{GetChainLength} // 0) + 1;
if ($hash->{GetChainLength} > AttrVal($name, "maxGetChain", 10)) {
Log3 $name, 4, "$name: chaining to get $get due to attr ${type}${num}FollowGet suppressed because chain would get longer than maxGetChain";
return;
}
Log3 $name, 4, "$name: chaining to get $get due to attr ${type}${num}FollowGet, Level $hash->{GetChainLength}";
GetFn($hash, $name, $get);
return;
}
################################### ###################################
# request new data from device # request new data from device
# calltype can be update and reread # calltype can be update and reread
@ -1331,10 +1358,9 @@ sub GetUpdate {
Log3 $name, 4, "$name: GetUpdate called ($calltype)"; Log3 $name, 4, "$name: GetUpdate called ($calltype)";
$hash->{'.LastUpdate'} = $now; $hash->{'.LastUpdate'} = $now; # note the we were called - even when not as 'update' and UpdateTimer is not called afterwards
if ($calltype eq 'update') { UpdateTimer($hash, \&HTTPMOD::GetUpdate, 'next') if ($calltype eq 'update'); # set update timer for next round
UpdateTimer($hash, \&HTTPMOD::GetUpdate, 'next'); # set update timer for next round
}
if (IsDisabled($name)) { if (IsDisabled($name)) {
Log3 $name, 5, "$name: GetUpdate called but device is disabled"; Log3 $name, 5, "$name: GetUpdate called but device is disabled";
return; return;
@ -1454,9 +1480,10 @@ sub FormatReading {
$expr = GetFAttr($name, $context, $num, "OExpr", $expr); # new syntax $expr = GetFAttr($name, $context, $num, "OExpr", $expr); # new syntax
# if no encode is specified and bodyDecode did decode automatically, then encode as utf8 by default # if no encode is specified and bodyDecode did decode automatically, then encode as utf8 by default
my $fDefault = ($featurelevel > 5.9 ? 'auto' : ''); #my $fDefault = ($featurelevel > 5.9 ? 'auto' : '');
my $bodyDecode = AttrVal($name, 'bodyDecode', $fDefault); #my $fDefault = 'none';
$encode = 'utf8' if (!$encode && $bodyDecode eq 'auto'); #my $bodyDecode = AttrVal($name, 'bodyDecode', $fDefault);
#$encode = 'utf8' if (!$encode && $bodyDecode eq 'auto');
$val = decode($decode, $val) if ($decode && $decode ne 'none'); $val = decode($decode, $val) if ($decode && $decode ne 'none');
$val = encode($encode, $val) if ($encode && $encode ne 'none'); $val = encode($encode, $val) if ($encode && $encode ne 'none');
@ -2005,8 +2032,8 @@ sub ExtractSid {
} }
################################### ###############################################################
# Check if Auth is necessary # Check if Auth is necessary and queue auth steps if needed
# called from _Read # called from _Read
sub CheckAuth { sub CheckAuth {
my $hash = shift; # hash reference passed to HttpUtils_NonblockingGet (our device) my $hash = shift; # hash reference passed to HttpUtils_NonblockingGet (our device)
@ -2070,11 +2097,11 @@ sub CheckAuth {
if ($doAuth) { if ($doAuth) {
Log3 $name, 4, "$name: CheckAuth decided new authentication required"; Log3 $name, 4, "$name: CheckAuth decided new authentication required";
if ($request->{retryCount} < AttrVal($name, "authRetries", 1)) { if ($request->{retryCount} < AttrVal($name, "authRetries", 1)) {
DoAuth $hash;
if (!AttrVal($name, "dontRequeueAfterAuth", 0)) { if (!AttrVal($name, "dontRequeueAfterAuth", 0)) {
AddToSendQueue ($hash, { %{$request}, 'retryCount' => $request->{retryCount}+1, 'value' => $request->{value} } ); AddToSendQueue ($hash, { %{$request}, 'priority' => 1, 'retryCount' => $request->{retryCount}+1, 'value' => $request->{value} } );
Log3 $name, 4, "$name: CheckAuth requeued request $request->{type} after auth, retryCount $request->{retryCount} ..."; Log3 $name, 4, "$name: CheckAuth prepended request $request->{type} again before auth, retryCount $request->{retryCount} ...";
} }
DoAuth $hash;
return 1; return 1;
} else { } else {
Log3 $name, 4, "$name: Authentication still required but no retries left - did last authentication fail?"; Log3 $name, 4, "$name: Authentication still required but no retries left - did last authentication fail?";
@ -3366,12 +3393,12 @@ sub AddToSendQueue {
If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to modidify this attribute. If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to modidify this attribute.
Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br> Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br>
<li><b>bodyDecode</b></li> <li><b>bodyDecode</b></li>
defines an encoding to be used in a call to the perl function decode to convert the raw http response body data string read from the device before further processing / matching<br> defines an encoding to be used in a call to the perl function decode to convert the raw http response body data string
read from the device before further processing / matching<br>
If you have trouble matching special characters or if your reading values contain Umlauts If you have trouble matching special characters or if your reading values contain Umlauts
and they are shown as strange looking icons then might need to use this feature.<br> and they are shown as strange looking icons then you might need to use this feature.<br>
This attribute defaults to auto since Fhem featurelevel > 5.9. HTTPMOD automatically looks for a charset header and decodes the body acordingly. If this attribute is set to 'auto' then HTTPMOD automatically looks for a charset header and decodes the body acordingly.
If no charset headr is found, the body will remain undecoded. If no charset header is found, the body will remain undecoded.
So you don't want this behavior, you can disable it by setting this attribute to 'none'.
<br> <br>
<li><b>regexDecode</b></li> <li><b>regexDecode</b></li>
defines an encoding to be used in a call to the perl function decode to convert the raw data string from regex attributes before further processing / matching<br> defines an encoding to be used in a call to the perl function decode to convert the raw data string from regex attributes before further processing / matching<br>