76_SMAPortal: contrib 3.7.0

git-svn-id: https://svn.fhem.de/fhem/trunk@23173 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
DS_Starter
2020-11-18 14:07:45 +00:00
parent 520c8da142
commit 4d4a262d1f

View File

@@ -49,7 +49,6 @@ use LWP::UserAgent;
use HTTP::Cookies; use HTTP::Cookies;
use JSON qw(decode_json); use JSON qw(decode_json);
use MIME::Base64; use MIME::Base64;
use Color;
use Encode; use Encode;
use utf8; use utf8;
@@ -138,7 +137,7 @@ BEGIN {
# Versions History intern # Versions History intern
my %vNotesIntern = ( my %vNotesIntern = (
"3.7.0" => "16.11.2020 add new consumer management for switched sockets and EVCharger ", "3.7.0" => "18.11.2020 add new consumer management for switched sockets and EVCharger ",
"3.6.5" => "12.11.2020 verbose5data switchConsumer, more preselected user agents ", "3.6.5" => "12.11.2020 verbose5data switchConsumer, more preselected user agents ",
"3.6.4" => "11.11.2020 preselect the user agent randomly, set min. interval to 180 s ", "3.6.4" => "11.11.2020 preselect the user agent randomly, set min. interval to 180 s ",
"3.6.3" => "05.11.2020 fix only four consumer are shown in set command drop down list ", "3.6.3" => "05.11.2020 fix only four consumer are shown in set command drop down list ",
@@ -288,7 +287,7 @@ my %hal = (
my %hsusyid = ( # Schalten/Management der Verbraucher entspr. ihrer SUSyID my %hsusyid = ( # Schalten/Management der Verbraucher entspr. ihrer SUSyID
191 => { arg => ":on,off,auto", fn => \&_switchConsumer }, # 191 = Schaltdosen 191 => { arg => ":on,off,auto", fn => \&_switchConsumer }, # 191 = Schaltdosen
315 => { arg => ":colorpicker,CT,0,1,100", fn => \&_manageConsumerByEnergy }, # 315 = SMA EV Charger 315 => { arg => ":slider,0,1,100", fn => \&_manageConsumerByEnergy }, # 315 = SMA EV Charger
); );
# Tags der verfügbaren Datenquellen # Tags der verfügbaren Datenquellen
@@ -844,9 +843,14 @@ sub CallInfo { ## no critic 'complexity'
} }
if ($hash->{HELPER}{RUNNING_PID}) { if ($hash->{HELPER}{RUNNING_PID}) {
if($hash->{HELPER}{RUNNING_PID}{pid} =~ m/DEAD/) { # tote PID's löschen
delete $hash->{HELPER}{RUNNING_PID};
}
else {
Log3 ($name, 3, "$name - An old data cycle is still running, the new data cycle start is postponed."); Log3 ($name, 3, "$name - An old data cycle is still running, the new data cycle start is postponed.");
return; return;
} }
}
my $getp = $hash->{HELPER}{GETTER}; my $getp = $hash->{HELPER}{GETTER};
my $setp = $hash->{HELPER}{SETTER}; my $setp = $hash->{HELPER}{SETTER};
@@ -1307,8 +1311,8 @@ sub _manageConsumerByEnergy {
my $hash = $defs{$name}; my $hash = $defs{$name};
my $pvval = $op/100; my $gcval = $op/100;
my $gcval = 1-$pvval; my $pvval = 1-$gcval;
my ($serial,$oid,$oname); my ($serial,$oid,$oname);
@@ -1321,8 +1325,8 @@ sub _manageConsumerByEnergy {
} }
} }
my $gclog = 100-$op; my $pvlog = 100-$op;
Log3 ($name, 4, qq{$name - Manage consumer "$d" (SuSyID $susyid): switch on if condition PV=$op% (GridConsumption=$gclog%) is fulfilled }); Log3 ($name, 4, qq{$name - Manage consumer "$d" (SuSyID $susyid): switch on if condition GridConsumption=$op% (PV=$pvlog%) is fulfilled });
my $plantOid = $hash->{HELPER}{PLANTOID}; my $plantOid = $hash->{HELPER}{PLANTOID};
my $errstate = 0; my $errstate = 0;
@@ -1353,7 +1357,7 @@ sub _manageConsumerByEnergy {
call => 'https://www.sunnyportal.com/HoMan/Consumer/Semp/$oid', call => 'https://www.sunnyportal.com/HoMan/Consumer/Semp/$oid',
tag => $tag, tag => $tag,
state => $state, state => $state,
fnaref => [ qw( extractSwitchConsumerData ) ], fnaref => [ qw( extractConsumerByEnergyData ) ],
fields => \%fields, fields => \%fields,
content => $cont, content => $cont,
addon => "$d:$susyid:$op", # optionales Addon für aufzurufende Funktion addon => "$d:$susyid:$op", # optionales Addon für aufzurufende Funktion
@@ -1686,8 +1690,6 @@ sub _getBalanceDayData { ## no critic "not used"
my $state = $paref->{state}; my $state = $paref->{state};
my $daref = $paref->{daref}; # Referenz zum Datenarray my $daref = $paref->{daref}; # Referenz zum Datenarray
# _detailViewOn ($paref); # Detailanzeige einschalten
my ($reread,$retry,$errstate) = (0,0,0); my ($reread,$retry,$errstate) = (0,0,0);
my @bd = split /\s+/x ,AttrVal($name, "balanceDay", "current"); my @bd = split /\s+/x ,AttrVal($name, "balanceDay", "current");
@@ -1770,8 +1772,6 @@ sub _getBalanceMonthData { ## no critic "not used"
my $state = $paref->{state}; my $state = $paref->{state};
my $daref = $paref->{daref}; # Referenz zum Datenarray my $daref = $paref->{daref}; # Referenz zum Datenarray
# _detailViewOn ($paref); # Detailanzeige einschalten
my ($reread,$retry,$errstate) = (0,0,0); my ($reread,$retry,$errstate) = (0,0,0);
my @bd = split /\s+/x ,AttrVal($name, "balanceMonth", "current"); my @bd = split /\s+/x ,AttrVal($name, "balanceMonth", "current");
@@ -1868,8 +1868,6 @@ sub _getBalanceYearData { ## no critic "not used"
my $state = $paref->{state}; my $state = $paref->{state};
my $daref = $paref->{daref}; # Referenz zum Datenarray my $daref = $paref->{daref}; # Referenz zum Datenarray
# _detailViewOn ($paref); # Detailanzeige einschalten
my ($reread,$retry,$errstate) = (0,0,0); my ($reread,$retry,$errstate) = (0,0,0);
my @bd = split /\s+/x ,AttrVal($name, "balanceYear", "current"); my @bd = split /\s+/x ,AttrVal($name, "balanceYear", "current");
@@ -2130,9 +2128,19 @@ sub __dispatchPost {
if ($data_cont && $data_cont !~ m/undefined/ix) { if ($data_cont && $data_cont !~ m/undefined/ix) {
my @func = @$fnref; my @func = @$fnref;
my $params = {
hash => $hash,
daref => $daref,
data_cont => $data_cont,
data => $data,
fnaddon => $fnaddon,
tag => $tag
};
no strict "refs"; ## no critic 'NoStrict' no strict "refs"; ## no critic 'NoStrict'
for my $fn (@func) { for my $fn (@func) {
$state = &{$fn} ($hash,$daref,$data_cont,$fnaddon,$tag) // $state; $state = &{$fn} ($params) // $state;
} }
use strict "refs"; use strict "refs";
} }
@@ -2203,8 +2211,7 @@ sub ___postData {
} }
my $data = $ua->post( $call, %$fields, Content => $content ); my $data = $ua->post( $call, %$fields, Content => $content );
my $dcont = $data->decoded_content;
my $dcont = $data->content;
$cont = eval{decode_json($dcont)} or do { $cont = $dcont }; $cont = eval{decode_json($dcont)} or do { $cont = $dcont };
@@ -2236,6 +2243,7 @@ sub ___analyzeData { ## no critic 'complexity'
my $v5d = AttrVal($name, "verbose5Data", "none"); my $v5d = AttrVal($name, "verbose5Data", "none");
my $ad_content = encode("utf8", $ad->decoded_content); my $ad_content = encode("utf8", $ad->decoded_content);
my $rescode = $ad->code; # HTML Code der Antwort
my $act = $hash->{HELPER}{RETRIES}; # Index aktueller Wiederholungsversuch my $act = $hash->{HELPER}{RETRIES}; # Index aktueller Wiederholungsversuch
my $attstr = "Attempts read data again in $sleepretry s ... ($act of $maxretries)"; # Log vorbereiten my $attstr = "Attempts read data again in $sleepretry s ... ($act of $maxretries)"; # Log vorbereiten
@@ -2326,7 +2334,7 @@ sub ___analyzeData { ## no critic 'complexity'
$njdat = encode("utf8", $ad->decoded_content); $njdat = encode("utf8", $ad->decoded_content);
Log3 ($name, 5, "$name - No JSON Data received:\n ".$njdat); Log3 ($name, 5, "$name - No JSON Data received:\n ".$njdat);
$errstate = 1; $errstate = 1 if($rescode != 302); # 302 -> HTTP-Antwort liefert zusätzlich eine URL im Header-Feld Location. Es soll eine zweite, ansonsten identische Anfrage an die in Location angegebene neue URL gestellt werden.
$state = "ERROR - see logfile for further information"; $state = "ERROR - see logfile for further information";
} }
@@ -2783,23 +2791,26 @@ return;
# Total # Total
################################################################ ################################################################
sub extractStatisticData { sub extractStatisticData {
my $hash = shift; my $paref = shift;
my $daref = shift; my $hash = $paref->{hash};
my $statistic = shift; my $daref = $paref->{daref};
my $period = shift; my $data_cont = $paref->{data_cont}; # empfangene Daten decoded Content
my $tag = shift; my $data = $paref->{data}; # empfangene Rohdaten
my $period = $paref->{fnaddon};
my $tag = $paref->{tag};
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $sd; my $sd;
Log3 ($name, 4, "$name - extracting balance data "); Log3 ($name, 4, "$name - extracting balance data ");
$statistic = eval{decode_json($statistic)} or do { Log3 ($name, 2, "$name - ERROR - can't decode JSON Data"); $data_cont = eval{decode_json($data_cont)} or do { Log3 ($name, 2, "$name - ERROR - can't decode JSON Data");
return; return;
}; };
my $lv = $stpl{$tag}{level}; my $lv = $stpl{$tag}{level};
if(ref $statistic eq "HASH") { if(ref $data_cont eq "HASH") {
$sd = decode_json ( encode('UTF-8', $statistic->{d}) ); $sd = decode_json ( encode('UTF-8', $data_cont->{d}) );
} }
if($sd && ref $sd eq "ARRAY") { if($sd && ref $sd eq "ARRAY") {
@@ -3190,21 +3201,23 @@ return;
# Auswertung Ergebnis aus Switch Consumer # Auswertung Ergebnis aus Switch Consumer
################################################################ ################################################################
sub extractSwitchConsumerData { sub extractSwitchConsumerData {
my $hash = shift; my $paref = shift;
my $daref = shift; # Referenz zum Datenarray my $hash = $paref->{hash};
my $jdata = shift; # empfangene JSON-Daten my $daref = $paref->{daref}; # Referenz zum Datenarray
my $addon = shift; # ein optionales AddOn my $data_cont = $paref->{data_cont}; # Daten decoded Content
my $tag = shift; # Kennzeichen der abgerufenen Daten/ der Abrufroutine my $data = $paref->{data}; # empfangene Rohdaten
my $addon = $paref->{fnaddon}; # ein optionales AddOn
my $tag = $paref->{tag}; # Kennzeichen der abgerufenen Daten/ der Abrufroutine
my $name = $hash->{NAME}; my $name = $hash->{NAME};
Log3 ($name, 4, "$name - extracting Switch Consumer result "); Log3 ($name, 4, "$name - extracting Switch Consumer result ");
my ($d,$susyid,$op) = split(":",$addon); # $op -> Verbraucher Manage Operation my ($d,$susyid,$op) = split(":",$addon); # $op -> Verbraucher Manage Operation
Log3 ($name, 3, qq{$name - Set "$d $op" result: $jdata}); Log3 ($name, 3, qq{$name - Set "$d $op" result: $data_cont});
my $state; my $state;
if($jdata eq "true") { if($data_cont eq "true") {
$state = "ok - switched consumer $d to $op"; $state = "ok - switched consumer $d to $op";
BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "GETTER:all" ], 1); BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "GETTER:all" ], 1);
BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "SETTER:none"], 1); BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "SETTER:none"], 1);
@@ -3216,27 +3229,70 @@ sub extractSwitchConsumerData {
return $state; return $state;
} }
################################################################
# Auswertung Ergebnis aus Manage Consumer
# By Energy
################################################################
sub extractConsumerByEnergyData {
my $paref = shift;
my $hash = $paref->{hash};
my $daref = $paref->{daref}; # Referenz zum Datenarray
my $data_cont = $paref->{data_cont}; # Daten decoded Content
my $data = $paref->{data}; # empfangene Rohdaten
my $addon = $paref->{fnaddon}; # ein optionales AddOn
my $tag = $paref->{tag}; # Kennzeichen der abgerufenen Daten/ der Abrufroutine
my $name = $hash->{NAME};
Log3 ($name, 4, "$name - extracting manage Consumer by energy result ");
my $rescode = $data->code; # HTML Code der Antwort (sollte 302 sein bei Erfolg)
my $location = $data->header('Location');
my ($d,$susyid,$op) = split(":",$addon); # $op -> eingestellter Gridconsomption Schwellenwert
my $pvlog = 100-$op;
Log3 ($name, 3, qq{$name - Consumer "$d" (SuSyID $susyid) set to condition: switch on if GridConsumption=$op% (PV=$pvlog%) is fulfilled });
Log3 ($name, 3, qq{$name - GET "$location" to read the new values are set });
my $state;
if($rescode == 302) {
$state = qq{ok - Consumer "$d" set to condition: switch on if GridConsumption=$op% (PV=$pvlog%) is fulfilled};
Log3 ($name, 3, qq{$name - $state});
Log3 ($name, 3, qq{$name - GET "$location" to read the new values are set });
BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "GETTER:all" ], 1);
BlockingInformParent("FHEM::SMAPortal::setFromBlocking", [$name, "NULL", "SETTER:none"], 1);
}
else {
$state = qq{ERROR - couldn't set Consumer "$d" set to condition: switch on if GridConsumption=$op% (PV=$pvlog%)};
}
return $state;
}
################################################################ ################################################################
# Auswertung Daten aus Hilfsroutinen # Auswertung Daten aus Hilfsroutinen
################################################################ ################################################################
sub extractHelperData { sub extractHelperData {
my $hash = shift; my $paref = shift;
my $daref = shift; # Referenz zum Datenarray my $hash = $paref->{hash};
my $jdata = shift; # empfangene JSON-Daten my $daref = $paref->{daref}; # Referenz zum Datenarray
my $addon = shift; # ein optionales AddOn my $data_cont = $paref->{data_cont}; # Daten decoded Content
my $tag = shift; # Kennzeichen der abgerufenen Daten/ der Abrufroutine my $data = $paref->{data}; # empfangene Rohdaten
my $addon = $paref->{fnaddon}; # ein optionales AddOn
my $tag = $paref->{tag}; # Kennzeichen der abgerufenen Daten/ der Abrufroutine
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my $sd; my $sd;
Log3 ($name, 4, "$name - extracting Helper data "); Log3 ($name, 4, "$name - extracting Helper data ");
my $data = eval{decode_json($jdata)} or do { Log3 ($name, 2, "$name - ERROR - can't decode JSON Data"); my $decd = eval{decode_json($data_cont)} or do { Log3 ($name, 2, "$name - ERROR - can't decode JSON Data");
return; return;
}; };
if(ref $data eq "HASH") { if(ref $decd eq "HASH") {
while (my ($k,$v) = each %$data) { while (my ($k,$v) = each %$decd) {
push @$daref, "$tag:$v"; push @$daref, "$tag:$v";
} }
} }
@@ -5126,8 +5182,7 @@ return;
"LWP": 0, "LWP": 0,
"HTTP::Cookies": 0, "HTTP::Cookies": 0,
"MIME::Base64": 0, "MIME::Base64": 0,
"utf8": 0, "utf8": 0
"Color": 0
}, },
"recommends": { "recommends": {
"FHEM::Meta": 0 "FHEM::Meta": 0