mirror of
https://github.com/fhem/fhem-mirror.git
synced 2024-11-22 09:49:50 +00:00
1fd81325bc
git-svn-id: https://svn.fhem.de/fhem/trunk@28920 2b470e98-0d58-463d-a4d8-8e2adae1ed80
926 lines
36 KiB
Perl
Executable File
926 lines
36 KiB
Perl
Executable File
# $Id$
|
|
#
|
|
##############################################
|
|
#
|
|
# 2024.05.27 - fichtennadel v0.1
|
|
# - INFO: check in to svn trunk/fhem/contrib/fichtennadel
|
|
# - renamed file to lower case fronius to match device type (fhem standard)
|
|
# - no functional changes
|
|
# - removed links to outdated docs
|
|
# - extended copyright
|
|
#
|
|
# 2024.04.24 - fichtennadel v0.0.11d
|
|
# - CHANGE: for inverters in standby during fhem start:
|
|
# re-init fronius_GetAPIVersionInfo, if FroniusBaseURL is not set
|
|
# 2024.01.10 - fichtennadel v0.0.11c
|
|
# - CHANGE: for inverters in standby during fhem start:
|
|
# re-init fronius_GetAPIVersionInfo, if FroniusBaseURL is not set
|
|
# fronius_Get*Data: always create timer , even if $hash->{helper}{VARS}... is not set
|
|
#
|
|
# 2023.10.01 - fichtennadel v0.0.10
|
|
# - CHANGE: GetArchiveData API parameter StartDate+EndDate in UTC
|
|
# - CHANGE: internal: perl use strict, NOTIFY nur von global
|
|
#
|
|
# 2023.09.30 - fichtennadel v0.0.9
|
|
# - CHANGE: kask 2023.09.23 - https://forum.fhem.de/index.php?topic=113850.msg1287616#msg1287616
|
|
# - Add: Modul kann mit IntervalRealtimeData <= 0 mit dem command "GetAllData"(und einzel) zum Daten abholen gezwungen werden.
|
|
# Die Reihenfolge der einzelnen Datensätze kann Frei gewählt werden.
|
|
# Es erfolgt bei IntervalRealtimeData <= 0 keine automatische Datenabfrage mehr!
|
|
# - CHANGE: spezifische, parametrisierbare Intervalle je Datenset
|
|
# IntervalPowerFlowRealtimeData, IntervalArchiveData, IntervalStorageRealtimeData, IntervalMeterRealtimeData, IntervalInverterRealtimeData
|
|
# - CHANGE: GetArchiveData:
|
|
# - eigenständig, für IntervalArchiveData = 300 an fixen 5 Minuten-Intervallen ausgerichtet (minimales Datenintervall vom Fronius ist 5min)
|
|
# - zusätzlich Verbrauchswerte für konsistente Berechnungen (Realtime Inverter + Meter Daten sind getrennt)
|
|
# EnergyReal_WAC_Sum_Produced, EnergyReal_WAC_Minus_Absolute, EnergyReal_WAC_Plus_Absolute, PowerReal_PAC_Sum
|
|
# - Sekunden fix :00 (sonst leere Response von Fronius)
|
|
# - BUG: Sommer/Winterzeit (https://forum.fhem.de/index.php?topic=113850.msg1277280#msg1277280)
|
|
# - BUG: Timer erst nach init_done setzen (https://forum.fhem.de/index.php?topic=113850.msg1285030#msg1285030)
|
|
#
|
|
#
|
|
#
|
|
##############################################
|
|
# Copyright by Michael Winkler v0.0.1 - v0.0.8
|
|
# e-mail: michael.winkler at online.de
|
|
#
|
|
#
|
|
# 2022.11.14 v0.0.8
|
|
# - BUG: Sommer/Winterzeit
|
|
#
|
|
# 2022.07.13 v0.0.7
|
|
# - BUG: Doppelte Verwendung des Moduls z.B. 2x Fronius Wechselrichter
|
|
# - CHANGE: Keepalive = 0
|
|
# - FEATURE: MPPT1 & MPPT2 aus den Archivdaten
|
|
#
|
|
# 2021.10.20 v0.0.6
|
|
# - BUG: https://forum.fhem.de/index.php/topic,113850.msg1180843.html#msg1180843 (Danke carlos)
|
|
#
|
|
# 2021.10.19 v0.0.5
|
|
# - BUG: https://forum.fhem.de/index.php/topic,113850.msg1156141.html#msg1156141 (Danke carlos)
|
|
#
|
|
# 2021.04.13 v0.0.4
|
|
# - CHANGE: Meldung [name] [fronius_setState] to connected entfernt
|
|
#
|
|
# 2020.08.28 v0.0.3
|
|
# - BUG: Write Boolean Data from JSON
|
|
# - CHANGE: Logging
|
|
#
|
|
# 2020.08.28 v0.0.2
|
|
# - CHANGE: Anpassungen Dokumentation
|
|
# Query API Version & Base URL
|
|
# Codebereinigung
|
|
#
|
|
# 2020.08.26 v0.0.1
|
|
# - CHANGE: erste Version
|
|
# - FEATURE: erste Version
|
|
# - BUG: erste Version
|
|
#
|
|
#
|
|
##############################################
|
|
#
|
|
# This file is part of fhem.
|
|
#
|
|
# Fhem is free software: you can redistribute it andor modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Fhem is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with fhem. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# https://forum.fhem.de/index.php?topic=138356.0
|
|
#
|
|
##############################################################################
|
|
|
|
package main;
|
|
|
|
use strict;
|
|
use Time::Local;
|
|
use Encode;
|
|
use Encode qw/from_to/;
|
|
use URI::Escape;
|
|
use Data::Dumper;
|
|
use JSON;
|
|
use utf8;
|
|
use Date::Parse;
|
|
use Time::Piece;
|
|
use lib ('./FHEM/lib', './lib');
|
|
|
|
my $ModulVersion = "0.1";
|
|
|
|
##############################################################################
|
|
sub fronius_Initialize($) {
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
$hash->{DefFn} = "fronius_Define";
|
|
$hash->{UndefFn} = "fronius_Undefine";
|
|
$hash->{NOTIFYDEV} = "global";
|
|
$hash->{NotifyFn} = "fronius_Notify";
|
|
#$hash->{GetFn} = "fronius_Get";
|
|
$hash->{SetFn} = "fronius_Set";
|
|
$hash->{AttrFn} = "fronius_Attr";
|
|
$hash->{AttrList} = "disable:0,1 ".
|
|
"DeviceId ".
|
|
"IntervalRealtimeData ".
|
|
"IntervalPowerFlowRealtimeData ".
|
|
"IntervalArchiveData ".
|
|
"IntervalStorageRealtimeData ".
|
|
"IntervalMeterRealtimeData ".
|
|
"IntervalInverterRealtimeData ".
|
|
"SaveDataHead:0,1 ".
|
|
$readingFnAttributes;
|
|
}
|
|
|
|
sub fronius_Define($$$) {
|
|
my ($hash, $def) = @_;
|
|
my @a = split("[ \t][ \t]*", $def);
|
|
|
|
return "syntax: define <name> Fronius <IP>" if(int(@a) != 3 );
|
|
my $name = $hash->{NAME};
|
|
|
|
# Fronius Smart Meter
|
|
$hash->{helper}{VARS}{FroniusIP} = $a[2];
|
|
|
|
# nur notifies für global
|
|
$hash->{NOTIFYDEV} = "global";
|
|
|
|
# Internaltimer löschen
|
|
RemoveInternalTimer($hash);
|
|
|
|
# Module zurücksetzen
|
|
$hash->{helper}{VARS}{FroniusBaseURL} = "nA";
|
|
$hash->{helper}{VARS}{Smart_Meter} = "nA";
|
|
$hash->{helper}{VARS}{Smart_Inverter} = "nA";
|
|
$hash->{helper}{VARS}{Smart_Storage} = "nA";
|
|
$hash->{helper}{VARS}{Smart_OhmPilot} = "nA";
|
|
$hash->{helper}{VARS}{Smart_SensorCard} = "nA";
|
|
$hash->{helper}{VARS}{Smart_StringControl} = "nA";
|
|
|
|
# for WR in StandBy
|
|
$hash->{helper}{VARS}{ReInitGetAPIVersionInfo} = 0;
|
|
|
|
if ($init_done) {
|
|
fronius_StartUp($hash);
|
|
}
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub fronius_Undefine($$) {
|
|
my ( $hash, $arg ) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
Log3 $name, 3, "Fronius $name [fronius_Undefine] called function";
|
|
|
|
# Stop the internal GetStatus-Loop and exit
|
|
RemoveInternalTimer($hash);
|
|
|
|
return;
|
|
}
|
|
|
|
sub fronius_StartUp($) {
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = List::Util::max(AttrVal( $name, "IntervalArchiveData", AttrVal( $name, "IntervalRealtimeData", 300 ) ), 300);
|
|
|
|
Log3 $name, 4, "[$name] [fronius_StartUp]";
|
|
|
|
# Datenbereinigung
|
|
fronius_clearHeadData($hash);
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] clearHeadData";
|
|
|
|
# State
|
|
fronius_setState($hash,"initialize");
|
|
|
|
# Internaltimer löschen
|
|
RemoveInternalTimer($hash);
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] RemoveInternalTimer";
|
|
|
|
# Internaltimer Statische Daten
|
|
InternalTimer(gettimeofday() + 0 , "fronius_GetAPIVersionInfo", $hash, 0);
|
|
InternalTimer(gettimeofday() + 5 , "fronius_GetActiveDeviceInfo", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] InternalTimer Statische Daten";
|
|
|
|
# Internaltimer Realtime Daten
|
|
InternalTimer(gettimeofday() + 10, "fronius_GetPowerFlowRealtimeData", $hash, 0) if AttrVal( $name, "IntervalPowerFlowRealtimeData", AttrVal( $name, "IntervalRealtimeData", 60 ) ) > 0;
|
|
InternalTimer(gettimeofday() + 12, "fronius_GetStorageRealtimeData", $hash, 0) if AttrVal( $name, "IntervalStorageRealtimeData" , AttrVal( $name, "IntervalRealtimeData", 60 ) ) > 0;
|
|
InternalTimer(gettimeofday() + 14, "fronius_GetMeterRealtimeData", $hash, 0) if AttrVal( $name, "IntervalMeterRealtimeData" , AttrVal( $name, "IntervalRealtimeData", 60 ) ) > 0;
|
|
InternalTimer(gettimeofday() + 16, "fronius_GetInverterRealtimeData", $hash, 0) if AttrVal( $name, "IntervalInverterRealtimeData" , AttrVal( $name, "IntervalRealtimeData", 60 ) ) > 0;
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] InternalTimer Realtime Daten";
|
|
|
|
# align GetArchiveData on 5min intervals
|
|
$interval = AttrVal( $name, "IntervalArchiveData", AttrVal( $name, "IntervalRealtimeData", 300 ) );
|
|
if ($interval > 0) {
|
|
# Fronius Solar API V1 Doku - "Archive requests are not allowed to be performed in parallel and need to keep a timeout of 120 seconds between two consecutive calls."
|
|
$interval = $interval < 120 ? 120 : $interval;
|
|
if ($interval == 300) {
|
|
my ($sec,$min) = localtime;
|
|
my $rounded_min = ceil(($min+1)/5) * 5;
|
|
|
|
$interval = ($rounded_min*60) - ($min*60+$sec);
|
|
}
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetArchiveData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] InternalTimer Archive Daten - $interval";
|
|
}
|
|
|
|
Log3 $name, 4, "[$name] [fronius_StartUp] done";
|
|
|
|
return;
|
|
}
|
|
|
|
sub fronius_Notify($$) {
|
|
my ($hash,$dev) = @_;
|
|
my $name = $hash->{NAME};
|
|
return if($dev->{NAME} ne "global");
|
|
return if(!grep(m/^INITIALIZED|REREADCFG$/, @{$dev->{CHANGED}}));
|
|
|
|
Log3 $name, 4, "[$name] [fronius_Notify] reload";
|
|
|
|
# (re)create timer
|
|
fronius_StartUp($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub fronius_Get($@) {
|
|
my ($hash, @a) = @_;
|
|
shift @a;
|
|
my $command = shift @a;
|
|
my $parameter = join(' ',@a);
|
|
my $name = $hash->{NAME};
|
|
|
|
my $usage = "Unknown argument $command, choose one of ";
|
|
|
|
return $usage;
|
|
}
|
|
|
|
sub fronius_Set($@) {
|
|
my ($hash, $name, $opt, @a) = @_;
|
|
my $interval = AttrVal( $name, "IntervalRealtimeData", 60 );
|
|
#my @options = ("GetAllData","GetPowerFlowData","GetStorageData","GetMeterData","GetInverterData","RestartInterval");
|
|
my %sets = (
|
|
"GetAllData" => "noArg",
|
|
"GetPowerFlowData" => "noArg",
|
|
"GetStorageData" => "noArg",
|
|
"GetMeterData" => "noArg",
|
|
"GetInverterData" => "noArg",
|
|
"RestartInterval" => "noArg"
|
|
);
|
|
my %order = (
|
|
"PowerFlow" => -1,
|
|
"Storage" => -1,
|
|
"Meter" => -1,
|
|
"Inverter" => -1
|
|
);
|
|
|
|
if (($opt eq '?') || ($opt eq '')){
|
|
#return join( ' ', @options);
|
|
return join(" ", sort keys %sets);
|
|
} elsif ($opt eq 'RestartInterval') {
|
|
RemoveInternalTimer($hash, "fronius_GetPowerFlowRealtimeData");
|
|
RemoveInternalTimer($hash, "fronius_GetStorageRealtimeData");
|
|
RemoveInternalTimer($hash, "fronius_GetMeterRealtimeData");
|
|
RemoveInternalTimer($hash, "fronius_GetInverterRealtimeData");
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetPowerFlowRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + 2 + $interval, "fronius_GetStorageRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + 4 + $interval, "fronius_GetMeterRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + 6 + $interval, "fronius_GetInverterRealtimeData", $hash, 0);
|
|
} elsif ($interval le 0) {
|
|
if ($opt eq 'GetAllData') {
|
|
#übergabeparameter durchsuchen auf gültigkeit und übernehmen
|
|
my $tdelay = 0;
|
|
while(my $arg = shift(@a)){
|
|
if( exists($order{$arg} ) ) {
|
|
if ($order{$arg} lt 0){
|
|
$order{$arg} = $tdelay;
|
|
Log3 $name, 5, "[$name] [fronius_Set] arg set = $arg=$tdelay";
|
|
$tdelay = $tdelay+2;
|
|
}
|
|
}
|
|
Log3 $name, 5, "[$name] [fronius_Set] arg = $arg";
|
|
}
|
|
#reihenfolge aufarbeiten für nicht vorhandene calls in den übergabe parametern
|
|
my @getorder = split ( /\s+/, join(" ", keys %order) );
|
|
while(my $func = shift(@getorder)){
|
|
if ($order{$func} lt 0){
|
|
$order{$func} = $tdelay;
|
|
$tdelay = $tdelay+2;
|
|
}
|
|
Log3 $name, 5, "[$name] [fronius_Set] order $func=$order{$func}";
|
|
}
|
|
InternalTimer(gettimeofday() + $order{"PowerFlow"}, "fronius_GetPowerFlowRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + $order{"Storage"}, "fronius_GetStorageRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + $order{"Meter"}, "fronius_GetMeterRealtimeData", $hash, 0);
|
|
InternalTimer(gettimeofday() + $order{"Inverter"}, "fronius_GetInverterRealtimeData", $hash, 0);
|
|
} elsif ($opt eq 'GetPowerFlowData') {
|
|
InternalTimer(gettimeofday(), "fronius_GetPowerFlowRealtimeData", $hash, 0);
|
|
} elsif ($opt eq 'GetStorageData') {
|
|
InternalTimer(gettimeofday(), "fronius_GetStorageRealtimeData", $hash, 0);
|
|
} elsif ($opt eq 'GetMeterData') {
|
|
InternalTimer(gettimeofday(), "fronius_GetMeterRealtimeData", $hash, 0);
|
|
} elsif ($opt eq 'GetInverterData') {
|
|
InternalTimer(gettimeofday(), "fronius_GetInverterRealtimeData", $hash, 0);
|
|
} else {
|
|
#return "Unknown argument $opt choose one of : " . join( ', ', @options);
|
|
return "Unknown argument $opt choose one of : " . join(" ", sort keys %sets) .
|
|
".\x0D\x0A Or GetAllData with order argumens of \"".join("\",\"", sort keys %order)."\"".
|
|
".\x0D\x0A\x0D\x0A Example: Set $name GetAllData Inverter Meter".
|
|
"\x0D\x0A With this example the get commands for the $name will be in the following order: GetInverterData, GetMeterData afterwards automaticaly GetPowerflow and GetStorageData";
|
|
}
|
|
} else {
|
|
return "Set $opt not ok, IntervalRealtimeData > 0. Restart Interval with : set $name RestartInterval";
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
sub fronius_Attr($$$) {
|
|
|
|
my ($cmd, $name, $attrName, $attrVal) = @_;
|
|
my $hash = $defs{$name};
|
|
|
|
Log3 $name, 5, "[$name] [fronius_Attr] attrName=$attrName";
|
|
|
|
if ( $attrName eq "SaveDataHead" ) {
|
|
fronius_clearHeadData($hash);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#########################
|
|
# Standard Request
|
|
#########################
|
|
sub fronius_GetAPIVersionInfo($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = 36000;
|
|
|
|
$hash->{helper}{VARS}{ReInitGetAPIVersionInfo} = 0;
|
|
|
|
fronius_SendCommand($hash,"GetAPIVersionInfo","");
|
|
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetAPIVersionInfo", $hash, 0);
|
|
}
|
|
|
|
sub fronius_GetActiveDeviceInfo($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = 36000;
|
|
|
|
fronius_SendCommand($hash,"GetActiveDeviceInfo","");
|
|
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetActiveDeviceInfo", $hash, 0);
|
|
}
|
|
|
|
#########################
|
|
# RealtimeData
|
|
#########################
|
|
sub fronius_GetPowerFlowRealtimeData($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = AttrVal( $name, "IntervalPowerFlowRealtimeData", AttrVal( $name, "IntervalRealtimeData", 60 ) );
|
|
|
|
fronius_SendCommand($hash,"GetPowerFlowRealtimeData","");
|
|
|
|
if ($interval > 0) {
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetPowerFlowRealtimeData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_GetPowerFlowRealtimeData] Timer $interval";
|
|
} else {
|
|
RemoveInternalTimer($hash, "fronius_GetPowerFlowRealtimeData");
|
|
Log3 $name, 4, "[$name] [fronius_GetPowerFlowRealtimeData] Timer removed";
|
|
}
|
|
}
|
|
|
|
sub fronius_GetArchiveData($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = AttrVal( $name, "IntervalArchiveData", AttrVal( $name, "IntervalRealtimeData", 300 ) );
|
|
|
|
fronius_SendCommand($hash,"GetArchiveData","");
|
|
|
|
if ($interval > 0) {
|
|
|
|
# Fronius Solar API V1 Doku - "Archive requests are not allowed to be performed in parallel and need to keep a timeout of 120 seconds between two consecutive calls."
|
|
$interval = $interval < 120 ? 120 : $interval;
|
|
|
|
# align on 5min intervals
|
|
if ($interval == 300) {
|
|
my ($sec,$min) = localtime;
|
|
my $rounded_min = ceil(($min+1)/5) * 5;
|
|
|
|
$interval = ($rounded_min*60) - ($min*60+$sec);
|
|
}
|
|
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetArchiveData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_GetArchiveData] Timer $interval";
|
|
} else {
|
|
RemoveInternalTimer($hash, "fronius_GetArchiveData");
|
|
Log3 $name, 4, "[$name] [fronius_GetArchiveData] Timer removed";
|
|
}
|
|
}
|
|
|
|
|
|
sub fronius_GetStorageRealtimeData($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = AttrVal( $name, "IntervalStorageRealtimeData", AttrVal( $name, "IntervalRealtimeData", 60 ) );
|
|
my $StorageNumber = 999999999999;
|
|
|
|
if ($hash->{helper}{VARS}{Smart_Storage} ne "nA") {
|
|
foreach my $StorageDevice (sort keys %{$hash->{READINGS}}) {
|
|
if ($StorageDevice =~ m/DeviceInfo_Storage_/ ) {
|
|
my @StorageReading = split("\_",$StorageDevice);
|
|
if ($StorageNumber != $StorageReading[2]) {
|
|
$StorageNumber = $StorageReading[2];
|
|
Log3 $name, 5, "[$name] [fronius_GetStorageRealtimeData] Start Storage $StorageNumber";
|
|
fronius_SendCommand($hash,"GetStorageRealtimeData",$StorageNumber);
|
|
}else {Log3 $name, 5, "[$name] [fronius_GetStorageRealtimeData] SKIP Storage $StorageNumber";}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
# Eventuell vorhandene Daten wieder löschen!
|
|
foreach my $StorageDevice (sort keys %{$hash->{READINGS}}) {
|
|
readingsDelete($hash, $StorageDevice) if ($StorageDevice =~ m/DeviceInfo_Storage_/ );
|
|
}
|
|
}
|
|
|
|
if ($interval > 0) {
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetStorageRealtimeData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_GetStorageRealtimeData] Timer $interval";
|
|
} else {
|
|
RemoveInternalTimer($hash, "fronius_GetStorageRealtimeData");
|
|
Log3 $name, 4, "[$name] [fronius_GetStorageRealtimeData] Timer removed";
|
|
}
|
|
|
|
}
|
|
|
|
sub fronius_GetMeterRealtimeData($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = AttrVal( $name, "IntervalMeterRealtimeData", AttrVal( $name, "IntervalRealtimeData", 60 ) );
|
|
my $MeterNumber = 999999999999;
|
|
|
|
if ($hash->{helper}{VARS}{Smart_Meter} ne "nA") {
|
|
foreach my $MeterDevice (sort keys %{$hash->{READINGS}}) {
|
|
if ($MeterDevice =~ m/DeviceInfo_Meter_/ ) {
|
|
my @MeterReading = split("\_",$MeterDevice);
|
|
if ($MeterNumber != $MeterReading[2]) {
|
|
$MeterNumber = $MeterReading[2];
|
|
Log3 $name, 5, "[$name] [fronius_GetMeterRealtimeData] Start Storage $MeterNumber";
|
|
fronius_SendCommand($hash,"GetMeterRealtimeData",$MeterNumber);
|
|
}else {Log3 $name, 5, "[$name] [fronius_GetMeterRealtimeData] SKIP Storage $MeterNumber";}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
# Eventuell vorhandene Daten wieder löschen!
|
|
foreach my $MeterDevice (sort keys %{$hash->{READINGS}}) {
|
|
readingsDelete($hash, $MeterDevice) if ($MeterDevice =~ m/DeviceInfo_Meter_/ );
|
|
}
|
|
}
|
|
|
|
if ($interval > 0) {
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetMeterRealtimeData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_GetMeterRealtimeData] Timer $interval";
|
|
} else {
|
|
RemoveInternalTimer($hash, "fronius_GetMeterRealtimeData");
|
|
Log3 $name, 4, "[$name] [fronius_GetMeterRealtimeData] Timer removed";
|
|
}
|
|
|
|
}
|
|
|
|
sub fronius_GetInverterRealtimeData($) {
|
|
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $interval = AttrVal( $name, "IntervalInverterRealtimeData", AttrVal( $name, "IntervalRealtimeData", 60 ) );
|
|
my $InverterNumber = 999999999999;
|
|
|
|
if ($hash->{helper}{VARS}{Smart_Inverter} ne "nA") {
|
|
|
|
fronius_SendCommand($hash,"GetInverterRealtimeData_System",$InverterNumber);
|
|
|
|
foreach my $InverterDevice (sort keys %{$hash->{READINGS}}) {
|
|
if ($InverterDevice =~ m/DeviceInfo_Inverter_/ ) {
|
|
my @InverterReading = split("\_",$InverterDevice);
|
|
if ($InverterNumber != $InverterReading[2]) {
|
|
$InverterNumber = $InverterReading[2];
|
|
Log3 $name, 5, "[$name] [fronius_GetInverterRealtimeData] Start Storage $InverterNumber";
|
|
fronius_SendCommand($hash,"GetInverterRealtimeData_Cumulation",$InverterNumber);
|
|
fronius_SendCommand($hash,"GetInverterRealtimeData_Common",$InverterNumber);
|
|
fronius_SendCommand($hash,"GetInverterRealtimeData_3P",$InverterNumber);
|
|
}else {Log3 $name, 5, "[$name] [fronius_GetInverterRealtimeData] SKIP Storage $InverterNumber";}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
# Eventuell vorhandene Daten wieder löschen!
|
|
foreach my $InverterDevice (sort keys %{$hash->{READINGS}}) {
|
|
readingsDelete($hash, $InverterDevice) if ($InverterDevice =~ m/DeviceInfo_Inverter_/ );
|
|
}
|
|
}
|
|
|
|
if ($interval > 0) {
|
|
InternalTimer(gettimeofday() + $interval, "fronius_GetInverterRealtimeData", $hash, 0);
|
|
Log3 $name, 4, "[$name] [fronius_GetInverterRealtimeData] Timer $interval";
|
|
} else {
|
|
RemoveInternalTimer($hash, "fronius_GetInverterRealtimeData");
|
|
Log3 $name, 4, "[$name] [fronius_GetInverterRealtimeData] Timer removed";
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#########################
|
|
sub fronius_SendCommand($$$) {
|
|
my ( $hash, $type, $SendData ) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
Log3 $name, 4, "[$name] [fronius_SendCommand] [$type] START";
|
|
|
|
my $SendUrl;
|
|
|
|
# JSON Auswertung
|
|
if ($type eq "GetAPIVersionInfo") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . "/solar_api/GetAPIVersion.cgi";
|
|
}
|
|
elsif ($type eq "GetPowerFlowRealtimeData") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetPowerFlowRealtimeData.fcgi";
|
|
}
|
|
elsif ($type eq "GetStorageRealtimeData") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetStorageRealtimeData.cgi?Scope=System&DeviceId=$SendData";
|
|
}
|
|
elsif ($type eq "GetMeterRealtimeData") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetMeterRealtimeData.cgi?Scope=System&DeviceId=$SendData";
|
|
}
|
|
elsif ($type eq "GetActiveDeviceInfo") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetActiveDeviceInfo.cgi?DeviceClass=System";
|
|
}
|
|
elsif ($type eq "GetInverterRealtimeData_System") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetInverterRealtimeData.cgi?Scope=System";
|
|
}
|
|
elsif ($type eq "GetInverterRealtimeData_Cumulation") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetInverterRealtimeData.cgi?Scope=Device&DeviceId=$SendData&DataCollection=CumulationInverterData";
|
|
}
|
|
elsif ($type eq "GetInverterRealtimeData_Common") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetInverterRealtimeData.cgi?Scope=Device&DeviceId=$SendData&DataCollection=CommonInverterData";
|
|
}
|
|
elsif ($type eq "GetInverterRealtimeData_3P") {
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetInverterRealtimeData.cgi?Scope=Device&DeviceId=$SendData&DataCollection=3PInverterData";
|
|
}
|
|
elsif ($type eq "GetArchiveData") {
|
|
my $today = time;
|
|
my $StartDate = strftime "%Y-%m-%dT%H:%M:00Z", gmtime($today - 300); # Fronius Solar API V1 Doku - "...intervals which can be set between 5 and 30 minutes..."
|
|
my $EndDate = strftime "%Y-%m-%dT%H:%M:00Z", gmtime($today);
|
|
$SendUrl = "http://" . $hash->{helper}{VARS}{FroniusIP} . $hash->{helper}{VARS}{FroniusBaseURL} . "GetArchiveData.cgi?Scope=System&StartDate=$StartDate&EndDate=$EndDate&Channel=Current_DC_String_1&Channel=Current_DC_String_2&Channel=Voltage_DC_String_1&Channel=Voltage_DC_String_2&Channel=EnergyReal_WAC_Sum_Produced&Channel=EnergyReal_WAC_Minus_Absolute&Channel=EnergyReal_WAC_Plus_Absolute&Channel=PowerReal_PAC_Sum";
|
|
}
|
|
else {
|
|
Log3 $name, 3, "[$name] [fronius_SendCommand] [$type] ERROR=Type is unkown!!";
|
|
return;
|
|
}
|
|
|
|
#2018.01.14 - PushToCmdQueue
|
|
if ($hash->{helper}{VARS}{FroniusBaseURL} eq "nA" && $type ne "GetAPIVersionInfo") {
|
|
Log3 $name, 4, "[$name] [fronius_SendCommand] [$type] NOT PushToCmdQueue ERROR=Fronius API Base URL not set!";
|
|
|
|
if ($hash->{helper}{VARS}{ReInitGetAPIVersionInfo} == 0) {
|
|
RemoveInternalTimer($hash, "fronius_GetAPIVersionInfo");
|
|
InternalTimer(gettimeofday() + 60 , "fronius_GetAPIVersionInfo", $hash, 0);
|
|
$hash->{helper}{VARS}{ReInitGetAPIVersionInfo} = 1;
|
|
Log3 $name, 4, "[$name] [fronius_SendCommand] [$type] re-init fronius_GetAPIVersionInfo";
|
|
}
|
|
}
|
|
else {
|
|
|
|
#2018.01.14 - Übergabe SendCommandQuery
|
|
my $SendParam = {
|
|
url => $SendUrl,
|
|
hash => $hash,
|
|
CL => $hash->{CL},
|
|
httpversion => "1.1",
|
|
type => $type
|
|
};
|
|
|
|
Log3 $name, 4, "[$name] [fronius_SendCommand] [$type] PushToCmdQueue SendURL=" . $SendUrl;
|
|
push @{$hash->{helper}{CMD_QUEUE}}, $SendParam;
|
|
fronius_HandleCmdQueue($hash);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
sub fronius_HandleCmdQueue($) {
|
|
my ($hash, $param) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
return undef if(!defined($hash->{helper}{CMD_QUEUE}));
|
|
$hash->{helper}{RUNNING_REQUEST} = 0 if(!defined($hash->{helper}{RUNNING_REQUEST}));
|
|
|
|
if(not($hash->{helper}{RUNNING_REQUEST}) and @{$hash->{helper}{CMD_QUEUE}})
|
|
{
|
|
|
|
my $params = {
|
|
url => $param->{url},
|
|
timeout => 10,
|
|
noshutdown => 1,
|
|
keepalive => 0,
|
|
method => "GET",
|
|
CL => $param->{CL},
|
|
hash => $hash,
|
|
type => $param->{type},
|
|
httpversion => $param->{httpversion},
|
|
callback => \&fronius_Parse
|
|
};
|
|
|
|
my $request = pop @{$hash->{helper}{CMD_QUEUE}};
|
|
|
|
map {$hash->{helper}{".HTTP_CONNECTION"}{$_} = $params->{$_}} keys %{$params};
|
|
map {$hash->{helper}{".HTTP_CONNECTION"}{$_} = $request->{$_}} keys %{$request};
|
|
|
|
my $type = $hash->{helper}{".HTTP_CONNECTION"}{type};
|
|
|
|
$hash->{helper}{RUNNING_REQUEST} = 1;
|
|
Log3 $name, 4, "[$name] [fronius_HandleCmdQueue] [$type] send command=" . $hash->{helper}{".HTTP_CONNECTION"}{url};
|
|
HttpUtils_NonblockingGet($hash->{helper}{".HTTP_CONNECTION"});
|
|
|
|
}
|
|
}
|
|
|
|
sub fronius_Parse($$$) {
|
|
my ($param, $err, $data) = @_;
|
|
my $hash = $param->{hash};
|
|
my $name = $hash->{NAME};
|
|
my $msgtype = $param->{type};
|
|
|
|
Log3 $name, 4, "[$name] [fronius_Parse] [$msgtype] ";
|
|
Log3 $name, 5, "[$name] [fronius_Parse] [$msgtype] DATA Header=" . $param->{httpheader};
|
|
Log3 $name, 5, "[$name] [fronius_Parse] [$msgtype] DATA Dumper=" . $data;
|
|
|
|
$hash->{helper}{RUNNING_REQUEST} = 0;
|
|
|
|
# Connection prüfen
|
|
if ($err) {
|
|
Log3 $name, 3, "[$name] [fronius_Parse] [$msgtype] ERROR=$err";
|
|
fronius_setState($hash,"disconnected");
|
|
}
|
|
else {
|
|
|
|
fronius_setState($hash,"connected");
|
|
# HTML Informationen mit schreiben
|
|
|
|
# Prüfen ob es sich um ein json String handelt!
|
|
if (index($data, '{') == -1) {$data = '{"data": "nodata"}';}
|
|
|
|
my $json = eval { JSON->new->utf8(0)->decode($data) };
|
|
|
|
readingsBeginUpdate($hash);
|
|
|
|
if ($msgtype eq "GetAPIVersionInfo") {
|
|
fronius_expandJSON($hash,$name,"",$json,"API_");
|
|
}
|
|
elsif ($msgtype eq "GetPowerFlowRealtimeData") {
|
|
fronius_expandJSON($hash,$name,"",$json,"PowerFlow_");
|
|
}
|
|
elsif ($msgtype eq "GetActiveDeviceInfo") {
|
|
fronius_expandJSON($hash,$name,"",$json,"DeviceInfo_");
|
|
}
|
|
elsif ($msgtype eq "GetStorageRealtimeData") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Storage_");
|
|
}
|
|
elsif ($msgtype eq "GetMeterRealtimeData") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Meter_");
|
|
}
|
|
elsif ($msgtype eq "GetInverterRealtimeData_System") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Inverter_System_");
|
|
}
|
|
elsif ($msgtype eq "GetInverterRealtimeData_Cumulation") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Inverter_Cumulation_");
|
|
}
|
|
elsif ($msgtype eq "GetInverterRealtimeData_Common") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Inverter_Common_");
|
|
}
|
|
elsif ($msgtype eq "GetInverterRealtimeData_3P") {
|
|
fronius_expandJSON($hash,$name,"",$json,"Inverter_3P_");
|
|
}
|
|
elsif ($msgtype eq "GetArchiveData") {
|
|
fronius_expandJSON($hash,$name,"",$json,"ArchiveData_");
|
|
# Umrechnen in WATT
|
|
readingsBulkUpdate($hash, "MPPT1_DC_W", ReadingsVal($name, "MPPT1_DC_A", 0) * ReadingsVal($name, "MPPT1_DC_V", 0) );
|
|
readingsBulkUpdate($hash, "MPPT2_DC_W", ReadingsVal($name, "MPPT2_DC_A", 0) * ReadingsVal($name, "MPPT2_DC_V", 0) );
|
|
}
|
|
else {
|
|
Log3 $name, 4, "[$name] [fronius_Parse] [$msgtype] json for unknown message \n". $json;
|
|
}
|
|
|
|
readingsEndUpdate( $hash, 1 );
|
|
|
|
}
|
|
|
|
fronius_HandleCmdQueue($hash);
|
|
|
|
return undef;
|
|
}
|
|
|
|
sub fronius_expandJSON($$$$;$$) {
|
|
my ($hash,$dhash,$sPrefix,$ref,$prefix,$suffix) = @_;
|
|
my ($name,$type) = ($hash->{NAME},$hash->{TYPE});
|
|
my $SaveDataHead = AttrVal( $name, "SaveDataHead", 0 );
|
|
|
|
$prefix = "" if( !$prefix );
|
|
$suffix = "" if( !$suffix );
|
|
$suffix = "_$suffix" if( $suffix );
|
|
|
|
if( ref( $ref ) eq "ARRAY" ) {
|
|
while( my ($key,$value) = each @{ $ref } ) {
|
|
fronius_expandJSON($hash,$name,"",$value, $prefix.sprintf("%02i",$key+1)."_");
|
|
}
|
|
}
|
|
|
|
elsif( ref( $ref ) eq "HASH" ) {
|
|
while( my ($key,$value) = each %{ $ref } ) {
|
|
if( ref( $value ) && ref($value) ne "JSON::PP::Boolean") {
|
|
fronius_expandJSON($hash,$name,"",$value,$prefix.$key.$suffix."_");
|
|
}
|
|
else {
|
|
(my $reading = $sPrefix.$prefix.$key.$suffix) =~ s/[^A-Za-z\d_\.\-\/]/_/g;
|
|
|
|
if ($prefix =~ m/_Head_/ && $SaveDataHead == 0 ){
|
|
Log3 $name, 5, "[$name] [fronius_expandJSON] IGNOR DATA --> $reading VALUE --> $value";
|
|
next;
|
|
}
|
|
|
|
$reading =~ s/Body_Data_//g;
|
|
|
|
if ($reading eq "PowerFlow_Site_P_Load") {
|
|
if ( $value + 0 eq $value) {
|
|
if ($value < 0) {$value = $value * -1}
|
|
}
|
|
}
|
|
|
|
# Boolean Werte in Text umwandeln
|
|
if (ref($value) eq "JSON::PP::Boolean" && $value == 0) {$value="false"}
|
|
elsif (ref($value) eq "JSON::PP::Boolean" && $value == 1) {$value="true"}
|
|
|
|
Log3 $name, 5, "[$name] [fronius_expandJSON] WRITE DATA --> $reading VALUE --> $value";
|
|
|
|
# Sub Devices
|
|
$hash->{helper}{VARS}{Smart_Meter} = "1" if ($prefix =~ m/DeviceInfo_Body_Data_Meter/ );
|
|
$hash->{helper}{VARS}{Smart_Inverter} = "1" if ($prefix =~ m/DeviceInfo_Body_Data_Inverter/ );
|
|
$hash->{helper}{VARS}{Smart_Storage} = "1" if ($prefix =~ m/DeviceInfo_Body_Data_Storage/ );
|
|
$hash->{helper}{VARS}{Smart_OhmPilot} = "1" if ($prefix =~ m/DeviceInfo_Body_Data_OhmPilot/ );
|
|
$hash->{helper}{VARS}{Smart_StringControl} = "1" if ($prefix =~ m/DeviceInfo_Body_Data_StringControl/ );
|
|
|
|
# API Base URL
|
|
$hash->{helper}{VARS}{FroniusBaseURL} = $value if ($reading eq "API_BaseURL");
|
|
|
|
if ($prefix =~ m/ArchiveData_/ ) {
|
|
if ($prefix =~ m/Current_DC_String_1_Values/ ) {readingsBulkUpdate($hash, "MPPT1_DC_A", encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Current_DC_String_2_Values/ ) {readingsBulkUpdate($hash, "MPPT2_DC_A", encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Voltage_DC_String_1_Values/ ) {readingsBulkUpdate($hash, "MPPT1_DC_V", encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Voltage_DC_String_2_Values/ ) {readingsBulkUpdate($hash, "MPPT2_DC_V", encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Data_PowerReal_PAC_Sum_Values/ ) {readingsBulkUpdate($hash, "ArchiveData_PowerReal_PAC_Sum" , encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Data_EnergyReal_WAC_Sum_Produced_Values/ ) {readingsBulkUpdate($hash, "ArchiveData_EnergyReal_WAC_Sum_Produced" , encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Data_EnergyReal_WAC_Plus_Absolute_Values/ ) {readingsBulkUpdate($hash, "ArchiveData_EnergyReal_WAC_Plus_Absolute" , encode('UTF-8', $value) );}
|
|
elsif ($prefix =~ m/Data_EnergyReal_WAC_Minus_Absolute_Values/ ) {readingsBulkUpdate($hash, "ArchiveData_EnergyReal_WAC_Minus_Absolute" , encode('UTF-8', $value) );}
|
|
elsif ($reading =~ m/1_Start/ ) {readingsBulkUpdate($hash, "ArchiveData_StartDate" , encode('UTF-8', $value) );}
|
|
elsif ($reading =~ m/1_End/ ) {readingsBulkUpdate($hash, "ArchiveData_EndDate" , encode('UTF-8', $value) );}
|
|
#else {Log3 $name, 3, "$prefix $reading $value";}
|
|
}
|
|
else {
|
|
if ($value ne "") {readingsBulkUpdate($hash, $reading, encode('UTF-8', $value) );}
|
|
else {readingsBulkUpdate($hash, $reading, encode('UTF-8', 0) );}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#########################
|
|
# Helper
|
|
#########################
|
|
sub fronius_clearHeadData($) {
|
|
my ($hash) = @_;
|
|
my $name = $hash->{NAME};
|
|
my $SaveDataHead = AttrVal( $name, "SaveDataHead", 0 );
|
|
|
|
Log3 $name, 5, "[$name] [fronius_clearHeadData] START";
|
|
|
|
if ($SaveDataHead == 0) {
|
|
foreach my $Head (sort keys %{$hash->{READINGS}}) {
|
|
if ($Head =~ m/_Head_/ ) {
|
|
readingsDelete($hash, $Head) ;
|
|
Log3 $name, 5, "[$name] [fronius_clearHeadData] delete reading $Head";
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
sub fronius_setState($$) {
|
|
my ($hash,$State) = @_;
|
|
my $name = $hash->{NAME};
|
|
|
|
Log3 $name, 3, "[$name] [fronius_setState] to $State" if(ReadingsVal($name, "state", "nA") ne $State) ;
|
|
|
|
readingsBeginUpdate($hash);
|
|
readingsBulkUpdateIfChanged($hash, "state", $State, 1);
|
|
readingsEndUpdate($hash,1);
|
|
|
|
return;
|
|
}
|
|
|
|
1;
|
|
|
|
=pod
|
|
=item device
|
|
=item summary Fronius
|
|
=begin html
|
|
|
|
<a name="fronius"></a>
|
|
<h3>fronius</h3>
|
|
<ul>
|
|
Module to read data from Fronius inverter devices using <a href="https://www.fronius.com/~/downloads/Solar%20Energy/Operating%20Instructions/42,0410,2012.pdf">Fronius Solar API V1</a>
|
|
<br>
|
|
see also <a href="https://forum.fhem.de/index.php?topic=138356.0">FHEM Forum discussion thread</a>
|
|
<br>
|
|
<br>
|
|
|
|
<a id="fronius-define"></a>
|
|
<b>Define</b>
|
|
<ul>
|
|
<code>define <name> fronius <IP-adress of device></code>
|
|
</ul>
|
|
<br>
|
|
|
|
<a id="fronius-set"></a>
|
|
<b>Set</b>
|
|
<ul>
|
|
<li>if (and only if) IntervalRealtimeData <= 0 requests can be sent manually:
|
|
<ul>
|
|
<li>Set devicename GetAllData </li>
|
|
<li>Set devicename GetAllData Meter Inverter Storage PowerFlow</li>
|
|
<li>Set devicename GetPowerFlowData </li>
|
|
<li>Set devicename GetStorageData </li>
|
|
<li>Set devicename GetMeterData </li>
|
|
<li>Set devicename GetInverterData </li>
|
|
</ul>
|
|
</li>
|
|
<li>Restart timers, needed after changed to Interval* attributes:
|
|
<br>
|
|
<ul><li>set devicename RestartInterval</li></ul>
|
|
</li>
|
|
</ul>
|
|
<br>
|
|
|
|
<a id="fronius-attr"></a>
|
|
<b>Attributes</b>
|
|
<ul>
|
|
<li><a id="fronius-IntervalRealtimeData">IntervalRealtimeData</a><br>
|
|
Interval in seconds for requesting data from inverter, default 60s, 0 to disable requests.
|
|
</li>
|
|
|
|
<li><a id="fronius-IntervalArchiveData">IntervalArchiveData</a><br>
|
|
Interval in seconds for requesting GetArchiveData data from inverter, default MAX(300,IntervalRealtimeData), minimum allowed value 120s (Fronius Solar API V1 Doku - "Archive requests are not allowed to be performed in parallel and need to keep a timeout of 120 seconds between two consecutive calls.")
|
|
<br>
|
|
if set to 300, GetArchiveData calls are aligned on 5min intervals
|
|
<br>
|
|
0 to disable requests.
|
|
</li>
|
|
|
|
<li><a id="fronius-IntervalPowerFlowRealtimeData">IntervalPowerFlowRealtimeData</a><br>
|
|
Interval in seconds for requesting GetPowerFlowRealtimeData data from inverter, default IntervalRealtimeData, 0 to disable requests.
|
|
</li>
|
|
|
|
<li><a id="fronius-IntervalStorageRealtimeData">IntervalStorageRealtimeData</a><br>
|
|
Interval in seconds for requesting GetStorageRealtimeData data from inverter, default IntervalRealtimeData, 0 to disable requests.
|
|
</li>
|
|
|
|
<li><a id="fronius-IntervalMeterRealtimeData">IntervalMeterRealtimeData</a><br>
|
|
Interval in seconds for requesting GetMeterRealtimeData data from inverter, default IntervalRealtimeData, 0 to disable requests.
|
|
</li>
|
|
|
|
<li><a id="fronius-IntervalInverterRealtimeData">IntervalInverterRealtimeData</a><br>
|
|
Interval in seconds for requesting GetInverterRealtimeData data from inverter, default IntervalRealtimeData, 0 to disable requests.
|
|
</li>
|
|
|
|
</ul>
|
|
<br>
|
|
|
|
</ul>
|
|
|
|
=end html
|
|
|
|
=cut
|