From 6f5c922f36d9f4c6bda0aad0b2c8dfb586517bd1 Mon Sep 17 00:00:00 2001
From: StefanStrobel <>
Date: Sat, 30 Jan 2021 14:23:07 +0000
Subject: [PATCH] 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
---
fhem/FHEM/98_HTTPMOD.pm | 69 ++++++++++++++++++++++++++++-------------
1 file changed, 48 insertions(+), 21 deletions(-)
diff --git a/fhem/FHEM/98_HTTPMOD.pm b/fhem/FHEM/98_HTTPMOD.pm
index 20affec44..c4106fef3 100755
--- a/fhem/FHEM/98_HTTPMOD.pm
+++ b/fhem/FHEM/98_HTTPMOD.pm
@@ -21,7 +21,6 @@
# First version: 25.12.2013
#
# Todo:
-# Attribute für Regex und LogLevel zum verstecken bestimmter Fehlermedungen von HttpUtils im ReadCallback
# setXYHintExpression zum dynamischen Ändern / Erweitern der Hints
# extractAllReadings mit Filter / Prefix
# 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 (' ',
'(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
'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
+ '[gs]et[0-9]*FollowGet', # do a get after the set/get to update readings / create chains
+ 'maxGetChain', # max length of chains
'reAuthRegex',
'reAuthAlways:0,1',
@@ -972,11 +973,11 @@ sub DoAuth {
Log3 $name, 4, "$name: DoAuth called with Steps: " . join (" ", sort keys %steps);
$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);
if ($request->{'url'}) {
$request->{'ignoreRedirects'} = AttrVal($name, "sid${step}IgnoreRedirects", 0);
- $request->{'priority'} = 1;
+ $request->{'priority'} = 1; # prepend at front of queue
AddToSendQueue($hash, $request);
# todo: http method for sid steps?
} else {
@@ -1266,6 +1267,7 @@ sub SetFn {
} else {
readingsSingleUpdate($hash, makeReadingName($setName), $rawVal, 0);
}
+ ChainGet($hash, 'set', $setNum);
return;
}
@@ -1315,10 +1317,35 @@ sub GetFn {
} else {
Log3 $name, 3, "$name: no URL for Get $getNum";
}
+ ChainGet($hash, 'get', $getNum);
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
# calltype can be update and reread
@@ -1331,10 +1358,9 @@ sub GetUpdate {
Log3 $name, 4, "$name: GetUpdate called ($calltype)";
- $hash->{'.LastUpdate'} = $now;
- if ($calltype eq 'update') {
- UpdateTimer($hash, \&HTTPMOD::GetUpdate, 'next'); # set update timer for next round
- }
+ $hash->{'.LastUpdate'} = $now; # note the we were called - even when not as 'update' and UpdateTimer is not called afterwards
+ UpdateTimer($hash, \&HTTPMOD::GetUpdate, 'next') if ($calltype eq 'update'); # set update timer for next round
+
if (IsDisabled($name)) {
Log3 $name, 5, "$name: GetUpdate called but device is disabled";
return;
@@ -1454,9 +1480,10 @@ sub FormatReading {
$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
- my $fDefault = ($featurelevel > 5.9 ? 'auto' : '');
- my $bodyDecode = AttrVal($name, 'bodyDecode', $fDefault);
- $encode = 'utf8' if (!$encode && $bodyDecode eq 'auto');
+ #my $fDefault = ($featurelevel > 5.9 ? 'auto' : '');
+ #my $fDefault = 'none';
+ #my $bodyDecode = AttrVal($name, 'bodyDecode', $fDefault);
+ #$encode = 'utf8' if (!$encode && $bodyDecode eq 'auto');
$val = decode($decode, $val) if ($decode && $decode 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
sub CheckAuth {
my $hash = shift; # hash reference passed to HttpUtils_NonblockingGet (our device)
@@ -2070,11 +2097,11 @@ sub CheckAuth {
if ($doAuth) {
Log3 $name, 4, "$name: CheckAuth decided new authentication required";
if ($request->{retryCount} < AttrVal($name, "authRetries", 1)) {
- DoAuth $hash;
if (!AttrVal($name, "dontRequeueAfterAuth", 0)) {
- AddToSendQueue ($hash, { %{$request}, 'retryCount' => $request->{retryCount}+1, 'value' => $request->{value} } );
- Log3 $name, 4, "$name: CheckAuth requeued request $request->{type} after auth, retryCount $request->{retryCount} ...";
+ AddToSendQueue ($hash, { %{$request}, 'priority' => 1, 'retryCount' => $request->{retryCount}+1, 'value' => $request->{value} } );
+ Log3 $name, 4, "$name: CheckAuth prepended request $request->{type} again before auth, retryCount $request->{retryCount} ...";
}
+ DoAuth $hash;
return 1;
} else {
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.
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.