mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-01-31 06:39:11 +00:00
76_SMAPortal: new attr balanceDay, balanceMonth, balanceYear for statistics dataprovider, new set getData command, update button in header of Portal Graphics, minor code changes according PBP
git-svn-id: https://svn.fhem.de/fhem/trunk@22573 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
aad2f6bf5b
commit
0e58c690b4
@ -1,5 +1,9 @@
|
||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||
# Do not insert empty lines here, update check depends on it.
|
||||
- feature: 76_SMAPortal: new attr balanceDay, balanceMonth, balanceYear for
|
||||
statistics dataprovider, new set getData command,
|
||||
update button in header of Portal Graphics, minor
|
||||
code changes according PBP
|
||||
- change: 10_WS980: change conversion ration of w/m2 to 0.0079
|
||||
.- bugfix: 98_DOIFtools: improve popup position (Forum #113404)
|
||||
- bugfix: 48_BlinkCamera: videoDelete on new API and first TFA pin verify
|
||||
|
@ -71,6 +71,7 @@ BEGIN {
|
||||
CommandDeleteAttr
|
||||
CommandDeleteReading
|
||||
CommandSet
|
||||
CommandGet
|
||||
defs
|
||||
delFromDevAttrList
|
||||
delFromAttrList
|
||||
@ -136,6 +137,8 @@ BEGIN {
|
||||
|
||||
# Versions History intern
|
||||
my %vNotesIntern = (
|
||||
"3.4.0" => "09.08.2020 attr balanceDay, balanceMonth, balanceYear for data provider balanceDayData, balanceMonthData, balanceYearData ".
|
||||
"set getData command, update button in header of PortalAsHtml, minor code changes according PBP",
|
||||
"3.3.4" => "12.07.2020 fix break in header if attribute hourCount was reduced ",
|
||||
"3.3.3" => "07.07.2020 change extractLiveData, minor fixes ",
|
||||
"3.3.2" => "05.07.2020 change timeout calc, new reading lastSuccessTime ",
|
||||
@ -228,6 +231,12 @@ my %statkeys = ( # Statistikdaten auszulesende Schlüs
|
||||
AutarkyRate => 1,
|
||||
);
|
||||
|
||||
my %hset = ( # Hash der Set-Funktion
|
||||
credentials => { fn => "_setCredentials" },
|
||||
getData => { fn => "_setGetData" },
|
||||
createPortalGraphic => { fn => "_setCreatePortalGraphic" },
|
||||
);
|
||||
|
||||
my %mandatory; # Arbeitskopie von %stpl -> abzurufenden Datenprovider Stammdaten nach Login
|
||||
my %subs; # Arbeitskopie von %stpl -> Festlegung abzurufenden Datenprovider
|
||||
my %stpl = ( # Ausgangstemplate Subfunktionen der Datenprovider
|
||||
@ -241,12 +250,12 @@ my %stpl = (
|
||||
consumerMonthData => { doit => 0, nohm => 1, level => 'L07', func => '_getConsumerMonthData' },
|
||||
consumerYearData => { doit => 0, nohm => 1, level => 'L08', func => '_getConsumerYearData' },
|
||||
plantLogbook => { doit => 0, nohm => 0, level => 'L09', func => '_getPlantLogbook' },
|
||||
balanceCurrentData => { doit => 0, nohm => 0, level => 'L10', func => '_getBalanceCurrentData' },
|
||||
balanceDayData => { doit => 0, nohm => 0, level => 'L11', func => '_getBalanceDayData' },
|
||||
balanceMonthData => { doit => 0, nohm => 0, level => 'L12', func => '_getBalanceMonthData' },
|
||||
balanceYearData => { doit => 0, nohm => 0, level => 'L13', func => '_getBalanceYearData' },
|
||||
balanceTotalData => { doit => 0, nohm => 0, level => 'L14', func => '_getBalanceTotalData' },
|
||||
);
|
||||
|
||||
# Tags der verfügbaren Datenquellen
|
||||
my @pd = qw( plantMasterData
|
||||
consumerMasterdata
|
||||
@ -286,7 +295,10 @@ sub Initialize {
|
||||
$hash->{SetFn} = \&Set;
|
||||
$hash->{GetFn} = \&Get;
|
||||
$hash->{DbLog_splitFn} = \&DbLog_split;
|
||||
$hash->{AttrList} = "cookieLocation ".
|
||||
$hash->{AttrList} = "balanceDay ".
|
||||
"balanceMonth ".
|
||||
"balanceYear ".
|
||||
"cookieLocation ".
|
||||
"disable:0,1 ".
|
||||
"interval ".
|
||||
"noHomeManager:1,0 ".
|
||||
@ -360,7 +372,7 @@ sub Set { ## no critic 'complexity'
|
||||
my $opt = $a[1];
|
||||
my $prop = $a[2];
|
||||
my $prop1 = $a[3];
|
||||
my ($setlist,$success);
|
||||
my $setlist;
|
||||
my $ad = "";
|
||||
|
||||
return if(IsDisabled($name));
|
||||
@ -374,7 +386,8 @@ sub Set { ## no critic 'complexity'
|
||||
# erweiterte Setlist wenn Credentials gesetzt
|
||||
$setlist = "Unknown argument $opt, choose one of ".
|
||||
"credentials ".
|
||||
"createPortalGraphic:Generation,Consumption,Generation_Consumption,Differential "
|
||||
"createPortalGraphic:Generation,Consumption,Generation_Consumption,Differential ".
|
||||
"getData:noArg "
|
||||
;
|
||||
if($hash->{HELPER}{PLANTOID} && $hash->{HELPER}{CONSUMER}) {
|
||||
my $lfd = 0;
|
||||
@ -392,19 +405,86 @@ sub Set { ## no critic 'complexity'
|
||||
}
|
||||
}
|
||||
|
||||
if ($opt eq "credentials") {
|
||||
return "Credentials are incomplete, use username password" if (!$prop || !$prop1);
|
||||
($success) = setcredentials($hash,$prop,$prop1);
|
||||
if ($opt && $ad && $opt =~ /$ad/x) {
|
||||
# Verbraucher schalten
|
||||
$hash->{HELPER}{GETTER} = "none";
|
||||
$hash->{HELPER}{SETTER} = "$opt:$prop";
|
||||
CallInfo($hash);
|
||||
|
||||
} else {
|
||||
my $params = {
|
||||
hash => $hash,
|
||||
name => $name,
|
||||
opt => $opt,
|
||||
prop => $prop,
|
||||
prop1 => $prop1,
|
||||
aref => \@a,
|
||||
};
|
||||
|
||||
no strict "refs"; ## no critic 'NoStrict'
|
||||
if($hset{$opt}) {
|
||||
my $ret = "";
|
||||
$ret = &{$hset{$opt}{fn}} ($params) if(defined &{$hset{$opt}{fn}});
|
||||
return $ret;
|
||||
}
|
||||
use strict "refs";
|
||||
|
||||
return "$setlist";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Setter credentials
|
||||
# credentials speichern
|
||||
################################################################
|
||||
sub _setCredentials { ## no critic "not used"
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $prop = $paref->{prop};
|
||||
my $prop1 = $paref->{prop1};
|
||||
|
||||
return qq{Credentials are incomplete, use "set $name credentials <username> <password>"} if (!$prop || !$prop1);
|
||||
my ($success) = setcredentials($hash,$prop,$prop1);
|
||||
|
||||
if($success) {
|
||||
delcookiefile ($hash);
|
||||
CallInfo($hash);
|
||||
return "Username and Password saved successfully";
|
||||
|
||||
} else {
|
||||
return "Error while saving Username / Password - see logfile for details";
|
||||
}
|
||||
|
||||
} elsif ($opt eq "createPortalGraphic") {
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Setter getData
|
||||
# identisch zu "get gata", Workaround um mit webCmd
|
||||
# arbeiten zu können
|
||||
################################################################
|
||||
sub _setGetData { ## no critic "not used"
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
|
||||
CommandGet(undef, "$name data");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Setter createPortalGraphic
|
||||
# create createPortalGraphic devices
|
||||
################################################################
|
||||
sub _setCreatePortalGraphic { ## no critic "not used"
|
||||
my $paref = shift;
|
||||
my $hash = $paref->{hash};
|
||||
my $name = $paref->{name};
|
||||
my $prop = $paref->{prop};
|
||||
|
||||
if (!$hash->{CREDENTIALS}) {return "Credentials of $name are not set - make sure you've set it with \"set $name credentials username password\"";}
|
||||
my ($htmldev,$ret,$c,$type,$color2);
|
||||
|
||||
@ -438,7 +518,7 @@ sub Set { ## no critic 'complexity'
|
||||
CommandAttr($hash->{CL},"$htmldev alias $c"); # Alias setzen
|
||||
|
||||
$c = qq{This device provides a praphical output of SMA Sunny Portal values.\n}.
|
||||
qq{It is important that a SMA Home Manager is installed. Otherwise no forecast data are privided by SMA!\n}.
|
||||
qq{It is important that a SMA Home Manager is installed. Otherwise no forecast data are provided by SMA!\n}.
|
||||
qq{The device "$name" needs to contain "forecastData" in attribute "providerLevel".\n}.
|
||||
qq{The attribute "providerLevel" must also contain "consumerCurrentdata" if you want switch your consumer connectet to the SMA Home Manager.};
|
||||
|
||||
@ -473,19 +553,7 @@ sub Set { ## no critic 'complexity'
|
||||
my $room = AttrVal($name,"room","SMAPortal");
|
||||
CommandAttr($hash->{CL},"$htmldev room $room");
|
||||
|
||||
return "SMA Portal Graphics device \"$htmldev\" created and assigned to room \"$room\".";
|
||||
|
||||
} elsif ($opt && $ad && $opt =~ /$ad/x) {
|
||||
# Verbraucher schalten
|
||||
$hash->{HELPER}{GETTER} = "none";
|
||||
$hash->{HELPER}{SETTER} = "$opt:$prop";
|
||||
CallInfo($hash);
|
||||
|
||||
} else {
|
||||
return "$setlist";
|
||||
}
|
||||
|
||||
return;
|
||||
return "SMA Portal Graphics device \"$htmldev\" created and assigned to room \"$room\".";
|
||||
}
|
||||
|
||||
###############################################################
|
||||
@ -532,37 +600,10 @@ return;
|
||||
###############################################################
|
||||
sub DbLog_split {
|
||||
my ($event, $device) = @_;
|
||||
my $devhash = $defs{$device};
|
||||
my ($reading, $value, $unit);
|
||||
|
||||
if($event =~ m/[_\-fd]Consumption|Quote/x) {
|
||||
$event =~ /^L(.*):\s(.*)\s(.*)/x;
|
||||
if($1) {
|
||||
$reading = "L".$1;
|
||||
$value = $2;
|
||||
$unit = $3;
|
||||
}
|
||||
}
|
||||
if($event =~ m/Power|PV|FeedIn|SelfSupply|Temperature|Total|Energy|Hour:|Hour(\d\d):/x) {
|
||||
$event =~ /^L(.*):\s(.*)\s(.*)/x;
|
||||
if($1) {
|
||||
$reading = "L".$1;
|
||||
$value = $2;
|
||||
$unit = $3;
|
||||
}
|
||||
}
|
||||
if($event =~ m/Next04Hours-IsConsumption|RestOfDay-IsConsumption|Tomorrow-IsConsumption|Battery/x) {
|
||||
$event =~ /^L(.*):\s(.*)\s(.*)/x;
|
||||
if($1) {
|
||||
$reading = "L".$1;
|
||||
$value = $2;
|
||||
$unit = $3;
|
||||
}
|
||||
}
|
||||
if($event =~ m/summary/x && $event =~ /(.*):\s(.*)\s(.*)/x) {
|
||||
$reading = $1;
|
||||
$value = $2;
|
||||
$unit = $3;
|
||||
if($event =~ /\s(Wh|W|kWh|%|h)$/xms) {
|
||||
($reading, $value, $unit) = $event =~ /(.*):\s(.*)\s(.*)/x;
|
||||
}
|
||||
|
||||
return ($reading, $value, $unit);
|
||||
@ -584,8 +625,7 @@ sub setcredentials {
|
||||
$len = scalar @key;
|
||||
$i = 0;
|
||||
$credstr = join "",
|
||||
map { $i = ($i + 1) % $len;
|
||||
chr((ord($_) + $key[$i]) % 256) } split //, $credstr;
|
||||
map { $i = ($i + 1) % $len; chr((ord($_) + $key[$i]) % 256) } split //, $credstr; ## no critic 'Map blocks';
|
||||
# End Scramble-Routine
|
||||
|
||||
$index = $hash->{TYPE}."_".$hash->{NAME}."_credentials";
|
||||
@ -635,9 +675,7 @@ sub getcredentials {
|
||||
$len = scalar @key;
|
||||
$i = 0;
|
||||
$credstr = join "",
|
||||
map { $i = ($i + 1) % $len;
|
||||
chr((ord($_) - $key[$i] + 256) % 256) }
|
||||
split //, $credstr;
|
||||
map { $i = ($i + 1) % $len; chr((ord($_) - $key[$i] + 256) % 256) } split //, $credstr; ## no critic 'Map blocks';
|
||||
# Ende Descramble-Routine
|
||||
|
||||
($username, $passwd) = split(":",decode_base64($credstr));
|
||||
@ -693,11 +731,9 @@ sub Attr {
|
||||
}
|
||||
|
||||
if ($cmd eq "set") {
|
||||
if ($aName =~ m/interval/x) {
|
||||
unless ($aVal =~ /^\d+$/x) {return " The Value for $aName is not valid. Use only figures 0-9 !";}
|
||||
}
|
||||
if($aName =~ m/interval/x) {
|
||||
return qq{The interval must be >= 120 seconds or 0 if you don't want use automatic updates} if($aVal > 0 && $aVal < 30);
|
||||
if ($aName eq "interval") {
|
||||
unless ($aVal =~ /^\d+$/x) {return "The value for $aName is not valid. Use only figures 0-9 !";}
|
||||
return qq{The interval must be >= 120 seconds or 0 if you don't want use automatic updates} if($aVal > 0 && $aVal < 120);
|
||||
InternalTimer(gettimeofday()+1.0, "FHEM::SMAPortal::CallInfo", $hash, 0);
|
||||
}
|
||||
}
|
||||
@ -713,7 +749,7 @@ return;
|
||||
# $nr = 1 wenn Retry Zähler nicht zurückgesetzt werden soll
|
||||
#
|
||||
################################################################
|
||||
sub CallInfo {
|
||||
sub CallInfo { ## no critic 'complexity'
|
||||
my ($hash,$nc,$nr) = @_;
|
||||
my $name = $hash->{NAME};
|
||||
my $new;
|
||||
@ -768,6 +804,7 @@ sub CallInfo {
|
||||
Log3 ($name, 3, "$name - ################################################################");
|
||||
Log3 ($name, 3, "$name - ### start new set/get data from SMA Sunny Portal ###");
|
||||
Log3 ($name, 3, "$name - ################################################################");
|
||||
Log3 ($name, 5, "$name - SMAPortal version: $hash->{HELPER}{VERSION}");
|
||||
Log3 ($name, 4, "$name - calculated maximum cycles: $maxcycles");
|
||||
Log3 ($name, 4, "$name - calculated timeout: $timeout");
|
||||
}
|
||||
@ -1434,43 +1471,6 @@ sub _getForecastData { ## no critic "not used"
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Abruf Statistik Daten Day
|
||||
# (anchorTime beachten !)
|
||||
################################################################
|
||||
sub _getBalanceCurrentData { ## no critic "not used"
|
||||
my $paref = shift;
|
||||
my $name = $paref->{name};
|
||||
my $ua = $paref->{ua}; # LWP Useragent
|
||||
my $state = $paref->{state};
|
||||
my $daref = $paref->{daref}; # Referenz zum Datenarray
|
||||
|
||||
my ($reread,$retry,$errstate) = (0,0,0);
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
my $cts = fhemTimeLocal(0, 0, 0, $mday, $mon, $year);
|
||||
my $offset = fhemTzOffset($cts);
|
||||
my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum
|
||||
|
||||
my $tab = 0; # Tab 0 -> Current, Tab 1 -> Tag , 2->Monat, 3->Jahr, 4->Gesamt
|
||||
my %fields = ("Content-Type" => "application/json; charset=utf-8");
|
||||
my $cont = qq{{"tabNumber":$tab,"anchorTime":$anchort}};
|
||||
|
||||
($errstate,$state) = __dispatchPost ({ name => $name,
|
||||
ua => $ua,
|
||||
call => 'https://www.sunnyportal.com/FixedPages/HoManEnergyRedesign.aspx/GetLegendWithValues',
|
||||
tag => "balanceCurrentData",
|
||||
state => $state,
|
||||
fnaref => [ qw( extractStatisticData ) ],
|
||||
fields => \%fields,
|
||||
content => $cont,
|
||||
addon => "Current",
|
||||
daref => $daref
|
||||
});
|
||||
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
}
|
||||
|
||||
################################################################
|
||||
# Abruf Statistik Daten Day
|
||||
# (anchorTime beachten !)
|
||||
@ -1484,8 +1484,35 @@ sub _getBalanceDayData { ## no critic "not used"
|
||||
|
||||
my ($reread,$retry,$errstate) = (0,0,0);
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
my $cts = fhemTimeLocal(0, 0, 0, $mday, $mon, $year);
|
||||
my @bd = split /\s+/x ,AttrVal($name, "balanceDay", "current");
|
||||
|
||||
for my $bal (@bd) {
|
||||
my ($y,$m,$d);
|
||||
my $addon = "Day";
|
||||
$addon .= "_".$bal;
|
||||
|
||||
if($bal ne "current") {
|
||||
($y,$m,$d) = $bal =~ /(\d{4})-(\d{2})-(\d{2})/x;
|
||||
|
||||
if(!$y || !$m || !$d) {
|
||||
Log3 ($name, 2, qq{$name - The attribute "balanceDay" value "$bal" is ignored. A valid date with form "YYYY-MM-DD" is needed});
|
||||
next;
|
||||
}
|
||||
|
||||
$y -= 1900;
|
||||
$m -= 1;
|
||||
|
||||
} else {
|
||||
(undef,undef,undef,$d,$m,$y) = localtime(time);
|
||||
}
|
||||
|
||||
eval { timelocal(0, 0, 0, $d, $m, $y) } or do { $state = (split(" at", $@))[0];
|
||||
$errstate = 1;
|
||||
Log3($name, 2, "$name - ERROR - invalid date/time format in attribute 'balanceDay' detected: $state");
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
};
|
||||
|
||||
my $cts = fhemTimeLocal(0, 0, 0, $d, $m, $y);
|
||||
my $offset = fhemTzOffset($cts);
|
||||
my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum
|
||||
|
||||
@ -1501,10 +1528,12 @@ sub _getBalanceDayData { ## no critic "not used"
|
||||
fnaref => [ qw( extractStatisticData ) ],
|
||||
fields => \%fields,
|
||||
content => $cont,
|
||||
addon => "Day",
|
||||
addon => $addon,
|
||||
daref => $daref
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
}
|
||||
|
||||
@ -1521,8 +1550,36 @@ sub _getBalanceMonthData { ## no critic "not used"
|
||||
|
||||
my ($reread,$retry,$errstate) = (0,0,0);
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
my $cts = fhemTimeLocal(0, 0, 0, $mday, $mon, $year);
|
||||
my @bd = split /\s+/x ,AttrVal($name, "balanceMonth", "current");
|
||||
|
||||
for my $bal (@bd) {
|
||||
my ($y,$m);
|
||||
my $addon = "Month";
|
||||
$addon .= "_".$bal;
|
||||
|
||||
if($bal ne "current") {
|
||||
($y,$m) = $bal =~ /^(\d{4})-(\d{2})$/x;
|
||||
|
||||
if(!$y || !$m) {
|
||||
Log3 ($name, 2, qq{$name - The attribute "balanceMonth" value "$bal" is ignored. A valid date with form "YYYY-MM" is needed});
|
||||
next;
|
||||
}
|
||||
|
||||
$y -= 1900;
|
||||
$m -= 1;
|
||||
|
||||
} else {
|
||||
$m = (localtime(time))[4];
|
||||
$y = (localtime(time))[5];
|
||||
}
|
||||
|
||||
eval { timelocal(0, 0, 0, 1, $m, $y) } or do { $state = (split(" at", $@))[0];
|
||||
$errstate = 1;
|
||||
Log3($name, 2, "$name - ERROR - invalid date/time format in attribute 'balanceMonth' detected: $state");
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
};
|
||||
|
||||
my $cts = fhemTimeLocal(0, 0, 0, 1, $m, $y);
|
||||
my $offset = fhemTzOffset($cts);
|
||||
my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum
|
||||
|
||||
@ -1538,10 +1595,12 @@ sub _getBalanceMonthData { ## no critic "not used"
|
||||
fnaref => [ qw( extractStatisticData ) ],
|
||||
fields => \%fields,
|
||||
content => $cont,
|
||||
addon => "Month",
|
||||
addon => $addon,
|
||||
daref => $daref
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
}
|
||||
|
||||
@ -1558,8 +1617,33 @@ sub _getBalanceYearData { ## no critic "not used"
|
||||
|
||||
my ($reread,$retry,$errstate) = (0,0,0);
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
|
||||
my $cts = fhemTimeLocal(0, 0, 0, $mday, $mon, $year);
|
||||
my @bd = split /\s+/x ,AttrVal($name, "balanceYear", "current");
|
||||
|
||||
for my $bal (@bd) {
|
||||
my $y;
|
||||
my $addon = "Year";
|
||||
$addon .= "_".$bal;
|
||||
|
||||
if($bal ne "current") {
|
||||
($y) = $bal =~ /^(\d{4})$/x;
|
||||
|
||||
if(!$y) {
|
||||
Log3 ($name, 2, qq{$name - The attribute "balanceYear" value "$bal" is ignored. A valid date with form "YYYY" is needed});
|
||||
next;
|
||||
}
|
||||
|
||||
$y -= 1900;
|
||||
} else {
|
||||
$y = (localtime(time))[5];
|
||||
}
|
||||
|
||||
eval { timelocal(0, 0, 0, 1, 1, $y) } or do { $state = (split(" at", $@))[0];
|
||||
$errstate = 1;
|
||||
Log3($name, 2, "$name - ERROR - invalid date/time format in attribute 'balanceYear' detected: $state");
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
};
|
||||
|
||||
my $cts = fhemTimeLocal(0, 0, 0, 1, 1, $y);
|
||||
my $offset = fhemTzOffset($cts);
|
||||
my $anchort = int($cts + $offset); # anchorTime in UTC -> abzurufendes Datum
|
||||
|
||||
@ -1575,9 +1659,10 @@ sub _getBalanceYearData { ## no critic "not used"
|
||||
fnaref => [ qw( extractStatisticData ) ],
|
||||
fields => \%fields,
|
||||
content => $cont,
|
||||
addon => "Year",
|
||||
addon => $addon,
|
||||
daref => $daref
|
||||
});
|
||||
}
|
||||
|
||||
return ($errstate,$state,$reread,$retry);
|
||||
}
|
||||
@ -1858,6 +1943,13 @@ sub ___analyzeData { ## no critic 'complexity'
|
||||
|
||||
$data = eval{decode_json($ad_content)} or do { $data = $ad_content };
|
||||
|
||||
my $jsonerror = $ad->header('Jsonerror') // ""; # Portal meldet keine Verarbeitung des Reaquests möglich (z.B. Jahr 0000 zur Auswertung angefordert)
|
||||
if($jsonerror) {
|
||||
$errstate = 1;
|
||||
$state = "SMA Portal failure: "."Message -> ".$data->{Message}.",\nStackTrace -> ".$data->{StackTrace}.",\nExceptionType -> ".$data->{ExceptionType};
|
||||
return ($reread,$retry,$errstate,$state);
|
||||
}
|
||||
|
||||
if(ref $data eq "HASH") {
|
||||
for my $k (keys %{$data}) {
|
||||
my $val = $data->{$k};
|
||||
@ -1995,12 +2087,6 @@ sub ParseData { ## no critic
|
||||
my $gc = ReadingsNum($name, "${ldlv}_GridConsumption", 0);
|
||||
my $sum = $fi-$gc;
|
||||
|
||||
# if(!$errstate && $lddo && !$pv && !$fi && !$gc) {
|
||||
# keine Anlagendaten vorhanden
|
||||
# $state = "Data can't be retrieved from SMA-Portal. Reread at next scheduled cycle.";
|
||||
# Log3 ($name, 2, "$name - $state");
|
||||
# }
|
||||
|
||||
my $ts = strftime('%Y-%m-%d %H:%M:%S', localtime);
|
||||
if(AttrVal("global", "language", "EN") eq "DE") {
|
||||
$ts = strftime('%d.%m.%Y %H:%M:%S', localtime);
|
||||
@ -2345,7 +2431,10 @@ return;
|
||||
|
||||
################################################################
|
||||
# Auswertung Statistic Daten
|
||||
# $period = Current | Day | Month | Year
|
||||
# $period = Day[_<date>] |
|
||||
# Month[_<date>] |
|
||||
# Year[_<date>] |
|
||||
# Total
|
||||
################################################################
|
||||
sub extractStatisticData {
|
||||
my $hash = shift;
|
||||
@ -3125,7 +3214,7 @@ sub PortalAsHtml {
|
||||
|
||||
# Headerzeile generieren
|
||||
if ($header) {
|
||||
my $lang = AttrVal("global","language","EN");
|
||||
my $lang = AttrVal("global", "language", "EN");
|
||||
my $alias = AttrVal($name, "alias", "SMA Sunny Portal"); # Linktext als Aliasname oder "SMA Sunny Portal"
|
||||
my $dlink = "<a href=\"/fhem?detail=$name\">$alias</a>";
|
||||
my $lup = ReadingsTimestamp($name, "${fmin}_ForecastToday_Consumption", "0000-00-00 00:00:00"); # letzter Forecast Update
|
||||
@ -3146,11 +3235,34 @@ sub PortalAsHtml {
|
||||
|
||||
$header = "<table align=\"$hdrAlign\">";
|
||||
|
||||
# Header Link + Status
|
||||
# Header Link + Status + Update Button
|
||||
if($hdrDetail eq "all" || $hdrDetail eq "statusLink") {
|
||||
my ($year, $month, $day, $hour, $min, $sec) = $lup =~ /(\d+)-(\d\d)-(\d\d)\s+(.*)/x;
|
||||
$lup = "$3.$2.$1 $4";
|
||||
$header .= "<tr><td colspan=\"3\" align=\"left\"><b>".$dlink."</b></td><td colspan=\"4\" align=\"right\">(".$lupt." ".$lup.")</td></tr>";
|
||||
my ($year, $month, $day, $time) = $lup =~ /(\d{4})-(\d{2})-(\d{2})\s+(.*)/x;
|
||||
|
||||
if(AttrVal("global","language","EN") eq "DE") {
|
||||
$lup = "$day.$month.$year $time";
|
||||
} else {
|
||||
$lup = "$year-$month-$day $time";
|
||||
}
|
||||
|
||||
my $cmdupdate = "\"FW_cmd('$FW_ME$FW_subdir?XHR=1&cmd=set $name getData')\""; # Update Button generieren
|
||||
|
||||
if ($ftui && $ftui eq "ftui") {
|
||||
$cmdupdate = "\"ftui.setFhemStatus('set $name getData')\"";
|
||||
}
|
||||
|
||||
my $upstate = ReadingsVal($name,"state", "undef");
|
||||
my $upicon = "<img src=\"$FW_ME/www/images/default/1px-spacer.png\">";
|
||||
|
||||
if ($upstate =~ /ok/ix) {
|
||||
$upicon = "<a onClick=$cmdupdate><img src=\"$FW_ME/www/images/default/10px-kreis-gruen.png\"></a>";
|
||||
} elsif ($upstate =~ /running/ix) {
|
||||
$upicon = "<img src=\"$FW_ME/www/images/default/10px-kreis-gelb.png\"></a>";
|
||||
} else {
|
||||
$upicon = "<a onClick=$cmdupdate><img src=\"$FW_ME/www/images/default/10px-kreis-rot.png\"></a>";
|
||||
}
|
||||
|
||||
$header .= "<tr><td colspan=\"3\" align=\"left\"><b>".$dlink."</b></td><td colspan=\"3\" align=\"right\">(".$lupt." ".$lup.") ".$upicon."</td></tr>";
|
||||
}
|
||||
|
||||
# Header Information pv
|
||||
@ -3746,15 +3858,15 @@ sub SPGRefresh {
|
||||
my @rooms = split(",",$hash->{HELPER}{SPGROOM});
|
||||
for (@rooms) {
|
||||
my $room = $_;
|
||||
{ map { FW_directNotify("FILTER=room=$room", "#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") }
|
||||
{ map { FW_directNotify("FILTER=room=$room", "#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context';
|
||||
}
|
||||
} elsif ($pload && (!$hash->{HELPER}{SPGROOM} || $hash->{HELPER}{SPGDETAIL})) {
|
||||
# trifft zu bei Detailansicht oder im FLOORPLAN bzw. Dashboard oder wenn Seitenrefresh mit dem
|
||||
# SMAPortalSPG-Attribut "forcePageRefresh" erzwungen wird
|
||||
{ map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") }
|
||||
{ map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context';
|
||||
} else {
|
||||
if($fpr) {
|
||||
{ map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") }
|
||||
{ map { FW_directNotify("#FHEMWEB:$_", "location.reload('true')", "") } devspec2array("TYPE=FHEMWEB") } ## no critic 'void context';
|
||||
}
|
||||
}
|
||||
|
||||
@ -3865,7 +3977,7 @@ return;
|
||||
<br>
|
||||
<ul>
|
||||
<a name="createPortalGraphic"></a>
|
||||
<li><b> set <name> createPortalGraphic <Generation | Consumption | Generation_Consumption | Differential> </b> <br>
|
||||
<li><b> createPortalGraphic <Generation | Consumption | Generation_Consumption | Differential> </b> <br>
|
||||
Creates graphical devices to show the SMA Sunny Portal forecast data in several layouts.
|
||||
The attribute "providerLevel" must contain "forecastData". <br>
|
||||
With the <a href="#SMAPortalSPGattr">"attributes of the graphic device"</a> the appearance and coloration of the forecast
|
||||
@ -3875,18 +3987,26 @@ return;
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<li><b> set <name> credentials <username> <password> </b> </li>
|
||||
<li><b> credentials <username> <password> </b> </li>
|
||||
Set Username / Password used for the login into the SMA Sunny Portal.
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<a name="consumer"></a>
|
||||
<li><b> set <name> <consumer name> <on | off | auto> </b> <br>
|
||||
<li><b> <consumer name> <on | off | auto> </b> <br>
|
||||
Once consumer data are available, the consumer are shown in the Set and can be switched to on, off or the automatic mode (auto)
|
||||
that means the consumer are controlled by the Sunny Home Manager.
|
||||
</li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<a name="getData"></a>
|
||||
<li><b> getData </b> <br>
|
||||
Identical to the "get data" command. Simplifies the use of the attribute "webCmd" in the FHEMWEB.
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<br><br>
|
||||
@ -3898,7 +4018,7 @@ return;
|
||||
|
||||
<ul>
|
||||
<a name="data"></a>
|
||||
<li><b> get <name> data </b> <br>
|
||||
<li><b> data </b> <br>
|
||||
This command fetch the data from the SMA Sunny Portal manually.
|
||||
</ul>
|
||||
</li>
|
||||
@ -3906,7 +4026,7 @@ return;
|
||||
|
||||
<ul>
|
||||
<a name="storedCredentials"></a>
|
||||
<li><b> get <name> storedCredentials </b> <br>
|
||||
<li><b> storedCredentials </b> <br>
|
||||
The saved credentials are displayed in a popup window.
|
||||
</ul>
|
||||
</li>
|
||||
@ -3918,6 +4038,43 @@ return;
|
||||
<ul>
|
||||
<br>
|
||||
<ul>
|
||||
|
||||
<a name="balanceDay"></a>
|
||||
<li><b>balanceDay <YYYY-MM-DD> [current <YYYY-MM-DD> <YYYY-MM-DD> ...] </b><br>
|
||||
Defines the days from which the data provider "balanceDayData" delivers the data. The day specifications are separated by
|
||||
spaces, current = current day. <br>
|
||||
(default: current day) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Example:</b><br>
|
||||
attr <name> balanceDay current 2020-08-07 2020-08-06 2020-08-05 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="balanceMonth"></a>
|
||||
<li><b>balanceMonth <YYYY-MM> [current <YYYY-MM> <YYYY-MM> ...] </b><br>
|
||||
Defines from which months the data provider "balanceMonthData" delivers the data. The month specifications are separated by
|
||||
spaces, current = current month. <br>
|
||||
(default: current month) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Example:</b><br>
|
||||
attr <name> balanceMonth current 2019-07 2019-06 2019-05 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="balanceYear"></a>
|
||||
<li><b>balanceYear <YYYY> [current <YYYY> <YYYY> <YYYY> ...] </b><br>
|
||||
Defines the years from which the data provider "balanceYearData" delivers the data. The year specifications are separated by
|
||||
spaces, current = current year. <br>
|
||||
(default: current year) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Example:</b><br>
|
||||
attr <name> balanceYear current 2019 2018 2017 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="cookieLocation"></a>
|
||||
<li><b>cookieLocation <Pfad/File> </b><br>
|
||||
The path and filename of received Cookies. <br>
|
||||
@ -3990,9 +4147,9 @@ return;
|
||||
<tr><td> <b>consumerMonthData</b> </td><td>- consumer data month are generated </td></tr>
|
||||
<tr><td> <b>consumerYearData</b> </td><td>- consumer data year are generated </td></tr>
|
||||
<tr><td> <b>plantLogbook</b> </td><td>- the maximum of 25 most recent entries of the plant logbook are retrieved </td></tr>
|
||||
<tr><td> <b>balanceDayData</b> </td><td>- Statistics data of the day are retrieved </td></tr>
|
||||
<tr><td> <b>balanceMonthData</b> </td><td>- Statistics data of the month are retrieved </td></tr>
|
||||
<tr><td> <b>balanceYearData</b> </td><td>- Statistical data of the year are retrieved </td></tr>
|
||||
<tr><td> <b>balanceDayData</b> </td><td>- Statistics data of the day are retrieved (see attribute <a href="#balanceDay">balanceDay</a>) </td></tr>
|
||||
<tr><td> <b>balanceMonthData</b> </td><td>- Statistics data of the month are retrieved (see attribute <a href="#balanceMonth">balanceMonth</a>) </td></tr>
|
||||
<tr><td> <b>balanceYearData</b> </td><td>- Statistical data of the year are retrieved (see attribute <a href="#balanceYear">balanceYear</a>) </td></tr>
|
||||
<tr><td> <b>balanceTotalData</b> </td><td>- Total statistics data are retrieved </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
@ -4113,7 +4270,7 @@ return;
|
||||
<br>
|
||||
<ul>
|
||||
<a name="createPortalGraphic"></a>
|
||||
<li><b> set <name> createPortalGraphic <Generation | Consumption | Generation_Consumption | Differential> </b> <br>
|
||||
<li><b> createPortalGraphic <Generation | Consumption | Generation_Consumption | Differential> </b> <br>
|
||||
Erstellt Devices zur grafischen Anzeige der SMA Sunny Portal Prognosedaten in verschiedenen Layouts.
|
||||
Das Attribut "providerLevel" muss auf den Level "forecastData" enthalten. <br>
|
||||
Mit den <a href="#SMAPortalSPGattr">"Attributen des Grafikdevices"</a> können Erscheinungsbild und
|
||||
@ -4124,15 +4281,23 @@ return;
|
||||
|
||||
<ul>
|
||||
<a name="credentials"></a>
|
||||
<li><b> set <name> credentials <username> <password> </b> <br>
|
||||
<li><b> credentials <username> <password> </b> <br>
|
||||
Setzt Username / Passwort zum Login in das SMA Sunny Portal.
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<a name="getData"></a>
|
||||
<li><b> getData </b> <br>
|
||||
Identisch zum "get data" Befehl. Vereinfacht die Benutzung des Attributs "webCmd" im FHEMWEB.
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<a name="Verbrauchername"></a>
|
||||
<li><b> set <name> <Verbrauchername> <on | off | auto> </b> <br>
|
||||
<li><b> <Verbrauchername> <on | off | auto> </b> <br>
|
||||
Es werden die an den SMA Sunny Homemanager angeschlossene Verbraucher (Bluetooth Steckdosen) angeboten sobald sie vom
|
||||
Modul erkannt wurden.
|
||||
Sobald diese Daten vorliegen, werden die vorhandenen Verbraucher im Set angezeigt und können eingeschaltet, ausgeschaltet
|
||||
@ -4150,7 +4315,7 @@ return;
|
||||
<ul>
|
||||
|
||||
<a name="data"></a>
|
||||
<li><b> get <name> data </b> <br>
|
||||
<li><b> data </b> <br>
|
||||
Mit diesem Befehl werden die Daten aus dem SMA Sunny Portal manuell abgerufen.
|
||||
</ul>
|
||||
</li>
|
||||
@ -4158,7 +4323,7 @@ return;
|
||||
|
||||
<ul>
|
||||
<a name="storedCredentials"></a>
|
||||
<li><b> get <name> storedCredentials </b> <br>
|
||||
<li><b> storedCredentials </b> <br>
|
||||
Die gespeicherten Anmeldeinformationen (Credentials) werden in einem Popup als Klartext angezeigt.
|
||||
</ul>
|
||||
</li>
|
||||
@ -4171,6 +4336,43 @@ return;
|
||||
<ul>
|
||||
<br>
|
||||
<ul>
|
||||
|
||||
<a name="balanceDay"></a>
|
||||
<li><b>balanceDay <YYYY-MM-DD> [current <YYYY-MM-DD> <YYYY-MM-DD> ...] </b><br>
|
||||
Legt fest, von welchen Tagen der Datenprovider "balanceDayData" die Daten liefert. Die Tagesangaben werden durch Leerzeichen
|
||||
getrennt, current = aktueller Tag. <br>
|
||||
(default: aktueller Tag) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Beispiel:</b><br>
|
||||
attr <name> balanceDay current 2020-08-07 2020-08-06 2020-08-05 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="balanceMonth"></a>
|
||||
<li><b>balanceMonth <YYYY-MM> [current <YYYY-MM> <YYYY-MM> ...] </b><br>
|
||||
Legt fest, von welchen Monaten der Datenprovider "balanceMonthData" die Daten liefert. Die Monatsangaben werden durch Leerzeichen
|
||||
getrennt, current = aktueller Monat. <br>
|
||||
(default: aktueller Monat) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Beispiel:</b><br>
|
||||
attr <name> balanceMonth current 2019-07 2019-06 2019-05 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="balanceYear"></a>
|
||||
<li><b>balanceYear <YYYY> [current <YYYY> <YYYY> <YYYY> ...] </b><br>
|
||||
Legt fest, von welchen Jahren der Datenprovider "balanceYearData" die Daten liefert. Die Jahresangaben werden durch Leerzeichen
|
||||
getrennt, current = aktuelles Jahr. <br>
|
||||
(default: aktuelles Jahr) <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Beispiel:</b><br>
|
||||
attr <name> balanceYear current 2019 2018 2017 <br>
|
||||
</ul>
|
||||
</li><br>
|
||||
|
||||
<a name="cookieLocation"></a>
|
||||
<li><b>cookieLocation <Pfad/File> </b><br>
|
||||
Angabe von Pfad und Datei zur Abspeicherung des empfangenen Cookies. <br>
|
||||
@ -4244,9 +4446,9 @@ return;
|
||||
<tr><td> <b>consumerMonthData</b> </td><td>- Verbraucherdaten Monat werden erzeugt </td></tr>
|
||||
<tr><td> <b>consumerYearData</b> </td><td>- Verbraucherdaten Jahr werden erzeugt </td></tr>
|
||||
<tr><td> <b>plantLogbook</b> </td><td>- die maximal 25 aktuellsten Einträge des Anlagenlogbuchs werden abgerufen </td></tr>
|
||||
<tr><td> <b>balanceDayData</b> </td><td>- Statistikdaten des Tages werden abgerufen </td></tr>
|
||||
<tr><td> <b>balanceMonthData</b> </td><td>- Statistikdaten des Monats werden abgerufen </td></tr>
|
||||
<tr><td> <b>balanceYearData</b> </td><td>- Statistikdaten des Jahres werden abgerufen </td></tr>
|
||||
<tr><td> <b>balanceDayData</b> </td><td>- Statistikdaten des Tages werden abgerufen (siehe Attribut <a href="#balanceDay">balanceDay</a>) </td></tr>
|
||||
<tr><td> <b>balanceMonthData</b> </td><td>- Statistikdaten des Monats werden abgerufen (siehe Attribut <a href="#balanceMonth">balanceMonth</a>) </td></tr>
|
||||
<tr><td> <b>balanceYearData</b> </td><td>- Statistikdaten des Jahres werden abgerufen (siehe Attribut <a href="#balanceYear">balanceYear</a>) </td></tr>
|
||||
<tr><td> <b>balanceTotalData</b> </td><td>- Statistikdaten Gesamt werden abgerufen </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user